Skip to content

Commit 5c212da

Browse files
authored
Merge pull request #250 from StackStorm/feature/tasks
Add tasks to the module
2 parents fa0884e + 9b237be commit 5c212da

29 files changed

+1650
-3
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@
2222
/convert_report.txt
2323
/update_report.txt
2424
.DS_Store
25+
.coverage
2526
.librarian
2627
.kitchen
2728
.tmp
2829
.bundle
30+
/cover/
31+
/ci/
2932
Puppetfile.lock
33+
*.pyc

.sync.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
---
22
.gitignore:
33
paths:
4+
- .coverage
45
- .librarian
56
- .kitchen
67
- .tmp
78
- .bundle
9+
- /cover/
10+
- /ci/
811
- Puppetfile.lock
12+
- '*.pyc'
913
.gitlab-ci.yml:
1014
# we don't use GitLab
1115
unmanaged: true

.travis.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,22 @@ matrix:
5454
- UNIT_TEST="true"
5555
- PUPPET_GEM_VERSION="~> 6.0"
5656
- CHECK="syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop parallel_spec"
57+
- name: "Unit Testing - Bolt Tasks Python 2.7"
58+
language: python
59+
python: 2.7
60+
cache: pip
61+
before_install:
62+
- echo 'no bundler needed here'
63+
script:
64+
- make
65+
- name: "Unit Testing - Bolt Tasks Python 3.6"
66+
language: python
67+
python: 3.6
68+
cache: pip
69+
before_install:
70+
- echo 'no bundler needed here'
71+
script:
72+
- make
5773
- name: "Documentation Testing"
5874
rvm: 2.5
5975
# use default Gemfile in repo root (from PDK)

CHANGELOG.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
## Development
44

5+
- Added new tasks to communicate with the StackStorm CLI. The naming standard and parameters
6+
are modeled after the `st2` CLI command and must be run on the StackStorm node:
7+
- `st2::key_decrypt` - Decrypts an encrypted key/value pair
8+
- `st2::key_get` - Retrieves the value for a key from the datastore
9+
- `st2::key_load` - Loads a list of key/value pairs into the datastore
10+
- `st2::pack_install` - Installs a list of packs
11+
- `st2::pack_list` - Get a list of installed packs
12+
- `st2::pack_remove` - Removes a list of packs
13+
(Feature)
14+
515
- Fixed build for new release of `puppet/nginx` causing conflict with `puppetlabs/stdlib`.
616
The new version `0.16.0` of `puppet/nginx` requires `puppetlabs/stdlib >= 5.0.0`.
717
Several other modules we depend on require `puppetlabs/stdlib < 5.0.0` causing a conflict.
@@ -147,7 +157,7 @@
147157
- Fixed bug where the default nginx splash page was not being removed
148158
on RHEL/CentOS installs. (Bugfix)
149159
Contributed by @nmaludy
150-
160+
151161
## 1.1.0 (Sep 07, 2018)
152162

153163
- DEPRECATION WARNING - Dropped support for Puppet 3. (Enhancement)
@@ -202,7 +212,7 @@
202212
Contributed by @nmaludy
203213

204214
- Changed the behavior of `st2` packages. Previously they were automatically
205-
updating due to the package resources having `ensure => latest` set. Going
215+
updating due to the package resources having `ensure latest` set. Going
206216
forward, packages will have `ensure => present` set by default and it will be
207217
the responsibility of the end user to update the packages. (Change)
208218
Contributed by @nmaludy

Makefile

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,46 @@
11
THIS_FILE := $(lastword $(MAKEFILE_LIST))
22
ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
3+
CI_REPO_PATH ?= $(ROOT_DIR)/ci
4+
CI_REPO_BRANCH ?= master
5+
6+
.PHONY: all
7+
all: .DEFAULT
38

49
.PHONY: clean
5-
clean: clean-kitchen clean-puppet-librarian clean-bundler clean-pkg
10+
clean: clean-ci-repo clean-pyc clean-kitchen clean-puppet-librarian clean-bundler clean-pkg
11+
12+
# Clone the ci-repo into the ci/ directory
13+
.PHONY: clone-ci-repo
14+
clone-ci-repo:
15+
@echo
16+
@echo "==================== clone-ci-repo ===================="
17+
@echo
18+
@if [ ! -d "$(CI_REPO_PATH)" ]; then \
19+
git clone https://github.com/EncoreTechnologies/ci-puppet-python.git --depth 1 --single-branch --branch $(CI_REPO_BRANCH) $(CI_REPO_PATH); \
20+
else \
21+
cd $(CI_REPO_PATH); \
22+
git pull; \
23+
fi;
24+
25+
# Clean the ci-repo (calling `make clean` in that directory), then remove the
26+
# ci-repo directory
27+
.PHONY: clean-ci-repo
28+
clean-ci-repo:
29+
@echo
30+
@echo "==================== clean-ci-repo ===================="
31+
@echo
32+
@if [ -d "$(CI_REPO_PATH)" ]; then \
33+
make -f $(ROOT_DIR)/ci/Makefile clean; \
34+
fi;
35+
rm -rf $(CI_REPO_PATH)
36+
37+
# Clean *.pyc files.
38+
.PHONY: clean-pyc
39+
clean-pyc:
40+
@echo
41+
@echo "==================== clean-pyc ===================="
42+
@echo
43+
find $(ROOT_DIR) -name 'ci' -prune -or -name '.git' -or -type f -name "*.pyc" -print | xargs -r rm
644

