Commit d446a9ca authored by louis-riviere-xyz's avatar louis-riviere-xyz
Browse files

commands

parent 4111b098
MIT License
Copyright (c) 2016 Louis RIVIERE <louis@riviere.xyz>
Copyright (c) 2020 Louis RIVIERE <louis@riviere.xyz>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
# Commands
## run
**run shell cmd on target**
## commands
**List commands**
## module
**show module's help**
## edit
**Edit a file.**
## modules
**list modules**
arg = search pattern
## help
**Show Help**
## manager
**show manager's help**
## logs
**Show log files**
## managers
**list managers**
arg = search pattern
**List managers**
## mappings
**list mappings**
## deploy
**deploy module**
## remote
**deploy module remotly**
## update
**update packages**
## upgrade
**upgrade packages**
May hang, if user input is required.
## installed
**list installed packages**
arg = search pattern
## installable
**list avaiable packages**
arg = search pattern
## search
**search packages**
arg = search pattern
## bigs
**list the bigest installed packages**
## upgradable
**list upgradble packages**
## install
**install package**
## remove
**remove package**
## cleanup
**cleanup packages**
**List mappings**
## status
**query service status**
## start
**start service**
## stop
**stop service**
## restart
**restart service**
## enable
**enable service**
## disable
**disable service**
## download
**download file**
## modules
**List modules**
## logs
**show log file**
arg = level (default to "info")
## outlog
**show commands log**
## outrun
**show commands history**
## outlog
**show commands log**
## run
**run shell cmd on target**
## edit
**edit remote file**
arg = file path to edit
## backup
**Backup**
Sync "source" dir to "target" SSH Host
## net
**net**
Net commands
from setux.repl.helps import helps
from setux.cmd.cmd import get_commands
with open('docs/commands.md', 'w') as out:
def w(txt=''):
out.write(f'{txt} \n')
w(f'# Commands')
for name, txt in helps.items():
for name, cmd in get_commands().items():
w(f'## {name}')
for n, line in enumerate(txt.split('\n')):
for n, line in enumerate(cmd.__doc__.split('\n')):
if n==0:
w(f'**{line}**')
else:
......
......@@ -7,7 +7,7 @@ readme = open(join(curdir, 'README.md')).read()
setup(
name = 'setux_repl',
version = '0.22.24.0',
version = '0.22.25.0',
description = 'System deployment',
long_description = readme,
long_description_content_type='text/markdown',
......@@ -31,16 +31,15 @@ setup(
],
python_requires='>3.10',
install_requires = [
'pybrary>=0.22.24.0',
'setux>=0.22.24.0',
'pybrary>=0.22.25.0',
'setux>=0.22.25.0',
],
packages = find_namespace_packages(
include=['setux.*']
),
entry_points = dict(
console_scripts = (
'setux=setux.cli.main:main',
'setux_config=setux.cli.config:edit',
'setux=setux.cli.main:top',
),
),
)
from os import environ
from os.path import expanduser
from sys import argv
from types import GeneratorType
from importlib.resources import read_text
from pybrary.command import Command, Param, ValidationError
from pybrary.net import ParamIPv4
from pybrary.ssh import ParamSSH
from pybrary.command import Command
from setux.core.package import CommonPackager
from setux.targets import Local, SSH
from setux.logger import debug
from setux.cli.config import get_config
from setux.repl.repl import repl
from ..cmd.cmd import CommandCmd
from .usage import usage
class TargetParam(Param):
'''Target
SSH or Local Host
'''
name = 'target'
positional = True
mandatory = True
default = 'local'
def verify(self, value):
outdir = self.get('outdir') or expanduser('~/setux')
if value=='local':
return Local(outdir=outdir)
try:
host = ParamSSH(self).validate(value)
except ValidationError:
raise ValidationError(f'{value} is not a valid target')
target = SSH(
name = value,
host = value,
outdir = outdir,
)
if not target or not target.cnx:
raise ValidationError(f'{value} is unreachable')
return target
class ModuleParam(Param):
'''Module
Setux Module
'''
name = 'module'
positional = True
def verify(self, value):
target = self.get('target')
if value in target.modules.items:
return value
raise ValidationError(f'Module {value} not found')
class DeployCmd(Command):
'''deploy
Deploy Module
'''
vargs = True
def run(self):
target = self.get('target')
name = self.get('module')
if self.args:
commands['module'](target, name)
m = "module's arguments must be keyword arguments\n"
print(f'\n ! invalid argument : {" ".join(self.args)} !\n ! {m}')
return
k = {k:v for k,v in self.kws.items() if not k.startswith('_')}
if name=='infos': k['report'] = 'quiet'
try:
target.deploy(name, **k)
except KeyError as x:
commands['module'](target, name)
key = x.args[0]
print(f'\n ! missing argument : {key} !\n')
class ManagerParam(Param):
'''Manager
Setux Manager
'''
name = 'manager'
positional = True
def verify(self, value):
target = self.get('target')
if value in target.managers:
return value
raise ValidationError(f'Manager {value} not found')
class ActionParam(Param):
'''Action
Manager Action
'''
name = 'action'
positional = True
def verify(self, value):
return value
class ManageCmd(Command):
'''manage
Manager command
'''
vargs = True
def run(self):
target = self.get('target')
name = self.get('manager')
action = self.get('action')
manager = getattr(target, name)
if ':' in action:
attr, _, val = action.partition(':')
setattr(manager, attr, val)
else:
action = getattr(manager, action)
if callable(action):
result = action(*self.args)
if isinstance(result, GeneratorType):
for vals in result:
print('\t'.join(vals))
else:
print(result)
else:
print(action)
class MethodParam(Param):
'''Method
Target or Manager method or attribute
'''
name = 'method'
positional = True
def verify(self, value):
target = self.get('target')
if hasattr(target, value):
method = getattr(target, value)
return method
if ':' in value:
meth, _, val = value.partition(':')
else:
meth = value
for manager in target.managers.values():
if isinstance(manager, CommonPackager): continue
if hasattr(manager, meth):
method = getattr(manager, meth)
if callable(method):
return method
else:
self.set('manager', manager)
return value
raise ValidationError(f'Invalid method "{value}" for target "{target}"')
from ..cmd.deploy import DeployCmd
from ..cmd.manage import ManageCmd
from ..cmd.method import MethodCmd
from ..cmd.target import TargetParam
from ..cmd.config import get_config, ConfigCmd
from setux.repl.repl import repl
class MethodCmd(Command):
'''method
Execute target method
or get/set target attribute
class UsageCmd(Command):
'''Usage
show usage
'''
vargs = True
def run(self):
target = self.get('target')
method = self.get('method')
if callable(method):
result = method(*self.args, **self.kws)
if isinstance(result, GeneratorType):
for vals in result:
print('\t'.join(map(str, vals)))
else:
print(result)
else:
manager = self.get('manager')
name = '.'.join(str(manager).split('.')[1:])
if ':' in method:
attr, _, val = method.partition(':')
val1 = getattr(manager, attr)
setattr(manager, attr, val)
val2 = getattr(manager, attr)
if val2 != val1:
print(f' {name}.{attr}:{val1} -> {val2}')
else:
value = getattr(manager, method)
print(f' {name}.{method} == {value}')
from setux.main import banner
tpl = read_text('setux.cli', 'usage.tpl')
usage = tpl.strip().format(**locals())
print(usage)
class MainCmd(Command):
......@@ -212,17 +32,9 @@ class MainCmd(Command):
command = CommandCmd(
shortcut = False,
),
deploy = DeployCmd(
ModuleParam,
),
manage = ManageCmd(
ManagerParam,
ActionParam,
),
method = MethodCmd(
MethodParam,
),
# help = usage,
deploy = DeployCmd(),
manage = ManageCmd(),
method = MethodCmd(),
)
......@@ -241,6 +53,9 @@ class CliCmd(Command):
'''cli
Setux cli
'''
Params = [
TargetParam,
]
config = get_config()
subs = dict(
repl = ReplCmd(),
......@@ -248,9 +63,18 @@ class CliCmd(Command):
)
def main():
cli = CliCmd(
TargetParam,
class TopCmd(Command):
'''Setux Cli Top Command
'''
subs = dict(
config = ConfigCmd(
shortcut = False,
),
cli = CliCmd(),
usage = UsageCmd(),
)
cli()
def top():
TopCmd()()
from setux.main import banner
doc = f'''{banner}
{banner}
setux "config"
setux [Target] [Module | Manager | Command] [*args | **kwargs]
Deploy Module, Call Manager or Execute Command on Target
"config":
Edit Setux Config
Target:
- May be passed on command line
- Set in environement as "setux_target"
- Set in config ( cf setux_config )
- defaults to "local"
May be set:
- On the command line as the first arg
- In the environement as "setux_target"
- In the config dict as the "target" key
defaults to "local"
Module, Manager or Command:
- Deploy Module ( see the "modules" command )
ex:
deploy infos
- Call Manager ( see the "managers" command)
ex :
pip installed
- Set or Get Manager's Property
- Get or Set Manager's Property
ex :
system hostname
system hostname:server
shortcut:
hostname
hostname:server
- Execute Command ( see the "help" command )
- if not specified : enter REPL on Target
'''
- Modules, as well as system, Package and Service managers can be shortcut
ex:
infos <> deploy infos
install vim <> Package install vim
restart ssh <> Service restart ssh
hostname <> system hostname
hostname:server <> system hostname:server
- Execute Command ( see the "help" command )
ex:
run ps -ef
edit /et/hostname
def usage(*args):
print(doc)
- if not specified :
enter REPL on Target
from os import environ
from os.path import expanduser
from pathlib import Path
from subprocess import call
from subprocess import run
from pybrary.command import Command
init_config = '''
......@@ -42,11 +44,16 @@ def get_config():
return get_config_all()[1]
def edit():
path = get_config_path()
if not path:
path = Path('~/.config/setux/config.py').expanduser()
with open(path, 'w') as out:
out.write(init_config)
editor = environ.get('EDITOR','vim')
call([editor, path])
class ConfigCmd(Command):
'''Config
edit setux config
'''
def run(self):
path = get_config_path()
if not path:
path = Path('~/.config/setux/config.py').expanduser()
with open(path, 'w') as out:
out.write(init_config)
editor = environ.get('EDITOR','vim')
run([editor, path])
from pybrary.command import Command, Param, ValidationError
class ModuleParam(Param):
'''Module
Setux Module
'''
name = 'module'
positional = True
def verify(self, name):
target = self.get('target')
if name in target.modules.items:
return name
raise ValidationError(f'Module {name} not found')
class DeployCmd(Command):
'''deploy
Deploy Module
'''
Params = [
ModuleParam,
]
vargs = True
def run(self):
target = self.get('target')
name = self.get('module')
module = target.modules.items[name]
if self.args:
m = "module's arguments must be keyword arguments\n"
print(f'\n ! invalid argument : {" ".join(self.args)} !\n ! {m}')
return
k = {k:v for k,v in self.kws.items() if not k.startswith('_')}
if name=='infos': k['report'] = 'quiet'
try:
target.deploy(name, **k)
except KeyError as x:
key = x.args[0]
print(f'\n ! missing argument : {key} !\n')
from types import GeneratorType
from pybrary.command import Command, Param, ValidationError
class ManagerParam(Param):
'''Manager
Setux Manager
'''
name = 'manager'
positional = True
def verify(self, value):
target = self.get('target')
if value in target.managers:
return value
raise ValidationError(f'Manager {value} not found')
class ActionParam(Param):
'''Action
Manager Action
'''
name = 'action'
positional = True
def verify(self, value):
return value
class ManageCmd(Command):
'''manage
Manager command
'''
Params = [
ManagerParam,