Skip to content

Commit

Permalink
Merge pull request #28 from nzlosh/fixes
Browse files Browse the repository at this point in the history
Update client auth for 3004+ and support TLS certificate verification.
  • Loading branch information
nzlosh authored Apr 4, 2024
2 parents f550d8a + 97c2b09 commit cf603f8
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 203 deletions.
13 changes: 13 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Change Log

## Unreleased; 3.0.0

### Add
- Added TLS connection verification.
- Special handling for test.ping and test.version with empty lists.

### Change
- Formatted Python code with black.
- Updated client authentication to work with Salt 3004 to 3006 (maybe higher)

### Removed
- Removed salt-pepper as a python dependency.

## 2.0.1

* Drop Python 2.7 support
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ be running on and where the StackStorm packs are installed.

## Usage Options

### Scenario 1: ST2 Installed on a Salt Master
### Scenario 1: StackStorm Installed on a Salt Master

#### Configuration

If ST2 is installed on the master, no local configuration is required.
If StackStorm is installed on the master, no local configuration is required.

#### Examples

Expand All @@ -30,7 +30,7 @@ If ST2 is installed on the master, no local configuration is required.
st2 run salt.bootstrap instance_id=<uuid> provider=my-nova name=web.example.com
```

### Scenario 2: ST2 Using Salt NetAPI
### Scenario 2: StackStorm using Salt NetAPI

#### Configuration

Expand All @@ -47,7 +47,7 @@ password: clams
```
**Note** : When modifying the configuration in `/opt/stackstorm/configs/` please
remember to tell StackStorm to load these new values by running
remember reload StackStorm to load these new values with the command:
`st2ctl reload --register-configs`

#### Examples
Expand All @@ -68,9 +68,9 @@ One can also use the generic "runner" action to execute arbitrary runners and ex

### Actions

Saltstack runner/execution module function calls are represented as Stackstorm actions. Considering Saltstack's [`archive` execution module](http://docs.saltstack.com/en/2014.7/ref/modules/all/salt.modules.archive.html#module-salt.modules.archive), every function would be exposed as an Stackstorm action.
Saltstack runner/execution module function calls are represented as StackStorm actions. Considering Saltstack's [`archive` execution module](http://docs.saltstack.com/en/2014.7/ref/modules/all/salt.modules.archive.html#module-salt.modules.archive), every function would be exposed as an StackStorm action.

Stackstorm actions for this pack are namespaced relative to their Saltstack NetAPI client name and module name. Thus having the form:
StackStorm actions for this pack are namespaced relative to their Saltstack NetAPI client name and module name. Thus having the form:

`[NetAPI client name]_[module name].[function name]`

Expand Down
4 changes: 2 additions & 2 deletions actions/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