745
# Clean kitchen build files
846
.PHONY: clean-kitchen
@@ -40,3 +78,23 @@ clean-pkg:
4078
@echo "== clean-pkg ======================================"
4179
@echo
4280
rm -rf ${ROOT_DIR}/pkg
81+
82+
# list all makefile targets
83+
.PHONY: list
84+
list:
85+
@if [ -d "$(CI_REPO_PATH)" ]; then \
86+
$(MAKE) --no-print-directory -f $(ROOT_DIR)/ci/Makefile list; \
87+
fi;
88+
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | sort | uniq | xargs
89+
90+
# forward all make targets not found in this makefile to the ci makefile to do
91+
# the actual work (by calling the invoke-ci-makefile target)
92+
# http://stackoverflow.org/wiki/Last-Resort_Makefile_Targets
93+
# Unfortunately the .DEFAULT target doesn't allow for dependencies
94+
# so we have to manually specify all of the steps in this target.
95+
.DEFAULT:
96+
$(MAKE) clone-ci-repo
97+
@echo
98+
@echo "==================== invoke ci/Makefile (targets: $(MAKECMDGOALS)) ===================="
99+
@echo
100+
make -f $(ROOT_DIR)/ci/Makefile $(MAKECMDGOALS)

README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,99 @@ and [librarian-puppet](http://librarian-puppet.com/).
254254
* Ubuntu 16.06 - Puppet 4 - [build/ubuntu16-puppet4/Puppetfile](build/ubuntu16-puppet4/Puppetfile)
255255
* Ubuntu 16.06 - Puppet 5 - [build/ubuntu16-puppet5/Puppetfile](build/ubuntu16-puppet5/Puppetfile)
256256
* Ubuntu 16.06 - Puppet 6 - [build/ubuntu16-puppet6/Puppetfile](build/ubuntu16-puppet6/Puppetfile)
257+
258+
259+
## Tasks
260+
261+
This module provides several tasks for interacting with StackStorm. These tasks
262+
are modeled after the `st2` CLI command, names of the tasks and parameters reflect this.
263+
Under the hood, the tasks invoke the `st2` CLI command so they must be executed on
264+
a node where StackStorm is installed.
265+
266+
### Tasks List
267+
268+
- `st2::key_decrypt` - Decrypts an encrypted key/value pair
269+
- `st2::key_get` - Retrieves the value for a key from the datastore
270+
- `st2::key_load` - Loads a list of key/value pairs into the datastore
271+
- `st2::pack_install` - Installs a list of packs
272+
- `st2::pack_list` - Get a list of installed packs
273+
- `st2::pack_remove` - Removes a list of packs
274+
275+
### Task Usage
276+
277+
Tasks that interact with the `st2` CLI command require authentication with the StackStorm
278+
instance. There are three options for authentication:
279+
280+
- API Key
281+
- Auth token
282+
- Username/password
283+
284+
#### Task Usage - API Key
285+
286+
API keys are the recommended way for systems to authenticate with StackStorm.
287+
To do this via a task, you would first create an API key in StackStorm:
288+
289+
``` shell
290+
$ st2 apikey create -m '{"used_by": "bolt"}'
291+
```
292+
293+
Copy the API `key` parameter in the output, and then use it when invoking one of
294+
the tasks in this module via the `api_key` parameter:
295+
296+
Usage via command line:
297+
``` shell
298+
299+
bolt task run st2::key_get key="testkey" api_key='xyz123'
300+
```
301+
302+
Usage in a plan:
303+
``` puppet
304+
$res = run_task('st2::key_get', $stackstorm_target,
305+
key => 'testkey',
306+
api_key => $api_key)
307+
```
308+
309+
#### Task Usage - Auth tokens
310+
311+
Auth tokens can be used by `bolt` to communicate with StackStorm. First, the user
312+
needs to create an auth token, then pass it in via the `auth_token` parameter
313+
314+
``` shell
315+
$ st2 auth myuser
316+
```
317+
318+
Copy the auth token in the output, and then use it when invoking one of
319+
the tasks in this module:
320+
321+
Usage via command line:
322+
``` shell
323+
bolt task run st2::key_get key="testkey" auth_token='xyz123'
324+
```
325+
326+
Usage in a plan:
327+
``` puppet
328+
$res = run_task('st2::key_get', $stackstorm_target,
329+
key => 'testkey',
330+
auth_token => $auth_token)
331+
```
332+
333+
#### Task Usage - Username/Password
334+
335+
Finally `bolt` can accept username/passwords to communicate with StackStorm.
336+
337+
Usage via command line:
338+
``` shell
339+
bolt task run st2::key_get key="testkey" username="myuser" password="xyz123"
340+
```
341+
342+
Usage in a plan:
343+
``` puppet
344+
$res = run_task('st2::key_get', $stackstorm_target,
345+
key => 'testkey',
346+
username => $username,
347+
password => $password)
348+
```
349+
257350

258351
## Upgrading StackStorm
259352

build/scripts/ci.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ elif [ ! -z "$DOCS_TEST" ]; then
1515
export PUPPET_GEM_VERSION="$PUPPET_GEM_VERSION"
1616
echo $PUPPET_GEM_VERSION
1717
"$SCRIPT_DIR"/ci_docs_generate.sh
18+
elif [ ! -z "$PYTHON_TEST" ]; then
19+
pushd "$SCRIPT_DIR"/../..
20+
make
1821
else
1922
export TEST_NAME="$TEST_NAME"
2023
echo $TEST_NAME

files/st2_task_base.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env python
2+
import json
3+
import os
4+
import subprocess
5+
import sys
6+
import traceback
7+
8+
# import Bolt task helper
9+
sys.path.append(os.path.join(os.environ['PT__installdir'], 'python_task_helper', 'files'))
10+
from task_helper import TaskHelper, TaskError
11+
12+
try:
13+
# python 2
14+
from urlparse import urlparse
15+
except ImportError:
16+
# python 3
17+
from urllib.parse import urlparse # noqa
18+
19+
20+
class St2TaskBase(TaskHelper):
21+
22+
def login(self, args):
23+
self.api_key = args.get('api_key')
24+
self.auth_token = args.get('auth_token')
25+
self.username = args.get('username')
26+
self.password = args.get('password')
27+
# inherit environment variables from the Bolt context to preserve things
28+
# like locale... otherwise we get errors from the StackStorm client.
29+
self.env = os.environ
30+
31+
# prefer API key over auth tokens
32+
if self.api_key:
33+
self.env['ST2_API_KEY'] = self.api_key
34+
elif self.auth_token:
35+
self.env['ST2_AUTH_TOKEN'] = self.auth_token
36+
elif self.username and self.password:
37+
# auth on the command line with username/password
38+
cmd = ['st2', 'auth', '--only-token', '-p', self.password, self.username]
39+
stdout = subprocess.check_output(cmd)
40+
self.env['ST2_AUTH_TOKEN'] = stdout.rstrip()
41+
# else
42+
# assume auth token is written in client config for this user.
43+
# don't worry, if there is no auth we'll get an error
44+
45+
def parse_output(self, stdout):
46+
try:
47+
# try to parse stdout as JSON and return the parse result
48+
return {'result': json.loads(stdout)}
49+
except ValueError:
50+
# JSON parsing failed, return the raw stdout string
51+
return {'result': stdout}
52+
53+
def exec_cmd(self, cmd, error_msg):
54+
result = {}
55+
try:
56+
stdout = subprocess.check_output(cmd,
57+
stderr=subprocess.STDOUT,
58+
env=self.env)
59+
result.update(self.parse_output(stdout))
60+
except subprocess.CalledProcessError as e:
61+
tb = traceback.format_exc()
62+
raise TaskError(("Could not {}: {} \n {}\n {}".
63+
format(error_msg, str(e), e.output, tb)),
64+
'st2.task.base/subprocess_error')
65+
except Exception as e:
66+
tb = traceback.format_exc()
67+
raise TaskError(("Could not {}: {}\n {}".
68+
format(error_msg, str(e), tb)),
69+
'st2.task.base/exec_exception')
70+
return result
71+
72+
def task(self, args):
73+
try:
74+
self.login(args)
75+
return self.task_impl(args)
76+
except Exception as e:
77+
tb = traceback.format_exc()
78+
raise TaskError(str(e) + '\n' + tb,
79+
'st2.task.base/task_exception')
80+
81+
def task_impl(self, args):
82+
raise NotImplementedError()

tasks/key_decrypt.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"description": "Decrypt a StackStorm key/value pair. TODO - Remove this when the following is closed: https://github.com/StackStorm/st2/issues/4545",
3+
"parameters": {
4+
"crypto_key_path": {
5+
"type": "String",
6+
"description": "Path to StackStorm crypto key"
7+
},
8+
"keys": {
9+
"type": "Array[Hash]",
10+
"description": "List of key value pairs"
11+
}
12+
},
13+
"implementations": [
14+
{"name": "key_decrypt.py"}
15+
]
16+
}

0 commit comments

Comments
 (0)