Add OwnerState and PermissionState

master
garrettmills 4 years ago
parent 2725f9eac2
commit 6f1de65602
No known key found for this signature in database
GPG Key ID: 6ACD58D6ADACFC6E

@ -154,6 +154,24 @@ class UniversalPath extends Injectable {
})
}
async permissions(set_level = false, recursive = false) {
if ( set_level ) {
await this._host.set_permissions_for_path(this, set_level, recursive)
} else {
return this._host.get_permissions_for_path(this)
}
}
async ownership(set_owners = false, recursive = false) {
if ( set_owners ) {
const current = await this.ownership()
const target = {...current, ...set_owners}
await this._host.set_ownership_for_path(this, target, recursive)
} else {
return this._host.get_ownership_for_path(this)
}
}
async hash() {
const line = await this._host.run_line_result(`sha256sum ${this._path}`)
return line.split(' ')[0]

@ -24,6 +24,12 @@ class Host extends Injectable {
_resolve_path_command = `readlink -f "%%PATH%%"`
_reboot_command = `reboot`
_change_directory_command = `cd "%%PATH%%"`
_file_directory_permission_fetch_command = `stat -c %a "%%PATH%%"`
_file_directory_permission_set_command_flat = `chmod %%LEVEL%% "%%PATH%%"`
_file_directory_permission_set_command_recursive = `chmod -R %%LEVEL%% "%%PATH%%"`
_file_directory_ownership_fetch_command = `stat -c "%U:%G" "%%PATH%%"`
_file_directory_ownership_set_command_flat = `chown %%OWNERS%% "%%PATH%%"`
_file_directory_ownership_set_command_recursive = `chown -R %%OWNERS%% "%%PATH%%"`
constructor(config) {
super()
@ -117,6 +123,39 @@ class Host extends Injectable {
return this.run_line_result(this._resolve_path_command.replace('%%PATH%%', resource_path))
}
async get_permissions_for_path(resource_path) {
resource_path = typeof resource_path === 'string' ? resource_path : resource_path.path
return this.run_line_result(this._file_directory_permission_fetch_command.replace('%%PATH%%', resource_path))
}
async set_permissions_for_path(resource_path, level, recursive = false) {
resource_path = typeof resource_path === 'string' ? resource_path : resource_path.path
let cmd
if ( recursive ) cmd = this._file_directory_permission_set_command_recursive
else cmd = this._file_directory_permission_set_command_flat
cmd = cmd.replace('%%PATH%%', resource_path)
cmd = cmd.replace('%%LEVEL%%', level)
await this.run(cmd)
}
async get_ownership_for_path(resource_path) {
resource_path = typeof resource_path === 'string' ? resource_path : resource_path.path
const cmd = this._file_directory_ownership_fetch_command.replace('%%PATH%%', resource_path)
const result = await this.run_line_result(cmd)
const parts = result.split(':')
return {user: parts[0], group: parts[1]}
}
async set_ownership_for_path(resource_path, { user, group }, recursive = false) {
resource_path = typeof resource_path === 'string' ? resource_path : resource_path.path
let cmd
if ( recursive ) cmd = this._file_directory_ownership_set_command_recursive
else cmd = this._file_directory_ownership_set_command_flat
cmd = cmd.replace('%%PATH%%', resource_path)
cmd = cmd.replace('%%OWNERS%%', `${user}:${group}`)
await this.run(cmd)
}
async get_mount_points() {
const result = await this.execute(this._list_mount_points_command)
if ( result.exit_code !== 0 ) {

@ -0,0 +1,44 @@
const State = require('../State')
class OwnerState extends State {
static get services() {
return [...super.services, 'output']
}
async apply() {
if ( !(await this.check()) ) {
const path = await this._path()
await path.ownership(this._config.owners, !!this._config.recursive)
}
}
async check() {
const path = await this._path()
const owners = await path.ownership()
if ( this._config.owners.user && owners.user !== this._config.owners.user ) return false
else if ( this._config.owners.group && owners.group !== this._config.owners.group ) return false
return true
}
async reverse() {
if ( await this.check() ) {
if (this._config.revert_to) {
const path = await this._path()
await path.ownership(this._config.revert_to, !!this._config.recursive)
} else {
this.output.warn(`Owner state does not support automatic reversal. Specify the revert_to config key for this functionality. (Host: ${this._host.name})`)
}
}
}
async _path() {
const path = await this._host.get_path(this._config.path)
await path.classify()
if ( !path.is_valid() ) throw new Error(`Invalid path for OwnerState: ${path}`)
return path
}
}
module.exports = exports = OwnerState

@ -0,0 +1,39 @@
const State = require('../State')
class PermissionState extends State {
static get services() {
return [...super.services, 'output']
}
async apply() {
if ( !(await this.check()) ) {
const path = await this._path()
await path.permissions(this._config.level, !!this._config.recursive)
}
}
async check() {
const path = await this._path()
const permissions = `${await path.permissions()}`.trim()
const target = `${this._config.level}`.trim()
return permissions === target
}
async reverse() {
if ( this._config.revert_to ) {
const path = await this._path()
await path.permissions(this._config.revert_to, this._config.recursive)
} else {
this.output.warn(`Permission state does not support automatic reversal. Specify the revert_to config for this functionality. (Host: ${this._host.name})`)
}
}
async _path() {
const path = await this._host.get_path(this._config.path)
await path.classify()
if ( !path.is_valid() ) throw new Error(`Invalid path for PermissionState: ${path}`)
return path
}
}
module.exports = exports = PermissionState

@ -12,7 +12,6 @@ const { Service } = require('flitter-di')
class StatesService extends Service {
static #state_map = {
// TODO apache and nginx states - virtual host, reverse proxy
// TODO file/directory permissions state - chmod & chown
// TODO file pack state - zip, tarball
// TODO package repository states - import keys, install repository
// TODO service manager states - service enabled, service installed
@ -21,6 +20,8 @@ class StatesService extends Service {
'fs.file': require('../classes/state/fs/FileState'),
'fs.directory': require('../classes/state/fs/DirectoryState'),
'fs.unpack': require('../classes/state/fs/UnpackState'),
'fs.permission': require('../classes/state/fs/PermissionState'),
'fs.ownership': require('../classes/state/fs/OwnerState'),
'package.present': require('../classes/state/os/PackageState'),
'package.updates': require('../classes/state/os/UpdateState'),

Loading…
Cancel
Save