class SaltClientAction(Action):
def run(self, matches, module, args=[], kwargs={}):
'''
"""
CLI Examples:
st2 run salt.client matches='web*' module=test.ping
st2 run salt.client module=pkg.install \
kwargs='{"pkgs":["git","httpd"]}'
'''
"""
cli = salt.client.LocalClient()
if args is None:
ret = cli.cmd(matches, module, kwarg=kwargs)
Expand Down
91 changes: 49 additions & 42 deletions actions/lib/base.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,16 @@
# pylint: disable=no-member

from st2common.runners.base_action import Action
from requests import Request
import requests
from lib.utils import sanitize_payload


class SaltPackage(object):
_expression_forms = [
'glob',
'grain',
'pillar',
'nodegroup',
'list',
'compound'
]
_expression_forms = ["glob", "grain", "pillar", "nodegroup", "list", "compound"]

def __init__(self, client='local'):
self._data = {"eauth": "",
"username": "",
"password": "",
"client": "",
"fun": ""}

self._data['client'] = client
def __init__(self, client="local"):
self._data = {"client": "", "fun": ""}
self._data["client"] = client

@property
def data(self):
Expand All @@ -35,36 +23,55 @@ def data(self, key_value=[]):


class SaltAction(Action):
sensitive_keys = ["eauth", "password"]

def __init__(self, config):
super(SaltAction, self).__init__(config=config)
self.url = self.config.get('api_url', None)
self.eauth = self.config.get('eauth', None)
self.username = self.config.get('username', None)
self.password = self.config.get('password', None)
super().__init__(config=config)
self.url = self.config.get("api_url", None)
self.eauth = self.config.get("eauth", None)
self.username = self.config.get("username", None)
self.password = self.config.get("password", None)
self.verify_tls = self.config.get("verify_tls", self.config.get("verify_ssl", True))

def login(self):
"""
Authenticate with Salt API to receive an authentication token.
"""
resp = requests.request(
"POST",
f"{self.url}/login",
json={"eauth": self.eauth, "username": self.username, "password": self.password},
verify=self.verify_tls,
)
token = resp.headers.get("X-Auth-Token", "failed-login")
return token

def generate_package(self, client='local', cmd=None,
**kwargs):
def generate_package(self, client="local", cmd=None, **kwargs):
self.data = SaltPackage(client).data
self.data['eauth'] = self.eauth
self.data['username'] = self.username
self.data['password'] = self.password

if cmd:
self.data['fun'] = cmd
if client == 'local':
self.data['tgt'] = kwargs.get('target', '*')
self.data['tgt_type'] = kwargs.get('tgt_type', 'glob')
if isinstance(kwargs.get('args', []), list) and len(kwargs.get('args', [])) > 0:
self.data['arg'] = kwargs['args']
if len(kwargs.get('data', {})) > 0:
if kwargs['data'].get('kwargs', None) is not None:
self.data['kwarg'] = kwargs['data']['kwargs']
clean_payload = sanitize_payload(('username', 'password'), self.data)
self.logger.info("[salt] Payload to be sent: {0}".format(clean_payload))
self.data["fun"] = cmd
if client == "local":
self.data["tgt"] = kwargs.get("target", "*")
self.data["tgt_type"] = kwargs.get("tgt_type", "glob")
if isinstance(kwargs.get("args", []), list) and len(kwargs.get("args", [])) > 0:
self.data["arg"] = kwargs["args"]
if len(kwargs.get("data", {})) > 0:
if kwargs["data"].get("kwargs", None) is not None:
self.data["kwarg"] = kwargs["data"]["kwargs"]
clean_payload = sanitize_payload(SaltAction.sensitive_keys, self.data)
self.logger.info("[salt] Payload to be sent: %s", clean_payload)

def generate_request(self):
req = Request('POST',
"{0}/run".format(self.url),
headers={'content-type': 'application/json',
'charset': 'utf-8'})
req = requests.Request(
"POST",
self.url,
headers={
"Accept": "application/json",
"Content-Type": "application/json",
"charset": "utf-8",
"x-auth-token": self.login(),
"User-Agent": "St2 Salt pack",
},
)
return req.prepare()
127 changes: 70 additions & 57 deletions actions/lib/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,89 @@
runner_action_meta = {
"name": "",
"parameters": {
"action": {
"type": "string",
"immutable": True,
"default": ""
},
"kwargs": {
"type": "object",
"required": False
}
"action": {"type": "string", "immutable": True, "default": ""},
"kwargs": {"type": "object", "required": False},
},
"runner_type": "python-script",
"description": "Run Salt Runner functions through Salt API",
"enabled": True,
"entry_point": "runner.py"}
"entry_point": "runner.py",
}

local_action_meta = {
"name": "",
"parameters": {
"action": {
"type": "string",
"immutable": True,
"default": ""
},
"kwargs": {
"type": "object",
"required": False
}
"action": {"type": "string", "immutable": True, "default": ""},
"kwargs": {"type": "object", "required": False},
},
"runner_type": "python-script",
"description": "Run Salt Runner functions through Salt API",
"enabled": True,
"entry_point": "runner.py"}
"entry_point": "runner.py",
}


actions = {
'archive': ['gunzip', 'gzip', 'rar', 'tar', 'unrar', 'unzip', 'zip_'],
'cloud': ['action', 'create', 'destroy', 'network_create', 'profile_',
'virtual_interface_create', 'volume_attach', 'volume_create',
'volume_delete', 'volume_detach'],
'cmdmod': ['run', 'run_chroot', 'script'],
'cp': ['get_file', 'get_url', 'push', 'push_dir'],
'cron': ['ls', 'rm_job', 'set_job', 'set_env', 'rm_env'],
'data': ['cas', 'getval', 'update', 'dump'],
'event': ['fire', 'fire_master', 'send'],
'file': ['access', 'chgrp', 'chown', 'directory_exists', 'file_exists',
'find', 'manage_file', 'mkdir', 'remove', 'replace', 'search',
'symlink', 'touch', 'truncate'],
'grains': ['append', 'delval', 'get', 'remove', 'setval'],
'hosts': ['add_hosts', 'get_alias', 'get_ip', 'rm_host', 'set_host'],
'htpasswd': ['useradd', 'userdel'],
'mine': ['delete', 'get', 'send', 'update'],
'network': ['connect', 'ipaddrs', 'interface_ip', 'ping', 'subnets'],
'pillar': ['get'],
'pip': ['install', 'freeze', 'uninstall'],
'pkg': ['install', 'refresh_db', 'remove'],
'puppet': ['enable', 'disable', 'fact',
'noop', 'status', 'run', 'summary'],
'ret': ['get_fun', 'get_jid', 'get_jids', 'get_minions'],
'saltutil': ['sync_all', 'sync_modules', 'sync_grains', 'sync_outputters',
'sync_renderers', 'sync_returners',
'sync_states', 'sync_utils'],
'schedule': ['add', 'delete', 'enable_job', 'disable_job', 'run_job'],
'service': ['available', 'start', 'restart', 'status', 'stop'],
'shadow': ['del_password', 'gen_password', 'set_expire', ''],
'state': ['highstate', 'single', 'sls'],
'supervisord': ['add', 'remove', 'restart',
'reread', 'start', 'stop', 'custom'],
'systemd': ['available', 'disable', 'restart', 'enable',
'stop', 'start', 'systemctl_reload'],
'test': ['ping', 'cross_test', 'echo'],
'useradd': ['add', 'delete', 'chshell'],

"archive": ["gunzip", "gzip", "rar", "tar", "unrar", "unzip", "zip_"],
"cloud": [
"action",
"create",
"destroy",
"network_create",
"profile_",
"virtual_interface_create",
"volume_attach",
"volume_create",
"volume_delete",
"volume_detach",
],
"cmdmod": ["run", "run_chroot", "script"],
"cp": ["get_file", "get_url", "push", "push_dir"],
"cron": ["ls", "rm_job", "set_job", "set_env", "rm_env"],
"data": ["cas", "getval", "update", "dump"],
"event": ["fire", "fire_master", "send"],
"file": [
"access",
"chgrp",
"chown",
"directory_exists",
"file_exists",
"find",
"manage_file",
"mkdir",
"remove",
"replace",
"search",
"symlink",
"touch",
"truncate",
],
"grains": ["append", "delval", "get", "remove", "setval"],
"hosts": ["add_hosts", "get_alias", "get_ip", "rm_host", "set_host"],
"htpasswd": ["useradd", "userdel"],
"mine": ["delete", "get", "send", "update"],
"network": ["connect", "ipaddrs", "interface_ip", "ping", "subnets"],
"pillar": ["get"],
"pip": ["install", "freeze", "uninstall"],
"pkg": ["install", "refresh_db", "remove"],
"puppet": ["enable", "disable", "fact", "noop", "status", "run", "summary"],
"ret": ["get_fun", "get_jid", "get_jids", "get_minions"],
"saltutil": [
"sync_all",
"sync_modules",
"sync_grains",
"sync_outputters",
"sync_renderers",
"sync_returners",
"sync_states",
"sync_utils",
],
"schedule": ["add", "delete", "enable_job", "disable_job", "run_job"],
"service": ["available", "start", "restart", "status", "stop"],
"shadow": ["del_password", "gen_password", "set_expire", ""],
"state": ["highstate", "single", "sls"],
"supervisord": ["add", "remove", "restart", "reread", "start", "stop", "custom"],
"systemd": ["available", "disable", "restart", "enable", "stop", "start", "systemctl_reload"],
"test": ["ping", "cross_test", "echo"],
"useradd": ["add", "delete", "chshell"],
}
Loading

0 comments on commit cf603f8

Please sign in to comment.