feat(cli): using-click-framework
- using click framework - added api client - allow interactions between code and service endpoints - documention on the command line - updated gitignore Change-Id: Ibe359025f5b35606d876c29fa88e04048f276cc8
This commit is contained in:
parent
a99fc4ad6c
commit
7b26e59422
@ -5,3 +5,6 @@ CODE_OF_CONDUCT.rst
|
||||
ChangeLog
|
||||
LICENSE
|
||||
OWNERS
|
||||
etc/armada/armada.conf
|
||||
etc/armada/policy.yaml
|
||||
charts/*
|
||||
|
@ -1,18 +0,0 @@
|
||||
# EditorConfig http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = true
|
||||
max_line_length = 80
|
||||
curly_bracket_next_line = false
|
||||
spaces_around_operators = true
|
||||
spaces_around_brackets = true
|
||||
indent_brace_style = K&R
|
||||
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -24,6 +24,9 @@ var/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
etc/*.sample
|
||||
etc/hostname
|
||||
etc/hosts
|
||||
etc/resolv.conf
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
@ -97,3 +100,9 @@ ENV/
|
||||
**/*.tgz
|
||||
**/_partials.tpl
|
||||
**/_globals.tpl
|
||||
|
||||
AUTHORS
|
||||
ChangeLog
|
||||
etc/armada/armada.conf
|
||||
etc/armada/policy.yaml
|
||||
.editorconfig
|
||||
|
@ -3,6 +3,8 @@ FROM ubuntu:16.04
|
||||
MAINTAINER Armada Team
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LANG=C.UTF-8
|
||||
ENV LC_ALL=C.UTF-8
|
||||
|
||||
COPY . /armada
|
||||
|
||||
|
@ -10,22 +10,32 @@
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# limitations under the License
|
||||
|
||||
import json
|
||||
import uuid
|
||||
import logging as log
|
||||
import os
|
||||
import uuid
|
||||
import yaml
|
||||
|
||||
import falcon
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
from armada import const
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class BaseResource(object):
|
||||
|
||||
def __init__(self):
|
||||
self.logger = LOG
|
||||
if not (os.path.exists(const.CONFIG_PATH)):
|
||||
logging.register_options(CONF)
|
||||
logging.set_defaults(default_log_levels=CONF.default_log_levels)
|
||||
logging.setup(CONF, 'armada')
|
||||
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def on_options(self, req, resp):
|
||||
self_attrs = dir(self)
|
||||
@ -39,29 +49,23 @@ class BaseResource(object):
|
||||
resp.headers['Allow'] = ','.join(allowed_methods)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def req_json(self, req):
|
||||
def req_yaml(self, req):
|
||||
if req.content_length is None or req.content_length == 0:
|
||||
return None
|
||||
|
||||
if req.content_type is not None and req.content_type.lower(
|
||||
) == 'application/json':
|
||||
raw_body = req.stream.read(req.content_length or 0)
|
||||
raw_body = req.stream.read(req.content_length or 0)
|
||||
|
||||
if raw_body is None:
|
||||
return None
|
||||
if raw_body is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
# json_body = json.loads(raw_body.decode('utf-8'))
|
||||
# return json_body
|
||||
return raw_body
|
||||
except json.JSONDecodeError as jex:
|
||||
self.error(
|
||||
req.context,
|
||||
"Invalid JSON in request: \n%s" % raw_body.decode('utf-8'))
|
||||
raise json.JSONDecodeError("%s: Invalid JSON in body: %s" %
|
||||
(req.path, jex))
|
||||
else:
|
||||
raise json.JSONDecodeError("Requires application/json payload")
|
||||
try:
|
||||
return yaml.safe_load_all(raw_body.decode('utf-8'))
|
||||
except yaml.YAMLError as jex:
|
||||
self.error(
|
||||
req.context,
|
||||
"Invalid YAML in request: \n%s" % raw_body.decode('utf-8'))
|
||||
raise Exception(
|
||||
"%s: Invalid YAML in body: %s" % (req.path, jex))
|
||||
|
||||
def return_error(self, resp, status_code, message="", retry=False):
|
||||
resp.body = json.dumps({
|
||||
|
@ -1,60 +0,0 @@
|
||||
# Copyright 2017 The Armada Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
|
||||
import falcon
|
||||
from oslo_log import log as logging
|
||||
|
||||
from armada import api
|
||||
from armada.handlers.armada import Armada
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Apply(api.BaseResource):
|
||||
'''
|
||||
apply armada endpoint service
|
||||
'''
|
||||
|
||||
def on_post(self, req, resp):
|
||||
try:
|
||||
|
||||
# Load data from request and get options
|
||||
data = self.req_json(req)
|
||||
opts = {}
|
||||
# opts = data['options']
|
||||
|
||||
# Encode filename
|
||||
# data['file'] = data['file'].encode('utf-8')
|
||||
armada = Armada(
|
||||
data,
|
||||
disable_update_pre=opts.get('disable_update_pre', False),
|
||||
disable_update_post=opts.get('disable_update_post', False),
|
||||
enable_chart_cleanup=opts.get('enable_chart_cleanup', False),
|
||||
dry_run=opts.get('dry_run', False),
|
||||
wait=opts.get('wait', False),
|
||||
timeout=opts.get('timeout', False))
|
||||
|
||||
msg = armada.sync()
|
||||
|
||||
resp.data = json.dumps({'message': msg})
|
||||
|
||||
resp.content_type = 'application/json'
|
||||
resp.status = falcon.HTTP_200
|
||||
except Exception as e:
|
||||
self.error(req.context, "Failed to apply manifest")
|
||||
self.return_error(
|
||||
resp, falcon.HTTP_500,
|
||||
message="Failed to install manifest: {} {}".format(e, data))
|
71
armada/api/controller/armada.py
Normal file
71
armada/api/controller/armada.py
Normal file
@ -0,0 +1,71 @@
|
||||
# Copyright 2017 The Armada Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
|
||||
import falcon
|
||||
|
||||
from armada import api
|
||||
from armada.common import policy
|
||||
from armada.handlers.armada import Armada
|
||||
|
||||
|
||||
class Apply(api.BaseResource):
|
||||
'''
|
||||
apply armada endpoint service
|
||||
'''
|
||||
@policy.enforce('armada:create_endpoints')
|
||||
def on_post(self, req, resp):
|
||||
try:
|
||||
|
||||
# Load data from request and get options
|
||||
|
||||
data = list(self.req_yaml(req))
|
||||
|
||||
if type(data[0]) is list:
|
||||
data = list(data[0])
|
||||
|
||||
opts = req.params
|
||||
|
||||
# Encode filename
|
||||
armada = Armada(
|
||||
data,
|
||||
disable_update_pre=req.get_param_as_bool(
|
||||
'disable_update_pre'),
|
||||
disable_update_post=req.get_param_as_bool(
|
||||
'disable_update_post'),
|
||||
enable_chart_cleanup=req.get_param_as_bool(
|
||||
'enable_chart_cleanup'),
|
||||
dry_run=req.get_param_as_bool('dry_run'),
|
||||
wait=req.get_param_as_bool('wait'),
|
||||
timeout=int(opts.get('timeout', 3600)),
|
||||
tiller_host=opts.get('tiller_host', None),
|
||||
tiller_port=int(opts.get('tiller_port', 44134)),
|
||||
)
|
||||
|
||||
msg = armada.sync()
|
||||
|
||||
resp.body = json.dumps(
|
||||
{
|
||||
'message': msg,
|
||||
}
|
||||
)
|
||||
|
||||
resp.content_type = 'application/json'
|
||||
resp.status = falcon.HTTP_200
|
||||
except Exception as e:
|
||||
err_message = 'Failed to apply manifest: {}'.format(e)
|
||||
self.error(req.context, err_message)
|
||||
self.return_error(
|
||||
resp, falcon.HTTP_500, message=err_message)
|
134
armada/api/controller/test.py
Normal file
134
armada/api/controller/test.py
Normal file
@ -0,0 +1,134 @@
|
||||
# Copyright 2017 The Armada Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
|
||||
import falcon
|
||||
|
||||
from armada import api
|
||||
from armada.common import policy
|
||||
from armada import const
|
||||
from armada.handlers.tiller import Tiller
|
||||
from armada.handlers.manifest import Manifest
|
||||
from armada.utils.release import release_prefix
|
||||
|
||||
|
||||
class Test(api.BaseResource):
|
||||
'''
|
||||
Test helm releases via release name
|
||||
'''
|
||||
|
||||
@policy.enforce('armada:test_release')
|
||||
def on_get(self, req, resp, release):
|
||||
try:
|
||||
self.logger.info('RUNNING: %s', release)
|
||||
opts = req.params
|
||||
tiller = Tiller(tiller_host=opts.get('tiller_host', None),
|
||||
tiller_port=opts.get('tiller_port', None))
|
||||
tiller_resp = tiller.testing_release(release)
|
||||
msg = {
|
||||
'result': '',
|
||||
'message': ''
|
||||
}
|
||||
|
||||
if tiller_resp:
|
||||
test_status = getattr(
|
||||
tiller_resp.info.status, 'last_test_suite_run', 'FAILED')
|
||||
|
||||
if test_status.result[0].status:
|
||||
msg['result'] = 'PASSED: {}'.format(release)
|
||||
msg['message'] = 'MESSAGE: Test Pass'
|
||||
self.logger.info(msg)
|
||||
else:
|
||||
msg['result'] = 'FAILED: {}'.format(release)
|
||||
msg['message'] = 'MESSAGE: Test Fail'
|
||||
self.logger.info(msg)
|
||||
else:
|
||||
msg['result'] = 'FAILED: {}'.format(release)
|
||||
msg['message'] = 'MESSAGE: No test found'
|
||||
|
||||
resp.body = json.dumps(msg)
|
||||
resp.status = falcon.HTTP_200
|
||||
resp.content_type = 'application/json'
|
||||
|
||||
except Exception as e:
|
||||
err_message = 'Failed to test {}: {}'.format(release, e)
|
||||
self.error(req.context, err_message)
|
||||
self.return_error(
|
||||
resp, falcon.HTTP_500, message=err_message)
|
||||
|
||||
|
||||
class Tests(api.BaseResource):
|
||||
'''
|
||||
Test helm releases via a manifest
|
||||
'''
|
||||
|
||||
@policy.enforce('armada:tests_manifest')
|
||||
def on_post(self, req, resp):
|
||||
try:
|
||||
opts = req.params
|
||||
tiller = Tiller(tiller_host=opts.get('tiller_host', None),
|
||||
tiller_port=opts.get('tiller_port', None))
|
||||
|
||||
documents = self.req_yaml(req)
|
||||
armada_obj = Manifest(documents).get_manifest()
|
||||
prefix = armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
const.KEYWORD_PREFIX)
|
||||
known_releases = [release[0] for release in tiller.list_charts()]
|
||||
|
||||
message = {
|
||||
'tests': {
|
||||
'passed': [],
|
||||
'skipped': [],
|
||||
'failed': []
|
||||
}
|
||||
}
|
||||
|
||||
for group in armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
const.KEYWORD_GROUPS):
|
||||
for ch in group.get(const.KEYWORD_CHARTS):
|
||||
release_name = release_prefix(
|
||||
prefix, ch.get('chart').get('chart_name'))
|
||||
|
||||
if release_name in known_releases:
|
||||
self.logger.info('RUNNING: %s tests', release_name)
|
||||
resp = tiller.testing_release(release_name)
|
||||
|
||||
if not resp:
|
||||
continue
|
||||
|
||||
test_status = getattr(
|
||||
resp.info.status, 'last_test_suite_run',
|
||||
'FAILED')
|
||||
if test_status.results[0].status:
|
||||
self.logger.info("PASSED: %s", release_name)
|
||||
message['test']['passed'].append(release_name)
|
||||
else:
|
||||
self.logger.info("FAILED: %s", release_name)
|
||||
message['test']['failed'].append(release_name)
|
||||
else:
|
||||
self.logger.info(
|
||||
'Release %s not found - SKIPPING', release_name)
|
||||
message['test']['skipped'].append(release_name)
|
||||
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
resp.body = json.dumps(message)
|
||||
resp.content_type = 'application/json'
|
||||
|
||||
except Exception as e:
|
||||
err_message = 'Failed to test manifest: {}'.format(e)
|
||||
self.error(req.context, err_message)
|
||||
self.return_error(
|
||||
resp, falcon.HTTP_500, message=err_message)
|
@ -15,16 +15,11 @@
|
||||
import json
|
||||
|
||||
import falcon
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from armada import api
|
||||
from armada.common import policy
|
||||
from armada.handlers.tiller import Tiller
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class Status(api.BaseResource):
|
||||
@policy.enforce('tiller:get_status')
|
||||
@ -33,21 +28,27 @@ class Status(api.BaseResource):
|
||||
get tiller status
|
||||
'''
|
||||
try:
|
||||
message = {'tiller': Tiller().tiller_status()}
|
||||
opts = req.params
|
||||
tiller = Tiller(
|
||||
tiller_host=opts.get('tiller_host', None),
|
||||
tiller_port=opts.get('tiller_port', None))
|
||||
|
||||
if message.get('tiller', False):
|
||||
resp.status = falcon.HTTP_200
|
||||
else:
|
||||
resp.status = falcon.HTTP_503
|
||||
message = {
|
||||
'tiller': {
|
||||
'state': tiller.tiller_status(),
|
||||
'version': tiller.tiller_version()
|
||||
}
|
||||
}
|
||||
|
||||
resp.data = json.dumps(message)
|
||||
resp.status = falcon.HTTP_200
|
||||
resp.body = json.dumps(message)
|
||||
resp.content_type = 'application/json'
|
||||
|
||||
except Exception as e:
|
||||
self.error(req.context, "Unable to find resources")
|
||||
err_message = 'Failed to get Tiller Status: {}'.format(e)
|
||||
self.error(req.context, err_message)
|
||||
self.return_error(
|
||||
resp, falcon.HTTP_500,
|
||||
message="Unable to get status: {}".format(e))
|
||||
resp, falcon.HTTP_500, message=err_message)
|
||||
|
||||
|
||||
class Release(api.BaseResource):
|
||||
@ -58,21 +59,23 @@ class Release(api.BaseResource):
|
||||
'''
|
||||
try:
|
||||
# Get tiller releases
|
||||
handler = Tiller()
|
||||
opts = req.params
|
||||
tiller = Tiller(tiller_host=opts.get('tiller_host', None),
|
||||
tiller_port=opts.get('tiller_port', None))
|
||||
|
||||
releases = {}
|
||||
for release in handler.list_releases():
|
||||
for release in tiller.list_releases():
|
||||
if not releases.get(release.namespace, None):
|
||||
releases[release.namespace] = []
|
||||
|
||||
releases[release.namespace].append(release.name)
|
||||
|
||||
resp.data = json.dumps({'releases': releases})
|
||||
resp.body = json.dumps({'releases': releases})
|
||||
resp.content_type = 'application/json'
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
except Exception as e:
|
||||
self.error(req.context, "Unable to find resources")
|
||||
err_message = 'Unable to find Tiller Releases: {}'.format(e)
|
||||
self.error(req.context, err_message)
|
||||
self.return_error(
|
||||
resp, falcon.HTTP_500,
|
||||
message="Unable to find Releases: {}".format(e))
|
||||
resp, falcon.HTTP_500, message=err_message)
|
@ -13,17 +13,13 @@
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import yaml
|
||||
|
||||
import falcon
|
||||
from oslo_log import log as logging
|
||||
|
||||
from armada import api
|
||||
from armada.common import policy
|
||||
from armada.utils.lint import validate_armada_documents
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Validate(api.BaseResource):
|
||||
'''
|
||||
@ -33,24 +29,19 @@ class Validate(api.BaseResource):
|
||||
@policy.enforce('armada:validate_manifest')
|
||||
def on_post(self, req, resp):
|
||||
try:
|
||||
manifest = self.req_yaml(req)
|
||||
documents = list(manifest)
|
||||
|
||||
message = {
|
||||
'valid':
|
||||
validate_armada_documents(
|
||||
list(yaml.safe_load_all(self.req_json(req))))
|
||||
'valid': validate_armada_documents(documents)
|
||||
}
|
||||
|
||||
if message.get('valid', False):
|
||||
resp.status = falcon.HTTP_200
|
||||
else:
|
||||
resp.status = falcon.HTTP_400
|
||||
|
||||
resp.data = json.dumps(message)
|
||||
resp.status = falcon.HTTP_200
|
||||
resp.body = json.dumps(message)
|
||||
resp.content_type = 'application/json'
|
||||
|
||||
except Exception:
|
||||
self.error(req.context, "Failed: Invalid Armada Manifest")
|
||||
err_message = 'Failed to validate Armada Manifest'
|
||||
self.error(req.context, err_message)
|
||||
self.return_error(
|
||||
resp,
|
||||
falcon.HTTP_400,
|
||||
message="Failed: Invalid Armada Manifest")
|
||||
resp, falcon.HTTP_400, message=err_message)
|
@ -17,18 +17,20 @@ from uuid import UUID
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class AuthMiddleware(object):
|
||||
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
# Authentication
|
||||
def process_request(self, req, resp):
|
||||
ctx = req.context
|
||||
|
||||
for k, v in req.headers.items():
|
||||
LOG.debug("Request with header %s: %s" % (k, v))
|
||||
self.logger.debug("Request with header %s: %s" % (k, v))
|
||||
|
||||
auth_status = req.get_header('X-SERVICE-IDENTITY-STATUS')
|
||||
service = True
|
||||
@ -65,8 +67,9 @@ class AuthMiddleware(object):
|
||||
else:
|
||||
ctx.is_admin_project = False
|
||||
|
||||
LOG.debug('Request from authenticated user %s with roles %s' %
|
||||
(ctx.user, ','.join(ctx.roles)))
|
||||
self.logger.debug(
|
||||
'Request from authenticated user %s with roles %s' %
|
||||
(ctx.user, ','.join(ctx.roles)))
|
||||
else:
|
||||
ctx.authenticated = False
|
||||
|
||||
@ -91,6 +94,9 @@ class ContextMiddleware(object):
|
||||
|
||||
|
||||
class LoggingMiddleware(object):
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def process_response(self, req, resp, resource, req_succeeded):
|
||||
ctx = req.context
|
||||
extra = {
|
||||
@ -99,4 +105,4 @@ class LoggingMiddleware(object):
|
||||
'external_ctx': ctx.external_marker,
|
||||
}
|
||||
resp.append_header('X-Armada-Req', ctx.request_id)
|
||||
LOG.info("%s - %s" % (req.uri, resp.status), extra=extra)
|
||||
self.logger.info("%s - %s" % (req.uri, resp.status), extra=extra)
|
||||
|
@ -12,34 +12,28 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
|
||||
import falcon
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from armada import conf
|
||||
from armada.api import ArmadaRequest
|
||||
from armada.api.armada_controller import Apply
|
||||
from armada.api.controller.armada import Apply
|
||||
from armada.api.middleware import AuthMiddleware
|
||||
from armada.api.middleware import ContextMiddleware
|
||||
from armada.api.middleware import LoggingMiddleware
|
||||
from armada.api.tiller_controller import Release
|
||||
from armada.api.tiller_controller import Status
|
||||
from armada.api.validation_controller import Validate
|
||||
from armada.api.controller.test import Test
|
||||
from armada.api.controller.test import Tests
|
||||
from armada.api.controller.tiller import Release
|
||||
from armada.api.controller.tiller import Status
|
||||
from armada.api.controller.validation import Validate
|
||||
from armada.common import policy
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
conf.set_app_default_configs()
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
# Build API
|
||||
def create(middleware=CONF.middleware):
|
||||
if not (os.path.exists('etc/armada/armada.conf')):
|
||||
logging.register_options(CONF)
|
||||
logging.set_defaults(default_log_levels=CONF.default_log_levels)
|
||||
logging.setup(CONF, 'armada')
|
||||
|
||||
policy.setup_policy()
|
||||
|
||||
@ -55,13 +49,17 @@ def create(middleware=CONF.middleware):
|
||||
api = falcon.API(request_type=ArmadaRequest)
|
||||
|
||||
# Configure API routing
|
||||
url_routes_v1 = (('apply', Apply()),
|
||||
('releases', Release()),
|
||||
('status', Status()),
|
||||
('validate', Validate()))
|
||||
url_routes_v1 = (
|
||||
('apply', Apply()),
|
||||
('releases', Release()),
|
||||
('status', Status()),
|
||||
('tests', Tests()),
|
||||
('test/{release}', Test()),
|
||||
('validate', Validate()),
|
||||
)
|
||||
|
||||
for route, service in url_routes_v1:
|
||||
api.add_route("/v1.0/{}".format(route), service)
|
||||
api.add_route("/api/v1.0/{}".format(route), service)
|
||||
|
||||
return api
|
||||
|
||||
|
@ -11,3 +11,22 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CliAction(object):
|
||||
|
||||
def __init__(self):
|
||||
self.logger = LOG
|
||||
logging.register_options(CONF)
|
||||
logging.set_defaults(default_log_levels=CONF.default_log_levels)
|
||||
logging.setup(CONF, 'armada')
|
||||
|
||||
def invoke(self):
|
||||
raise Exception()
|
||||
|
@ -12,61 +12,195 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from cliff import command as cmd
|
||||
import yaml
|
||||
|
||||
import click
|
||||
from oslo_config import cfg
|
||||
|
||||
from armada.cli import CliAction
|
||||
from armada.handlers.armada import Armada
|
||||
|
||||
|
||||
def applyCharts(args):
|
||||
|
||||
armada = Armada(open(args.file).read(),
|
||||
args.disable_update_pre,
|
||||
args.disable_update_post,
|
||||
args.enable_chart_cleanup,
|
||||
args.dry_run,
|
||||
args.set,
|
||||
args.wait,
|
||||
args.timeout,
|
||||
args.tiller_host,
|
||||
args.tiller_port,
|
||||
args.values,
|
||||
args.debug_logging)
|
||||
armada.sync()
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class ApplyChartsCommand(cmd.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ApplyChartsCommand, self).get_parser(prog_name)
|
||||
parser.add_argument('file', type=str, metavar='FILE',
|
||||
help='Armada yaml file')
|
||||
parser.add_argument('--dry-run', action='store_true',
|
||||
default=False, help='Run charts with dry run')
|
||||
parser.add_argument('--debug-logging', action='store_true',
|
||||
default=False, help='Show debug logs')
|
||||
parser.add_argument('--disable-update-pre', action='store_true',
|
||||
default=False, help='Disable pre upgrade actions')
|
||||
parser.add_argument('--disable-update-post', action='store_true',
|
||||
default=False, help='Disable post upgrade actions')
|
||||
parser.add_argument('--enable-chart-cleanup', action='store_true',
|
||||
default=False, help='Enable Chart Clean Up')
|
||||
parser.add_argument('--set', action='append', help='Override Armada'
|
||||
' manifest values.')
|
||||
parser.add_argument('--wait', action='store_true',
|
||||
default=False, help='Wait until all charts'
|
||||
'have been deployed')
|
||||
parser.add_argument('--timeout', action='store', type=int,
|
||||
default=3600, help='Specifies time to wait'
|
||||
' for charts to deploy')
|
||||
parser.add_argument('--tiller-host', action='store', type=str,
|
||||
help='Specify the tiller host')
|
||||
@click.group()
|
||||
def apply():
|
||||
""" Apply manifest to cluster
|
||||
|
||||
parser.add_argument('--tiller-port', action='store', type=int,
|
||||
default=44134, help='Specify the tiller port')
|
||||
"""
|
||||
|
||||
parser.add_argument('--values', action='append',
|
||||
help='Override manifest values with a yaml file')
|
||||
|
||||
return parser
|
||||
DESC = """
|
||||
This command install and updates charts defined in armada manifest
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
applyCharts(parsed_args)
|
||||
The apply argument must be relative path to Armada Manifest. Executing apply
|
||||
commnad once will install all charts defined in manifest. Re-executing apply
|
||||
commnad will execute upgrade.
|
||||
|
||||
To see how to create an Armada manifest:
|
||||
http://armada-helm.readthedocs.io/en/latest/operations/
|
||||
|
||||
To obtain install/upgrade charts:
|
||||
|
||||
\b
|
||||
$ armada apply examples/simple.yaml
|
||||
|
||||
To obtain override manifest:
|
||||
|
||||
\b
|
||||
$ armada apply examples/simple.yaml \
|
||||
--set manifest:simple-armada:relase_name="wordpress"
|
||||
|
||||
\b
|
||||
or
|
||||
|
||||
\b
|
||||
$ armada apply examples/simple.yaml \
|
||||
--values examples/simple-ovr-values.yaml
|
||||
|
||||
"""
|
||||
|
||||
SHORT_DESC = "command install manifest charts"
|
||||
|
||||
|
||||
@apply.command(name='apply', help=DESC, short_help=SHORT_DESC)
|
||||
@click.argument('filename')
|
||||
@click.option('--api', help="Contacts service endpoint", is_flag=True)
|
||||
@click.option(
|
||||
'--disable-update-post', help="run charts without install", is_flag=True)
|
||||
@click.option(
|
||||
'--disable-update-pre', help="run charts without install", is_flag=True)
|
||||
@click.option('--dry-run', help="run charts without install", is_flag=True)
|
||||
@click.option(
|
||||
'--enable-chart-cleanup', help="Clean up Unmanaged Charts", is_flag=True)
|
||||
@click.option('--set', multiple=True, type=str, default=[])
|
||||
@click.option('--tiller-host', help="Tiller host ip")
|
||||
@click.option(
|
||||
'--tiller-port', help="Tiller host port", type=int, default=44134)
|
||||
@click.option(
|
||||
'--timeout', help="specifies time to wait for charts", type=int,
|
||||
default=3600)
|
||||
@click.option('--values', '-f', multiple=True, type=str, default=[])
|
||||
@click.option(
|
||||
'--wait', help="wait until all charts deployed", is_flag=True)
|
||||
@click.option(
|
||||
'--debug/--no-debug', help='Enable or disable debugging', default=False)
|
||||
@click.pass_context
|
||||
def apply_create(ctx,
|
||||
filename,
|
||||
api,
|
||||
disable_update_post,
|
||||
disable_update_pre,
|
||||
dry_run,
|
||||
enable_chart_cleanup,
|
||||
set,
|
||||
tiller_host,
|
||||
tiller_port,
|
||||
timeout,
|
||||
values,
|
||||
wait,
|
||||
debug):
|
||||
|
||||
if debug:
|
||||
CONF.debug = debug
|
||||
|
||||
ApplyManifest(
|
||||
ctx,
|
||||
filename,
|
||||
api,
|
||||
disable_update_post,
|
||||
disable_update_pre,
|
||||
dry_run,
|
||||
enable_chart_cleanup,
|
||||
set,
|
||||
tiller_host,
|
||||
tiller_port,
|
||||
timeout,
|
||||
values,
|
||||
wait).invoke()
|
||||
|
||||
|
||||
class ApplyManifest(CliAction):
|
||||
def __init__(self,
|
||||
ctx,
|
||||
filename,
|
||||
api,
|
||||
disable_update_post,
|
||||
disable_update_pre,
|
||||
dry_run,
|
||||
enable_chart_cleanup,
|
||||
set,
|
||||
tiller_host,
|
||||
tiller_port,
|
||||
timeout,
|
||||
values,
|
||||
wait):
|
||||
super(ApplyManifest, self).__init__()
|
||||
self.ctx = ctx
|
||||
self.filename = filename
|
||||
self.api = api
|
||||
self.disable_update_post = disable_update_post
|
||||
self.disable_update_pre = disable_update_pre
|
||||
self.dry_run = dry_run
|
||||
self.enable_chart_cleanup = enable_chart_cleanup
|
||||
self.set = set
|
||||
self.tiller_host = tiller_host
|
||||
self.tiller_port = tiller_port
|
||||
self.timeout = timeout
|
||||
self.values = values
|
||||
self.wait = wait
|
||||
|
||||
def output(self, resp):
|
||||
for result in resp:
|
||||
if not resp[result] and not result == 'diff':
|
||||
self.logger.info(
|
||||
'Did not performed chart %s(s)', result)
|
||||
elif result == 'diff' and not resp[result]:
|
||||
self.logger.info('No Relase changes detected')
|
||||
|
||||
for ch in resp[result]:
|
||||
if not result == 'diff':
|
||||
msg = 'Chart {} was {}'.format(ch, result)
|
||||
self.logger.info(msg)
|
||||
else:
|
||||
self.logger.info('Chart values diff')
|
||||
self.logger.info(ch)
|
||||
|
||||
def invoke(self):
|
||||
|
||||
if not self.ctx.obj.get('api', False):
|
||||
with open(self.filename) as f:
|
||||
armada = Armada(
|
||||
list(yaml.safe_load_all(f.read())),
|
||||
self.disable_update_pre,
|
||||
self.disable_update_post,
|
||||
self.enable_chart_cleanup,
|
||||
self.dry_run,
|
||||
self.set,
|
||||
self.wait,
|
||||
self.timeout,
|
||||
self.tiller_host,
|
||||
self.tiller_port,
|
||||
self.values)
|
||||
|
||||
resp = armada.sync()
|
||||
self.output(resp)
|
||||
else:
|
||||
query = {
|
||||
'disable_update_post': self.disable_update_post,
|
||||
'disable_update_pre': self.disable_update_pre,
|
||||
'dry_run': self.dry_run,
|
||||
'enable_chart_cleanup': self.enable_chart_cleanup,
|
||||
'tiller_host': self.tiller_host,
|
||||
'tiller_port': self.tiller_port,
|
||||
'timeout': self.timeout,
|
||||
'wait': self.wait
|
||||
}
|
||||
|
||||
client = self.ctx.obj.get('CLIENT')
|
||||
|
||||
with open(self.filename, 'r') as f:
|
||||
resp = client.post_apply(
|
||||
manifest=f.read(), values=self.values, set=self.set,
|
||||
query=query)
|
||||
self.output(resp.get('message'))
|
||||
|
@ -14,94 +14,141 @@
|
||||
|
||||
import yaml
|
||||
|
||||
from cliff import command as cmd
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import click
|
||||
|
||||
from armada.cli import CliAction
|
||||
from armada import const
|
||||
from armada.handlers.manifest import Manifest
|
||||
from armada.handlers.tiller import Tiller
|
||||
from armada.utils.release import release_prefix
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
CONF = cfg.CONF
|
||||
@click.group()
|
||||
def test():
|
||||
""" Test Manifest Charts
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def testService(args):
|
||||
DESC = """
|
||||
This command test deployed charts
|
||||
|
||||
tiller = Tiller(tiller_host=args.tiller_host, tiller_port=args.tiller_port)
|
||||
known_release_names = [release[0] for release in tiller.list_charts()]
|
||||
The tiller command uses flags to obtain information from tiller services.
|
||||
The test command will run the release chart tests either via a the manifest or
|
||||
by targetings a relase.
|
||||
|
||||
if args.release:
|
||||
LOG.info("RUNNING: %s tests", args.release)
|
||||
resp = tiller.testing_release(args.release)
|
||||
To test armada deployed releases:
|
||||
|
||||
if not resp:
|
||||
LOG.info("FAILED: %s", args.release)
|
||||
return
|
||||
$ armada test --file examples/simple.yaml
|
||||
|
||||
test_status = getattr(resp.info.status, 'last_test_suite_run',
|
||||
'FAILED')
|
||||
if test_status.results[0].status:
|
||||
LOG.info("PASSED: %s", args.release)
|
||||
else:
|
||||
LOG.info("FAILED: %s", args.release)
|
||||
To test release:
|
||||
|
||||
if args.file:
|
||||
documents = yaml.safe_load_all(open(args.file).read())
|
||||
armada_obj = Manifest(documents).get_manifest()
|
||||
prefix = armada_obj.get(const.KEYWORD_ARMADA).get(const.KEYWORD_PREFIX)
|
||||
$ armada test --release blog-1
|
||||
|
||||
for group in armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
const.KEYWORD_GROUPS):
|
||||
for ch in group.get(const.KEYWORD_CHARTS):
|
||||
release_name = release_prefix(
|
||||
prefix, ch.get('chart').get('chart_name'))
|
||||
"""
|
||||
|
||||
if release_name in known_release_names:
|
||||
LOG.info('RUNNING: %s tests', release_name)
|
||||
resp = tiller.testing_release(release_name)
|
||||
SHORT_DESC = "command test releases"
|
||||
|
||||
if not resp:
|
||||
continue
|
||||
|
||||
test_status = getattr(resp.info.status,
|
||||
'last_test_suite_run', 'FAILED')
|
||||
if test_status.results[0].status:
|
||||
LOG.info("PASSED: %s", release_name)
|
||||
else:
|
||||
LOG.info("FAILED: %s", release_name)
|
||||
@test.command(name='test', help=DESC, short_help=SHORT_DESC)
|
||||
@click.option('--file', help='armada manifest', type=str)
|
||||
@click.option('--release', help='helm release', type=str)
|
||||
@click.option('--tiller-host', help="Tiller Host IP")
|
||||
@click.option(
|
||||
'--tiller-port', help="Tiller host Port", type=int, default=44134)
|
||||
@click.pass_context
|
||||
def test_charts(ctx, file, release, tiller_host, tiller_port):
|
||||
TestChartManifest(
|
||||
ctx, file, release, tiller_host, tiller_port).invoke()
|
||||
|
||||
|
||||
class TestChartManifest(CliAction):
|
||||
def __init__(self, ctx, file, release, tiller_host, tiller_port):
|
||||
|
||||
super(TestChartManifest, self).__init__()
|
||||
self.ctx = ctx
|
||||
self.file = file
|
||||
self.release = release
|
||||
self.tiller_host = tiller_host
|
||||
self.tiller_port = tiller_port
|
||||
|
||||
def invoke(self):
|
||||
tiller = Tiller(
|
||||
tiller_host=self.tiller_host, tiller_port=self.tiller_port)
|
||||
known_release_names = [release[0] for release in tiller.list_charts()]
|
||||
|
||||
if self.release:
|
||||
if not self.ctx.obj.get('api', False):
|
||||
self.logger.info("RUNNING: %s tests", self.release)
|
||||
resp = tiller.testing_release(self.release)
|
||||
|
||||
if not resp:
|
||||
self.logger.info("FAILED: %s", self.release)
|
||||
return
|
||||
|
||||
test_status = getattr(resp.info.status, 'last_test_suite_run',
|
||||
'FAILED')
|
||||
if test_status.results[0].status:
|
||||
self.logger.info("PASSED: %s", self.release)
|
||||
else:
|
||||
LOG.info('Release %s not found - SKIPPING', release_name)
|
||||
self.logger.info("FAILED: %s", self.release)
|
||||
else:
|
||||
client = self.ctx.obj.get('CLIENT')
|
||||
query = {
|
||||
'tiller_host': self.tiller_host,
|
||||
'tiller_port': self.tiller_port
|
||||
}
|
||||
resp = client.get_test_release(release=self.release,
|
||||
query=query)
|
||||
|
||||
self.logger.info(resp.get('result'))
|
||||
self.logger.info(resp.get('message'))
|
||||
|
||||
class TestServerCommand(cmd.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(TestServerCommand, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--release', action='store', help='testing Helm in Release')
|
||||
parser.add_argument(
|
||||
'-f',
|
||||
'--file',
|
||||
type=str,
|
||||
metavar='FILE',
|
||||
help='testing Helm releases in Manifest')
|
||||
parser.add_argument(
|
||||
'--tiller-host',
|
||||
action='store',
|
||||
type=str,
|
||||
default=None,
|
||||
help='Specify the tiller host')
|
||||
parser.add_argument(
|
||||
'--tiller-port',
|
||||
action='store',
|
||||
type=int,
|
||||
default=44134,
|
||||
help='Specify the tiller port')
|
||||
if self.file:
|
||||
if not self.ctx.obj.get('api', False):
|
||||
documents = yaml.safe_load_all(open(self.file).read())
|
||||
armada_obj = Manifest(documents).get_manifest()
|
||||
prefix = armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
const.KEYWORD_PREFIX)
|
||||
|
||||
return parser
|
||||
for group in armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
const.KEYWORD_GROUPS):
|
||||
for ch in group.get(const.KEYWORD_CHARTS):
|
||||
release_name = release_prefix(
|
||||
prefix, ch.get('chart').get('chart_name'))
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
testService(parsed_args)
|
||||
if release_name in known_release_names:
|
||||
self.logger.info('RUNNING: %s tests', release_name)
|
||||
resp = tiller.testing_release(release_name)
|
||||
|
||||
if not resp:
|
||||
continue
|
||||
|
||||
test_status = getattr(
|
||||
resp.info.status, 'last_test_suite_run',
|
||||
'FAILED')
|
||||
if test_status.results[0].status:
|
||||
self.logger.info("PASSED: %s", release_name)
|
||||
else:
|
||||
self.logger.info("FAILED: %s", release_name)
|
||||
|
||||
else:
|
||||
self.logger.info(
|
||||
'Release %s not found - SKIPPING',
|
||||
release_name)
|
||||
else:
|
||||
client = self.ctx.obj.get('CLIENT')
|
||||
query = {
|
||||
'tiller_host': self.tiller_host,
|
||||
'tiller_port': self.tiller_port
|
||||
}
|
||||
|
||||
with open(self.filename, 'r') as f:
|
||||
resp = client.get_test_manifest(manifest=f.read(),
|
||||
query=query)
|
||||
for test in resp.get('tests'):
|
||||
self.logger.info('Test State: %s', test)
|
||||
for item in test.get('tests').get(test):
|
||||
self.logger.info(item)
|
||||
|
||||
self.logger.info(resp)
|
||||
|
@ -12,41 +12,96 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from cliff import command as cmd
|
||||
|
||||
import click
|
||||
|
||||
from armada.cli import CliAction
|
||||
from armada.handlers.tiller import Tiller
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@click.group()
|
||||
def tiller():
|
||||
""" Tiller Services actions
|
||||
|
||||
CONF = cfg.CONF
|
||||
"""
|
||||
|
||||
|
||||
def tillerServer(args):
|
||||
DESC = """
|
||||
This command gets tiller information
|
||||
|
||||
tiller = Tiller()
|
||||
The tiller command uses flags to obtain information from tiller services
|
||||
|
||||
if args.status:
|
||||
resp = tiller.tiller_version()
|
||||
LOG.info('Tiller Service: %s', tiller.tiller_status())
|
||||
LOG.info('Tiller Version: %s', getattr(resp.Version, 'sem_ver', False))
|
||||
To obtain armada deployed releases:
|
||||
|
||||
if args.releases:
|
||||
for release in tiller.list_releases():
|
||||
LOG.info("Release: %s ( namespace= %s )", release.name,
|
||||
release.namespace)
|
||||
$ armada tiller --releases
|
||||
|
||||
To obtain tiller service status/information:
|
||||
|
||||
$ armada tiller --status
|
||||
|
||||
"""
|
||||
|
||||
SHORT_DESC = "command gets tiller infromation"
|
||||
|
||||
|
||||
class TillerServerCommand(cmd.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(TillerServerCommand, self).get_parser(prog_name)
|
||||
parser.add_argument('--status', action='store_true',
|
||||
default=False, help='Check Tiller service')
|
||||
parser.add_argument('--releases', action='store_true',
|
||||
default=False, help='List Tiller Releases')
|
||||
return parser
|
||||
@tiller.command(name='tiller', help=DESC, short_help=SHORT_DESC)
|
||||
@click.option('--tiller-host', help="Tiller host ip", default=None)
|
||||
@click.option(
|
||||
'--tiller-port', help="Tiller host port", type=int, default=44134)
|
||||
@click.option('--releases', help="list of deployed releses", is_flag=True)
|
||||
@click.option('--status', help="Status of Armada services", is_flag=True)
|
||||
@click.pass_context
|
||||
def tiller_service(ctx, tiller_host, tiller_port, releases, status):
|
||||
TillerServices(ctx, tiller_host, tiller_port, releases, status).invoke()
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tillerServer(parsed_args)
|
||||
|
||||
class TillerServices(CliAction):
|
||||
|
||||
def __init__(self, ctx, tiller_host, tiller_port, releases, status):
|
||||
super(TillerServices, self).__init__()
|
||||
self.ctx = ctx
|
||||
self.tiller_host = tiller_host
|
||||
self.tiller_port = tiller_port
|
||||
self.releases = releases
|
||||
self.status = status
|
||||
|
||||
def invoke(self):
|
||||
|
||||
tiller = Tiller(
|
||||
tiller_host=self.tiller_host, tiller_port=self.tiller_port)
|
||||
|
||||
if self.status:
|
||||
if not self.ctx.obj.get('api', False):
|
||||
self.logger.info('Tiller Service: %s', tiller.tiller_status())
|
||||
self.logger.info('Tiller Version: %s', tiller.tiller_version())
|
||||
else:
|
||||
client = self.ctx.obj.get('CLIENT')
|
||||
query = {
|
||||
'tiller_host': self.tiller_host,
|
||||
'tiller_port': self.tiller_port
|
||||
}
|
||||
resp = client.get_status(query=query)
|
||||
tiller_status = resp.get('tiller').get('state', False)
|
||||
tiller_version = resp.get('tiller').get('version')
|
||||
|
||||
self.logger.info("Tiller Service: %s", tiller_status)
|
||||
self.logger.info("Tiller Version: %s", tiller_version)
|
||||
|
||||
if self.releases:
|
||||
if not self.ctx.obj.get('api', False):
|
||||
for release in tiller.list_releases():
|
||||
self.logger.info(
|
||||
"Release %s in namespace: %s",
|
||||
release.name, release.namespace)
|
||||
else:
|
||||
client = self.ctx.obj.get('CLIENT')
|
||||
query = {
|
||||
'tiller_host': self.tiller_host,
|
||||
'tiller_port': self.tiller_port
|
||||
}
|
||||
resp = client.get_releases(query=query)
|
||||
for namespace in resp.get('releases'):
|
||||
for release in resp.get('releases').get(namespace):
|
||||
self.logger.info(
|
||||
'Release %s in namespace: %s', release,
|
||||
namespace)
|
||||
|
@ -12,39 +12,68 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from cliff import command as cmd
|
||||
|
||||
import click
|
||||
import yaml
|
||||
|
||||
from armada.utils.lint import validate_armada_documents, validate_armada_object
|
||||
from armada.cli import CliAction
|
||||
from armada.utils.lint import validate_armada_documents
|
||||
from armada.utils.lint import validate_armada_object
|
||||
from armada.handlers.manifest import Manifest
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@click.group()
|
||||
def validate():
|
||||
""" Test Manifest Charts
|
||||
|
||||
CONF = cfg.CONF
|
||||
"""
|
||||
|
||||
|
||||
def validateYaml(args):
|
||||
documents = yaml.safe_load_all(open(args.file).read())
|
||||
manifest_obj = Manifest(documents).get_manifest()
|
||||
obj_check = validate_armada_object(manifest_obj)
|
||||
doc_check = validate_armada_documents(documents)
|
||||
DESC = """
|
||||
This command validates Armada Manifest
|
||||
|
||||
try:
|
||||
if doc_check and obj_check:
|
||||
LOG.info('Successfully validated: %s', args.file)
|
||||
except Exception:
|
||||
raise Exception('Failed to validate: %s', args.file)
|
||||
The validate argument must be a relative path to Armada manifest
|
||||
|
||||
$ armada validate examples/simple.yaml
|
||||
|
||||
"""
|
||||
|
||||
SHORT_DESC = "command validates Armada Manifest"
|
||||
|
||||
|
||||
class ValidateYamlCommand(cmd.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ValidateYamlCommand, self).get_parser(prog_name)
|
||||
parser.add_argument('file', type=str, metavar='FILE',
|
||||
help='Armada yaml file to validate')
|
||||
return parser
|
||||
@validate.command(name='validate', help=DESC, short_help=SHORT_DESC)
|
||||
@click.argument('filename')
|
||||
@click.pass_context
|
||||
def validate_manifest(ctx, filename):
|
||||
ValidateManifest(ctx, filename).invoke()
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
validateYaml(parsed_args)
|
||||
|
||||
class ValidateManifest(CliAction):
|
||||
|
||||
def __init__(self, ctx, filename):
|
||||
super(ValidateManifest, self).__init__()
|
||||
self.ctx = ctx
|
||||
self.filename = filename
|
||||
|
||||
def invoke(self):
|
||||
if not self.ctx.obj.get('api', False):
|
||||
documents = yaml.safe_load_all(open(self.filename).read())
|
||||
manifest_obj = Manifest(documents).get_manifest()
|
||||
obj_check = validate_armada_object(manifest_obj)
|
||||
doc_check = validate_armada_documents(documents)
|
||||
|
||||
try:
|
||||
if doc_check and obj_check:
|
||||
self.logger.info(
|
||||
'Successfully validated: %s', self.filename)
|
||||
except Exception:
|
||||
raise Exception('Failed to validate: %s', self.filename)
|
||||
else:
|
||||
client = self.ctx.obj.get('CLIENT')
|
||||
with open(self.filename, 'r') as f:
|
||||
resp = client.post_validate(f.read())
|
||||
if resp.get('valid', False):
|
||||
self.logger.info(
|
||||
'Successfully validated: %s', self.filename)
|
||||
else:
|
||||
self.logger.error("Failed to validate: %s", self.filename)
|
||||
|
107
armada/common/client.py
Normal file
107
armada/common/client.py
Normal file
@ -0,0 +1,107 @@
|
||||
# Copyright 2017 The Armada Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import yaml
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from armada.exceptions import api_exceptions as err
|
||||
from armada.handlers.armada import Override
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
|
||||
API_VERSION = 'v{}/{}'
|
||||
|
||||
|
||||
class ArmadaClient(object):
|
||||
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
def _set_endpoint(self, version, action):
|
||||
return API_VERSION.format(version, action)
|
||||
|
||||
def get_status(self, query):
|
||||
|
||||
endpoint = self._set_endpoint('1.0', 'status')
|
||||
resp = self.session.get(endpoint, query=query)
|
||||
|
||||
self._check_response(resp)
|
||||
|
||||
return resp.json()
|
||||
|
||||
def get_releases(self, query):
|
||||
|
||||
endpoint = self._set_endpoint('1.0', 'releases')
|
||||
resp = self.session.get(endpoint, query=query)
|
||||
|
||||
self._check_response(resp)
|
||||
|
||||
return resp.json()
|
||||
|
||||
def post_validate(self, manifest=None):
|
||||
|
||||
endpoint = self._set_endpoint('1.0', 'validate')
|
||||
resp = self.session.post(endpoint, body=manifest)
|
||||
|
||||
self._check_response(resp)
|
||||
|
||||
return resp.json()
|
||||
|
||||
def post_apply(self, manifest=None, values=None, set=None, query=None):
|
||||
|
||||
if values or set:
|
||||
document = list(yaml.safe_load_all(manifest))
|
||||
override = Override(
|
||||
document, overrides=set, values=values).update_manifests()
|
||||
manifest = yaml.dump(override)
|
||||
|
||||
endpoint = self._set_endpoint('1.0', 'apply')
|
||||
resp = self.session.post(endpoint, body=manifest, query=query)
|
||||
|
||||
self._check_response(resp)
|
||||
|
||||
return resp.json()
|
||||
|
||||
def get_test_release(self, release=None, query=None):
|
||||
|
||||
endpoint = self._set_endpoint('1.0', 'test/{}'.format(release))
|
||||
resp = self.session.get(endpoint, query=query)
|
||||
|
||||
self._check_response(resp)
|
||||
|
||||
return resp.json()
|
||||
|
||||
def post_test_manifest(self, manifest=None, query=None):
|
||||
|
||||
endpoint = self._set_endpoint('1.0', 'tests')
|
||||
resp = self.session.post(endpoint, body=manifest, query=query)
|
||||
|
||||
self._check_response(resp)
|
||||
|
||||
return resp.json()
|
||||
|
||||
def _check_response(self, resp):
|
||||
if resp.status_code == 401:
|
||||
raise err.ClientUnauthorizedError(
|
||||
"Unauthorized access to %s, include valid token.".format(
|
||||
resp.url))
|
||||
elif resp.status_code == 403:
|
||||
raise err.ClientForbiddenError(
|
||||
"Forbidden access to %s" % resp.url)
|
||||
elif not resp.ok:
|
||||
raise err.ClientError(
|
||||
"Error - received %d: %s" % (resp.status_code, resp.text))
|
@ -20,12 +20,22 @@ armada_policies = [
|
||||
name=base.ARMADA % 'create_endpoints',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
description='install manifest charts',
|
||||
operations=[{'path': '/v1.0/apply/', 'method': 'POST'}]),
|
||||
operations=[{'path': '/api/v1.0/apply/', 'method': 'POST'}]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.ARMADA % 'validate_manifest',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
description='validate installed manifest',
|
||||
operations=[{'path': '/api/v1.0/validate/', 'method': 'POST'}]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.ARMADA % 'test_release',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
description='validate install manifest',
|
||||
operations=[{'path': '/v1.0/validate/', 'method': 'POST'}]),
|
||||
operations=[{'path': '/api/v1.0/test/{release}', 'method': 'GET'}]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.ARMADA % 'test_manifest',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
description='validate install manifest',
|
||||
operations=[{'path': '/api/v1.0/tests/', 'method': 'POST'}]),
|
||||
]
|
||||
|
||||
|
||||
|
@ -20,15 +20,13 @@ tiller_policies = [
|
||||
name=base.TILLER % 'get_status',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
description='Get tiller status',
|
||||
operations=[{'path': '/v1.0/status/',
|
||||
'method': 'GET'}]),
|
||||
operations=[{'path': '/api/v1.0/status/', 'method': 'GET'}]),
|
||||
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.TILLER % 'get_release',
|
||||
check_str=base.RULE_ADMIN_REQUIRED,
|
||||
description='Get tiller release',
|
||||
operations=[{'path': '/v1.0/releases/',
|
||||
'method': 'GET'}]),
|
||||
operations=[{'path': '/api/v1.0/releases/', 'method': 'GET'}]),
|
||||
]
|
||||
|
||||
|
||||
|
96
armada/common/session.py
Normal file
96
armada/common/session.py
Normal file
@ -0,0 +1,96 @@
|
||||
# Copyright 2017 The Armada Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import requests
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class ArmadaSession(object):
|
||||
"""
|
||||
A session to the Armada API maintaining credentials and API options
|
||||
|
||||
:param string host: The armada server hostname or IP
|
||||
:param int port: (optional) The service port appended if specified
|
||||
:param string token: Auth token
|
||||
:param string marker: (optional) external context marker
|
||||
"""
|
||||
|
||||
def __init__(self, host, port=None, scheme='http', token=None,
|
||||
marker=None):
|
||||
|
||||
self._session = requests.Session()
|
||||
self._session.headers.update({
|
||||
'X-Auth-Token': token,
|
||||
'X-Context-Marker': marker
|
||||
})
|
||||
self.host = host
|
||||
self.scheme = scheme
|
||||
|
||||
if port:
|
||||
self.port = port
|
||||
self.base_url = "{}://{}:{}/api/".format(
|
||||
self.scheme, self.host, self.port)
|
||||
else:
|
||||
self.base_url = "{}://{}/api/".format(
|
||||
self.scheme, self.host)
|
||||
|
||||
self.token = token
|
||||
self.marker = marker
|
||||
self.logger = LOG
|
||||
|
||||
# TODO Add keystone authentication to produce a token for this session
|
||||
def get(self, endpoint, query=None):
|
||||
"""
|
||||
Send a GET request to armada.
|
||||
|
||||
:param string endpoint: URL string following hostname and API prefix
|
||||
:param dict query: A dict of k, v pairs to add to the query string
|
||||
|
||||
:return: A requests.Response object
|
||||
"""
|
||||
api_url = '{}{}'.format(self.base_url, endpoint)
|
||||
resp = self._session.get(
|
||||
api_url, params=query, timeout=3600)
|
||||
|
||||
return resp
|
||||
|
||||
def post(self, endpoint, query=None, body=None, data=None):
|
||||
"""
|
||||
Send a POST request to armada. If both body and data are specified,
|
||||
body will will be used.
|
||||
|
||||
:param string endpoint: URL string following hostname and API prefix
|
||||
:param dict query: dict of k, v parameters to add to the query string
|
||||
:param string body: string to use as the request body.
|
||||
:param data: Something json.dumps(s) can serialize.
|
||||
:return: A requests.Response object
|
||||
"""
|
||||
api_url = '{}{}'.format(self.base_url, endpoint)
|
||||
|
||||
self.logger.debug("Sending POST with armada_client session")
|
||||
if body is not None:
|
||||
self.logger.debug("Sending POST with explicit body: \n%s" % body)
|
||||
resp = self._session.post(
|
||||
api_url, params=query, data=body, timeout=3600)
|
||||
else:
|
||||
self.logger.debug("Sending POST with JSON body: \n%s" % str(data))
|
||||
resp = self._session.post(
|
||||
api_url, params=query, json=data, timeout=3600)
|
||||
|
||||
return resp
|
@ -17,12 +17,13 @@ import os
|
||||
from oslo_config import cfg
|
||||
|
||||
from armada.conf import default
|
||||
from armada import const
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
# Load config file if exists
|
||||
if (os.path.exists('etc/armada/armada.conf')):
|
||||
CONF(['--config-file', 'etc/armada/armada.conf'])
|
||||
if (os.path.exists(const.CONFIG_PATH)):
|
||||
CONF(['--config-file', const.CONFIG_PATH])
|
||||
|
||||
|
||||
def set_app_default_configs():
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from keystoneauth1 import loading
|
||||
|
||||
from armada.conf import utils
|
||||
|
||||
default_options = [
|
||||
@ -71,7 +73,12 @@ The Keystone project domain name used for authentication.
|
||||
|
||||
def register_opts(conf):
|
||||
conf.register_opts(default_options)
|
||||
conf.register_opts(
|
||||
loading.get_auth_plugin_conf_options('password'),
|
||||
group='keystone_authtoken')
|
||||
|
||||
|
||||
def list_opts():
|
||||
return {'DEFAULT': default_options}
|
||||
return {
|
||||
'DEFAULT': default_options,
|
||||
'keystone_authtoken': loading.get_auth_plugin_conf_options('password')}
|
||||
|
@ -28,3 +28,6 @@ KEYWORD_CHART = 'chart'
|
||||
# Statuses
|
||||
STATUS_DEPLOYED = 'DEPLOYED'
|
||||
STATUS_FAILED = 'FAILED'
|
||||
|
||||
# Configuration File
|
||||
CONFIG_PATH = '/etc/armada/armada.conf'
|
||||
|
@ -31,3 +31,21 @@ class ApiJsonException(ApiException):
|
||||
'''Exception that occurs during chart cleanup.'''
|
||||
|
||||
message = 'There was an error listing the helm chart releases.'
|
||||
|
||||
|
||||
class ClientUnauthorizedError(ApiException):
|
||||
'''Exception that occurs during chart cleanup.'''
|
||||
|
||||
message = 'There was an error listing the helm chart releases.'
|
||||
|
||||
|
||||
class ClientForbiddenError(ApiException):
|
||||
'''Exception that occurs during chart cleanup.'''
|
||||
|
||||
message = 'There was an error listing the helm chart releases.'
|
||||
|
||||
|
||||
class ClientError(ApiException):
|
||||
'''Exception that occurs during chart cleanup.'''
|
||||
|
||||
message = 'There was an error listing the helm chart releases.'
|
||||
|
@ -53,8 +53,7 @@ class Armada(object):
|
||||
timeout=DEFAULT_TIMEOUT,
|
||||
tiller_host=None,
|
||||
tiller_port=44134,
|
||||
values=None,
|
||||
debug=False):
|
||||
values=None):
|
||||
'''
|
||||
Initialize the Armada Engine and establish
|
||||
a connection to Tiller
|
||||
@ -69,14 +68,8 @@ class Armada(object):
|
||||
self.timeout = timeout
|
||||
self.tiller = Tiller(tiller_host=tiller_host, tiller_port=tiller_port)
|
||||
self.values = values
|
||||
self.documents = list(yaml.safe_load_all(file))
|
||||
self.documents = file
|
||||
self.config = None
|
||||
self.debug = debug
|
||||
|
||||
# Set debug value
|
||||
# Define a default handler at INFO logging level
|
||||
if self.debug:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
def get_armada_manifest(self):
|
||||
return Manifest(self.documents).get_manifest()
|
||||
@ -193,7 +186,7 @@ class Armada(object):
|
||||
Syncronize Helm with the Armada Config(s)
|
||||
'''
|
||||
|
||||
msg = {'installed': [], 'upgraded': [], 'diff': []}
|
||||
msg = {'install': [], 'upgrade': [], 'diff': []}
|
||||
|
||||
# TODO: (gardlt) we need to break up this func into
|
||||
# a more cleaner format
|
||||
@ -314,7 +307,7 @@ class Armada(object):
|
||||
timeout=wait_values.get('timeout', DEFAULT_TIMEOUT)
|
||||
)
|
||||
|
||||
msg['upgraded'].append(prefix_chart)
|
||||
msg['upgrade'].append(prefix_chart)
|
||||
|
||||
# process install
|
||||
else:
|
||||
@ -338,7 +331,7 @@ class Armada(object):
|
||||
namespace=chart.namespace,
|
||||
timeout=wait_values.get('timeout', 3600))
|
||||
|
||||
msg['installed'].append(prefix_chart)
|
||||
msg['install'].append(prefix_chart)
|
||||
|
||||
LOG.debug("Cleaning up chart source in %s",
|
||||
chartbuilder.source_directory)
|
||||
|
@ -15,7 +15,9 @@
|
||||
import re
|
||||
import time
|
||||
|
||||
from kubernetes import client, config, watch
|
||||
from kubernetes import client
|
||||
from kubernetes import config
|
||||
from kubernetes import watch
|
||||
from kubernetes.client.rest import ApiException
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
@ -37,7 +39,10 @@ class K8s(object):
|
||||
'''
|
||||
Initialize connection to Kubernetes
|
||||
'''
|
||||
config.load_kube_config()
|
||||
try:
|
||||
config.load_incluster_config()
|
||||
except:
|
||||
config.load_kube_config()
|
||||
|
||||
self.client = client.CoreV1Api()
|
||||
self.batch_api = client.BatchV1Api()
|
||||
|
@ -309,9 +309,6 @@ class Tiller(object):
|
||||
|
||||
LOG.info("Wait: %s, Timeout: %s", wait, timeout)
|
||||
|
||||
if timeout > self.timeout:
|
||||
self.timeout = timeout
|
||||
|
||||
if values is None:
|
||||
values = Config(raw='')
|
||||
else:
|
||||
@ -349,8 +346,9 @@ class Tiller(object):
|
||||
try:
|
||||
|
||||
stub = ReleaseServiceStub(self.channel)
|
||||
release_request = TestReleaseRequest(name=release, timeout=timeout,
|
||||
cleanup=cleanup)
|
||||
|
||||
release_request = TestReleaseRequest(
|
||||
name=release, timeout=timeout, cleanup=cleanup)
|
||||
|
||||
content = self.get_release_content(release)
|
||||
|
||||
@ -417,9 +415,11 @@ class Tiller(object):
|
||||
stub = ReleaseServiceStub(self.channel)
|
||||
release_request = GetVersionRequest()
|
||||
|
||||
return stub.GetVersion(
|
||||
tiller_version = stub.GetVersion(
|
||||
release_request, self.timeout, metadata=self.metadata)
|
||||
|
||||
return getattr(tiller_version.Version, 'sem_ver', None)
|
||||
|
||||
except Exception:
|
||||
raise ex.TillerVersionException()
|
||||
|
||||
|
@ -12,39 +12,81 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import click
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from cliff import app
|
||||
from cliff import commandmanager as cm
|
||||
|
||||
import armada
|
||||
from armada.cli.apply import apply_create
|
||||
from armada.cli.test import test_charts
|
||||
from armada.cli.tiller import tiller_service
|
||||
from armada.cli.validate import validate_manifest
|
||||
from armada.common.client import ArmadaClient
|
||||
from armada.common.session import ArmadaSession
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class ArmadaApp(app.App):
|
||||
def __init__(self, **kwargs):
|
||||
super(ArmadaApp, self).__init__(
|
||||
description='Armada - Upgrade and deploy your charts',
|
||||
version=armada.__version__,
|
||||
command_manager=cm.CommandManager('armada'),
|
||||
**kwargs)
|
||||
@click.group()
|
||||
@click.option(
|
||||
'--debug/--no-debug', help='Enable or disable debugging', default=False)
|
||||
@click.option(
|
||||
'--api/--no-api', help='Execute service endpoints. (requires url option)',
|
||||
default=False)
|
||||
@click.option(
|
||||
'--url', help='Armada Service Endpoint', envvar='HOST', default=None)
|
||||
@click.option(
|
||||
'--token', help='Keystone Service Token', envvar='TOKEN', default=None)
|
||||
@click.pass_context
|
||||
def main(ctx, debug, api, url, token):
|
||||
"""
|
||||
Multi Helm Chart Deployment Manager
|
||||
|
||||
def build_option_parser(self, description, version, argparse_kwargs=None):
|
||||
parser = super(ArmadaApp, self).build_option_parser(
|
||||
description, version, argparse_kwargs)
|
||||
return parser
|
||||
Common actions from this point include:
|
||||
|
||||
def configure_logging(self):
|
||||
super(ArmadaApp, self).configure_logging()
|
||||
log.register_options(CONF)
|
||||
log.set_defaults(default_log_levels=CONF.default_log_levels)
|
||||
log.setup(CONF, 'armada')
|
||||
\b
|
||||
$ armada apply
|
||||
$ armada test
|
||||
$ armada tiller
|
||||
$ armada validate
|
||||
|
||||
Environment:
|
||||
|
||||
\b
|
||||
$TOKEN set auth token
|
||||
$HOST set armada service host endpoint
|
||||
|
||||
This tool will communicate with deployed Tiller in your Kubernetes cluster.
|
||||
"""
|
||||
|
||||
if not ctx.obj:
|
||||
ctx.obj = {}
|
||||
|
||||
if api:
|
||||
if not url or not token:
|
||||
raise click.ClickException(
|
||||
'When api option is enable user needs to pass url')
|
||||
else:
|
||||
ctx.obj['api'] = api
|
||||
parsed_url = urlparse(url)
|
||||
ctx.obj['CLIENT'] = ArmadaClient(
|
||||
ArmadaSession(
|
||||
host=parsed_url.netloc,
|
||||
scheme=parsed_url.scheme,
|
||||
token=token)
|
||||
)
|
||||
|
||||
log.register_options(CONF)
|
||||
|
||||
if debug:
|
||||
CONF.debug = debug
|
||||
|
||||
log.set_defaults(default_log_levels=CONF.default_log_levels)
|
||||
log.setup(CONF, 'armada')
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv[1:]
|
||||
return ArmadaApp().run(argv)
|
||||
main.add_command(apply_create)
|
||||
main.add_command(test_charts)
|
||||
main.add_command(tiller_service)
|
||||
main.add_command(validate_manifest)
|
||||
|
@ -38,7 +38,7 @@ class TestAPI(APITestCase):
|
||||
@mock.patch('armada.api.armada_controller.Handler')
|
||||
def test_armada_apply(self, mock_armada):
|
||||
'''
|
||||
Test /armada/apply endpoint
|
||||
Test /api/v1.0/apply endpoint
|
||||
'''
|
||||
mock_armada.sync.return_value = None
|
||||
|
||||
@ -54,7 +54,7 @@ class TestAPI(APITestCase):
|
||||
|
||||
doc = {u'message': u'Success'}
|
||||
|
||||
result = self.simulate_post(path='/armada/apply', body=body)
|
||||
result = self.simulate_post(path='/api/v1.0/apply', body=body)
|
||||
self.assertEqual(result.json, doc)
|
||||
|
||||
@unittest.skip('Test does not handle auth/policy correctly')
|
||||
@ -62,6 +62,7 @@ class TestAPI(APITestCase):
|
||||
def test_tiller_status(self, mock_tiller):
|
||||
'''
|
||||
Test /status endpoint
|
||||
Test /api/v1.0/status endpoint
|
||||
'''
|
||||
|
||||
# Mock tiller status value
|
||||
@ -70,11 +71,13 @@ class TestAPI(APITestCase):
|
||||
# FIXME(lamt) This variable is unused. Uncomment when it is.
|
||||
# doc = {u'message': u'Tiller Server is Active'}
|
||||
|
||||
result = self.simulate_get('/v1.0/status')
|
||||
result = self.simulate_get('/api/v1.0/status')
|
||||
|
||||
# TODO(lamt) This should be HTTP_401 if no auth is happening, but auth
|
||||
# is not implemented currently, so it falls back to a policy check
|
||||
# failure, thus a 403. Change this once it is completed
|
||||
|
||||
# Fails due to invalid access
|
||||
self.assertEqual(falcon.HTTP_403, result.status)
|
||||
|
||||
# FIXME(lamt) Need authentication - mock, fixture
|
||||
@ -84,7 +87,7 @@ class TestAPI(APITestCase):
|
||||
@mock.patch('armada.api.tiller_controller.Tiller')
|
||||
def test_tiller_releases(self, mock_tiller):
|
||||
'''
|
||||
Test /tiller/releases endpoint
|
||||
Test /api/v1.0/releases endpoint
|
||||
'''
|
||||
|
||||
# Mock tiller status value
|
||||
@ -93,7 +96,7 @@ class TestAPI(APITestCase):
|
||||
# FIXME(lamt) This variable is unused. Uncomment when it is.
|
||||
# doc = {u'releases': {}}
|
||||
|
||||
result = self.simulate_get('/v1.0/releases')
|
||||
result = self.simulate_get('/api/v1.0/releases')
|
||||
|
||||
# TODO(lamt) This should be HTTP_401 if no auth is happening, but auth
|
||||
# is not implemented currently, so it falls back to a policy check
|
||||
|
@ -7,15 +7,42 @@ Commands
|
||||
|
||||
.. code:: bash
|
||||
|
||||
Usage: armada apply FILE
|
||||
Usage: armada apply [OPTIONS] FILENAME
|
||||
|
||||
This command install and updates charts defined in armada manifest
|
||||
|
||||
The apply argument must be relative path to Armada Manifest. Executing
|
||||
apply commnad once will install all charts defined in manifest. Re-
|
||||
executing apply commnad will execute upgrade.
|
||||
|
||||
To see how to create an Armada manifest:
|
||||
http://armada-helm.readthedocs.io/en/latest/operations/
|
||||
|
||||
To obtain install/upgrade charts:
|
||||
|
||||
$ armada apply examples/simple.yaml
|
||||
|
||||
To obtain override manifest:
|
||||
|
||||
$ armada apply examples/simple.yaml --set manifest:simple-armada:relase_name="wordpress"
|
||||
|
||||
or
|
||||
|
||||
$ armada apply examples/simple.yaml --values examples/simple-ovr-values.yaml
|
||||
|
||||
Options:
|
||||
|
||||
[-h] [--dry-run] [--debug-logging] [--disable-update-pre]
|
||||
[--disable-update-post] [--enable-chart-cleanup] [--wait]
|
||||
[--timeout TIMEOUT]
|
||||
|
||||
--api Contacts service endpoint
|
||||
--disable-update-post run charts without install
|
||||
--disable-update-pre run charts without install
|
||||
--dry-run run charts without install
|
||||
--enable-chart-cleanup Clean up Unmanaged Charts
|
||||
--set TEXT
|
||||
--tiller-host TEXT Tiller host ip
|
||||
--tiller-port INTEGER Tiller host port
|
||||
--timeout INTEGER specifies time to wait for charts
|
||||
-f, --values TEXT
|
||||
--wait wait until all charts deployed
|
||||
--help Show this message and exit.
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
@ -7,11 +7,28 @@ Commands
|
||||
|
||||
.. code:: bash
|
||||
|
||||
Usage: armada test
|
||||
Usage: armada test [OPTIONS]
|
||||
|
||||
This command test deployed charts
|
||||
|
||||
The tiller command uses flags to obtain information from tiller services.
|
||||
The test command will run the release chart tests either via a
|
||||
manifest or by targeting a relase.
|
||||
|
||||
To obtain armada deployed releases:
|
||||
|
||||
$ armada test --file examples/simple.yaml
|
||||
|
||||
To test release:
|
||||
|
||||
$ armada test --release blog-1
|
||||
|
||||
Options:
|
||||
|
||||
[-h] [--release RELEASE] [--file FILE]
|
||||
--file TEXT armada manifest
|
||||
--release TEXT helm release
|
||||
--tiller-host TEXT Tiller Host IP
|
||||
--tiller-port INTEGER Tiller host Port
|
||||
--help Show this message and exit.
|
||||
|
||||
|
||||
Synopsis
|
||||
|
@ -7,12 +7,26 @@ Commands
|
||||
|
||||
.. code:: bash
|
||||
|
||||
Usage: armada tiller
|
||||
Usage: armada tiller [OPTIONS]
|
||||
|
||||
This command gets tiller information
|
||||
|
||||
The tiller command uses flags to obtain information from tiller services
|
||||
|
||||
To obtain armada deployed releases:
|
||||
|
||||
$ armada tiller --releases
|
||||
|
||||
To obtain tiller service status/information:
|
||||
|
||||
$ armada tiller --status
|
||||
|
||||
Options:
|
||||
|
||||
[-h] [--status] [--releases]
|
||||
|
||||
--tiller-host TEXT Tiller host ip
|
||||
--tiller-port INTEGER Tiller host port
|
||||
--releases list of deployed releases
|
||||
--status Status of Armada services
|
||||
--help Show this message and exit.
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
@ -7,11 +7,16 @@ Commands
|
||||
|
||||
.. code:: bash
|
||||
|
||||
Usage: armada validate FILE
|
||||
Usage: armada validate [OPTIONS] FILENAME
|
||||
|
||||
This command validates Armada Manifest
|
||||
|
||||
The validate argument must be a relative path to Armada manifest
|
||||
|
||||
$ armada validate examples/simple.yaml
|
||||
|
||||
Options:
|
||||
|
||||
[-h]
|
||||
--help Show this message and exit.
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
@ -13,8 +13,7 @@ To use the docker containter to develop:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone http://github.com/att-comdev/armada.git
|
||||
cd armada
|
||||
git clone http://github.com/att-comdev/armada.git && cd armada
|
||||
|
||||
pip install tox
|
||||
|
||||
@ -23,7 +22,7 @@ To use the docker containter to develop:
|
||||
|
||||
docker build . -t armada/latest
|
||||
|
||||
docker run -d --name armada -v ~/.kube/config:/armada/.kube/config -v $(pwd)/etc:/armada/etc armada:local
|
||||
docker run -d --name armada -v ~/.kube/:/armada/.kube/ -v $(pwd)/etc:/etc armada:local
|
||||
|
||||
.. note::
|
||||
|
||||
@ -45,7 +44,8 @@ From the directory of the forked repository:
|
||||
|
||||
|
||||
git clone http://github.com/att-comdev/armada.git && cd armada
|
||||
virtualenv venv
|
||||
|
||||
virtualenv -p python3 venv
|
||||
|
||||
pip install -r requirements.txt -r test-requirements.txt
|
||||
|
||||
@ -53,6 +53,7 @@ From the directory of the forked repository:
|
||||
|
||||
# Testing your armada code
|
||||
# The tox command will execute lint, bandit, cover
|
||||
pip install tox
|
||||
tox
|
||||
|
||||
# For targeted test
|
||||
@ -60,7 +61,6 @@ From the directory of the forked repository:
|
||||
tox -e bandit
|
||||
tox -e cover
|
||||
|
||||
|
||||
# policy and config are used in order to use and configure Armada API
|
||||
tox -e genconfig
|
||||
tox -e genpolicy
|
||||
|
@ -1,87 +1,532 @@
|
||||
Armada RESTful API
|
||||
===================
|
||||
Armada Restful API v1.0
|
||||
=======================
|
||||
|
||||
Armada Endpoints
|
||||
Description
|
||||
~~~~~~~~~~~
|
||||
|
||||
The Armada API provides the services similar to the cli via Restful endpoints
|
||||
|
||||
|
||||
Base URL
|
||||
~~~~~~~~
|
||||
|
||||
https://armada.localhost/api/v1.0/
|
||||
|
||||
DEFAULT
|
||||
~~~~~~~
|
||||
|
||||
GET ``/releases``
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
Endpoint: POST /armada/apply
|
||||
Summary
|
||||
+++++++
|
||||
|
||||
:string file The yaml file to apply
|
||||
:>json boolean debug Enable debug logging
|
||||
:>json boolean disable_update_pre
|
||||
:>json boolean disable_update_post
|
||||
:>json boolean enable_chart_cleanup
|
||||
:>json boolean skip_pre_flight
|
||||
:>json object values Override manifest values
|
||||
:>json boolean dry_run
|
||||
:>json boolean wait
|
||||
:>json float timeout
|
||||
Get tiller releases
|
||||
|
||||
|
||||
::
|
||||
|
||||
Request:
|
||||
Request
|
||||
+++++++
|
||||
|
||||
|
||||
Responses
|
||||
+++++++++
|
||||
|
||||
**200**
|
||||
^^^^^^^
|
||||
|
||||
obtain all running releases
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"file": "examples/openstack-helm.yaml",
|
||||
"options": {
|
||||
"debug": true,
|
||||
"disable_update_pre": false,
|
||||
"disable_update_post": false,
|
||||
"enable_chart_cleanup": false,
|
||||
"skip_pre_flight": false,
|
||||
"dry_run": false,
|
||||
"wait": false,
|
||||
"timeout": false
|
||||
"message": {
|
||||
"namespace": [
|
||||
"armada-release",
|
||||
"armada-release"
|
||||
],
|
||||
"default": [
|
||||
"armada-release",
|
||||
"armada-release"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
::
|
||||
**403**
|
||||
^^^^^^^
|
||||
|
||||
Results:
|
||||
Unable to Authorize or Permission
|
||||
|
||||
|
||||
**405**
|
||||
^^^^^^^
|
||||
|
||||
Failed to perform action
|
||||
|
||||
GET ``/status``
|
||||
---------------
|
||||
|
||||
|
||||
Summary
|
||||
+++++++
|
||||
|
||||
Get armada running state
|
||||
|
||||
|
||||
Request
|
||||
+++++++
|
||||
|
||||
|
||||
Responses
|
||||
+++++++++
|
||||
|
||||
**200**
|
||||
^^^^^^^
|
||||
|
||||
obtain armada status
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"message": "success"
|
||||
}
|
||||
|
||||
Tiller Endpoints
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
Endpoint: GET /tiller/releases
|
||||
|
||||
Description: Retrieves tiller releases.
|
||||
|
||||
|
||||
::
|
||||
|
||||
Results:
|
||||
|
||||
{
|
||||
"releases": {
|
||||
"armada-memcached": "openstack",
|
||||
"armada-etcd": "openstack",
|
||||
"armada-keystone": "openstack",
|
||||
"armada-rabbitmq": "openstack",
|
||||
"armada-horizon": "openstack"
|
||||
"message": {
|
||||
"tiller": {
|
||||
"state": True,
|
||||
"version": "v2.5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
**403**
|
||||
^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
Endpoint: GET /tiller/status
|
||||
|
||||
Retrieves the status of the Tiller server.
|
||||
Unable to Authorize or Permission
|
||||
|
||||
|
||||
::
|
||||
**405**
|
||||
^^^^^^^
|
||||
|
||||
Results:
|
||||
Failed to perform action
|
||||
|
||||
|
||||
GET ``/validate``
|
||||
-----------------
|
||||
|
||||
|
||||
Summary
|
||||
+++++++
|
||||
|
||||
Get tiller releases
|
||||
|
||||
|
||||
Request
|
||||
+++++++
|
||||
|
||||
|
||||
Responses
|
||||
+++++++++
|
||||
|
||||
**200**
|
||||
^^^^^^^
|
||||
|
||||
obtain all running releases
|
||||
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"message": Tiller Server is Active
|
||||
"valid": true
|
||||
}
|
||||
|
||||
**403**
|
||||
^^^^^^^
|
||||
|
||||
Unable to Authorize or Permission
|
||||
|
||||
|
||||
**405**
|
||||
^^^^^^^
|
||||
|
||||
Failed to perform action
|
||||
|
||||
|
||||
POST ``/apply``
|
||||
---------------
|
||||
|
||||
|
||||
Summary
|
||||
+++++++
|
||||
|
||||
Install/Update Armada Manifest
|
||||
|
||||
Request
|
||||
+++++++
|
||||
|
||||
Body
|
||||
^^^^
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
disable-update-post | boolean | | | |
|
||||
disable-update-pre | boolean | | | |
|
||||
dry-run | boolean | | | |
|
||||
enable-chart-cleanup | boolean | | | |
|
||||
tiller-host | string | | | |
|
||||
tiller-port | int | | | |
|
||||
timeout | int | | | |
|
||||
wait | boolean | | | |
|
||||
|
||||
|
||||
**Armada schema:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"api": true,
|
||||
"armada": {}
|
||||
}
|
||||
|
||||
Responses
|
||||
+++++++++
|
||||
|
||||
**200**
|
||||
^^^^^^^
|
||||
|
||||
Succesfull installation/update of manifest
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"message": {
|
||||
"installed": [
|
||||
"armada-release",
|
||||
"armada-release"
|
||||
],
|
||||
"updated": [
|
||||
"armada-release",
|
||||
"armada-release"
|
||||
],
|
||||
"diff": [
|
||||
"values": "value diff",
|
||||
"values": "value diff 2"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
**403**
|
||||
^^^^^^^
|
||||
|
||||
Unable to Authorize or Permission
|
||||
|
||||
|
||||
**405**
|
||||
^^^^^^^
|
||||
|
||||
Failed to perform action
|
||||
|
||||
|
||||
POST ``/test/{release}``
|
||||
------------------------
|
||||
|
||||
|
||||
Summary
|
||||
+++++++
|
||||
|
||||
Test release name
|
||||
|
||||
|
||||
Parameters
|
||||
++++++++++
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Located in", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 15, 10, 10, 10, 20, 30
|
||||
|
||||
release | path | Yes | string | | | name of the release to test
|
||||
|
||||
Request
|
||||
+++++++
|
||||
|
||||
|
||||
Responses
|
||||
+++++++++
|
||||
|
||||
**200**
|
||||
^^^^^^^
|
||||
|
||||
Succesfully Test release response
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"message": {
|
||||
"message": "armada-release",
|
||||
"result": "No test found."
|
||||
}
|
||||
}
|
||||
|
||||
**403**
|
||||
^^^^^^^
|
||||
|
||||
Unable to Authorize or Permission
|
||||
|
||||
|
||||
**405**
|
||||
^^^^^^^
|
||||
|
||||
Failed to perform action
|
||||
|
||||
POST ``/tests``
|
||||
---------------
|
||||
|
||||
|
||||
Summary
|
||||
+++++++
|
||||
|
||||
Test manifest releases
|
||||
|
||||
Request
|
||||
+++++++
|
||||
|
||||
Body
|
||||
^^^^
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
armada | Yes | | | |
|
||||
|
||||
**Armada schema:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"armada": {}
|
||||
}
|
||||
|
||||
Responses
|
||||
+++++++++
|
||||
|
||||
**200**
|
||||
^^^^^^^
|
||||
|
||||
Succesfully Test of manifest
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"message": {
|
||||
"failed": [
|
||||
"armada-release",
|
||||
"armada-release"
|
||||
],
|
||||
"passed": [
|
||||
"armada-release",
|
||||
"armada-release"
|
||||
],
|
||||
"skipped": [
|
||||
"armada-release",
|
||||
"armada-release"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
**403**
|
||||
^^^^^^^
|
||||
|
||||
Unable to Authorize or Permission
|
||||
|
||||
|
||||
**405**
|
||||
^^^^^^^
|
||||
|
||||
Failed to perform action
|
||||
|
||||
Data Structures
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Armada Request Model Structure
|
||||
------------------------------
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
disable-update-post | boolean | | | |
|
||||
disable-update-pre | boolean | | | |
|
||||
dry-run | boolean | | | |
|
||||
enable-chart-cleanup | boolean | | | |
|
||||
tiller-host | string | | | |
|
||||
tiller-port | int | | | |
|
||||
timeout | int | | | |
|
||||
wait | boolean | | | |
|
||||
|
||||
**Armada schema:**
|
||||
|
||||
Armada Response Model Structure
|
||||
-------------------------------
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
message | No | | | |
|
||||
|
||||
**Message schema:**
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
installed | No | array of string | | |
|
||||
updated | No | array of string | | |
|
||||
values | No | array of string | | |
|
||||
|
||||
|
||||
Releases Response Model Structure
|
||||
---------------------------------
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
message | No | | | |
|
||||
|
||||
**Message schema:**
|
||||
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
namespace | No | array of string | | |
|
||||
|
||||
Status Response Model Structure
|
||||
-------------------------------
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
message | No | | | |
|
||||
|
||||
|
||||
|
||||
**Message schema:**
|
||||
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
tiller | No | | | |
|
||||
|
||||
|
||||
|
||||
**Tiller schema:**
|
||||
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
state | No | string | | |
|
||||
version | No | string | | |
|
||||
|
||||
|
||||
|
||||
Test Response Model Structure
|
||||
-----------------------------
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
message | No | | | |
|
||||
|
||||
**Message schema:**
|
||||
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
message | No | string | | |
|
||||
result | No | string | | |
|
||||
|
||||
Tests Request Model Structure
|
||||
-----------------------------
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
armada | Yes | | | |
|
||||
|
||||
|
||||
|
||||
**Armada schema:**
|
||||
|
||||
|
||||
Tests Response Model Structure
|
||||
------------------------------
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
message | No | | | |
|
||||
|
||||
|
||||
**Message schema:**
|
||||
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
failed | No | array of string | | |
|
||||
passed | No | array of string | | |
|
||||
skipped | No | array of string | | |
|
||||
|
||||
|
||||
Validate Response Model Structure
|
||||
---------------------------------
|
||||
|
||||
.. csv-table::
|
||||
:delim: |
|
||||
:header: "Name", "Required", "Type", "Format", "Properties", "Description"
|
||||
:widths: 20, 10, 15, 15, 30, 25
|
||||
|
||||
valid | No | boolean | | |
|
||||
|
@ -9,6 +9,7 @@ file can be generated via tox
|
||||
.. code-block:: bash
|
||||
|
||||
$ tox -e genconfig
|
||||
$ tox -e genpolicy
|
||||
|
||||
Customize your configuration based on the information below
|
||||
|
||||
@ -20,9 +21,9 @@ tokens
|
||||
|
||||
.. note::
|
||||
|
||||
If you do not have a keystone already deploy, then armada can deploy a keystone service.
|
||||
If you do not have a keystone already deploy, then armada can deploy a keystone services:
|
||||
|
||||
armada apply keystone-manifest.yaml
|
||||
$ armada apply keystone-manifest.yaml
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@ -40,13 +41,13 @@ The service account must then be included in the armada.conf
|
||||
.. code-block:: ini
|
||||
|
||||
[keystone_authtoken]
|
||||
auth_type = password
|
||||
auth_uri = https://<keystone-api>:5000/
|
||||
auth_url = https://<keystone-api>:35357/
|
||||
auth_version = 3
|
||||
delay_auth_decision = true
|
||||
auth_type = password
|
||||
auth_url = https://<keystone-api>:35357/
|
||||
project_name = service
|
||||
project_domain_name = ucp
|
||||
user_name = armada
|
||||
user_domain_name = ucp
|
||||
password = armada
|
||||
project_domain_name = ucp
|
||||
project_name = service
|
||||
user_domain_name = ucp
|
||||
user_name = armada
|
||||
|
@ -6,11 +6,7 @@ PORT="8000"
|
||||
set -e
|
||||
|
||||
if [ "$1" = 'server' ]; then
|
||||
exec uwsgi --http 0.0.0.0:${PORT} --paste config:$(pwd)/etc/armada/api-paste.ini --enable-threads -L --pyargv " --config-file $(pwd)/etc/armada/armada.conf"
|
||||
fi
|
||||
|
||||
if [ "$1" = 'tiller' ] || [ "$1" = 'apply' ]; then
|
||||
exec uwsgi --http :${PORT} --http-timeout 3600 --paste config:/etc/armada/api-paste.ini --enable-threads -L --pyargv "--config-file /etc/armada/armada.conf"
|
||||
else
|
||||
exec $CMD "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
441
etc/armada/armada.conf.sample
Normal file
441
etc/armada/armada.conf.sample
Normal file
@ -0,0 +1,441 @@
|
||||
[DEFAULT]
|
||||
|
||||
#
|
||||
# From armada.conf
|
||||
#
|
||||
|
||||
# IDs of approved API access roles. (list value)
|
||||
#armada_apply_roles = admin
|
||||
|
||||
# The default Keystone authentication url. (string value)
|
||||
#auth_url = http://0.0.0.0/v3
|
||||
|
||||
# Path to Kubernetes configurations. (string value)
|
||||
#kubernetes_config_path = /home/user/.kube/
|
||||
|
||||
# Enables or disables Keystone authentication middleware. (boolean value)
|
||||
#middleware = true
|
||||
|
||||
# The Keystone project domain name used for authentication. (string value)
|
||||
#project_domain_name = default
|
||||
|
||||
# The Keystone project name used for authentication. (string value)
|
||||
#project_name = admin
|
||||
|
||||
# Path to SSH private key. (string value)
|
||||
#ssh_key_path = /home/user/.ssh/
|
||||
|
||||
# IDs of approved API access roles. (list value)
|
||||
#tiller_release_roles = admin
|
||||
|
||||
# IDs of approved API access roles. (list value)
|
||||
#tiller_status_roles = admin
|
||||
|
||||
#
|
||||
# From oslo.log
|
||||
#
|
||||
|
||||
# If set to true, the logging level will be set to DEBUG instead of the default
|
||||
# INFO level. (boolean value)
|
||||
# Note: This option can be changed without restarting.
|
||||
#debug = false
|
||||
|
||||
# The name of a logging configuration file. This file is appended to any
|
||||
# existing logging configuration files. For details about logging configuration
|
||||
# files, see the Python logging module documentation. Note that when logging
|
||||
# configuration files are used then all logging configuration is set in the
|
||||
# configuration file and other logging configuration options are ignored (for
|
||||
# example, logging_context_format_string). (string value)
|
||||
# Note: This option can be changed without restarting.
|
||||
# Deprecated group/name - [DEFAULT]/log_config
|
||||
#log_config_append = <None>
|
||||
|
||||
# Defines the format string for %%(asctime)s in log records. Default:
|
||||
# %(default)s . This option is ignored if log_config_append is set. (string
|
||||
# value)
|
||||
#log_date_format = %Y-%m-%d %H:%M:%S
|
||||
|
||||
# (Optional) Name of log file to send logging output to. If no default is set,
|
||||
# logging will go to stderr as defined by use_stderr. This option is ignored if
|
||||
# log_config_append is set. (string value)
|
||||
# Deprecated group/name - [DEFAULT]/logfile
|
||||
#log_file = <None>
|
||||
|
||||
# (Optional) The base directory used for relative log_file paths. This option
|
||||
# is ignored if log_config_append is set. (string value)
|
||||
# Deprecated group/name - [DEFAULT]/logdir
|
||||
#log_dir = <None>
|
||||
|
||||
# Uses logging handler designed to watch file system. When log file is moved or
|
||||
# removed this handler will open a new log file with specified path
|
||||
# instantaneously. It makes sense only if log_file option is specified and
|
||||
# Linux platform is used. This option is ignored if log_config_append is set.
|
||||
# (boolean value)
|
||||
#watch_log_file = false
|
||||
|
||||
# Use syslog for logging. Existing syslog format is DEPRECATED and will be
|
||||
# changed later to honor RFC5424. This option is ignored if log_config_append
|
||||
# is set. (boolean value)
|
||||
#use_syslog = false
|
||||
|
||||
# Enable journald for logging. If running in a systemd environment you may wish
|
||||
# to enable journal support. Doing so will use the journal native protocol
|
||||
# which includes structured metadata in addition to log messages.This option is
|
||||
# ignored if log_config_append is set. (boolean value)
|
||||
#use_journal = false
|
||||
|
||||
# Syslog facility to receive log lines. This option is ignored if
|
||||
# log_config_append is set. (string value)
|
||||
#syslog_log_facility = LOG_USER
|
||||
|
||||
# Log output to standard error. This option is ignored if log_config_append is
|
||||
# set. (boolean value)
|
||||
#use_stderr = false
|
||||
|
||||
# Format string to use for log messages with context. (string value)
|
||||
#logging_context_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s
|
||||
|
||||
# Format string to use for log messages when context is undefined. (string
|
||||
# value)
|
||||
#logging_default_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
|
||||
|
||||
# Additional data to append to log message when logging level for the message
|
||||
# is DEBUG. (string value)
|
||||
#logging_debug_format_suffix = %(funcName)s %(pathname)s:%(lineno)d
|
||||
|
||||
# Prefix each line of exception output with this format. (string value)
|
||||
#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s
|
||||
|
||||
# Defines the format string for %(user_identity)s that is used in
|
||||
# logging_context_format_string. (string value)
|
||||
#logging_user_identity_format = %(user)s %(tenant)s %(domain)s %(user_domain)s %(project_domain)s
|
||||
|
||||
# List of package logging levels in logger=LEVEL pairs. This option is ignored
|
||||
# if log_config_append is set. (list value)
|
||||
#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,oslo_messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO
|
||||
|
||||
# Enables or disables publication of error events. (boolean value)
|
||||
#publish_errors = false
|
||||
|
||||
# The format for an instance that is passed with the log message. (string
|
||||
# value)
|
||||
#instance_format = "[instance: %(uuid)s] "
|
||||
|
||||
# The format for an instance UUID that is passed with the log message. (string
|
||||
# value)
|
||||
#instance_uuid_format = "[instance: %(uuid)s] "
|
||||
|
||||
# Interval, number of seconds, of log rate limiting. (integer value)
|
||||
#rate_limit_interval = 0
|
||||
|
||||
# Maximum number of logged messages per rate_limit_interval. (integer value)
|
||||
#rate_limit_burst = 0
|
||||
|
||||
# Log level name used by rate limiting: CRITICAL, ERROR, INFO, WARNING, DEBUG
|
||||
# or empty string. Logs with level greater or equal to rate_limit_except_level
|
||||
# are not filtered. An empty string means that all levels are filtered. (string
|
||||
# value)
|
||||
#rate_limit_except_level = CRITICAL
|
||||
|
||||
# Enables or disables fatal status of deprecations. (boolean value)
|
||||
#fatal_deprecations = false
|
||||
|
||||
|
||||
[cors]
|
||||
|
||||
#
|
||||
# From oslo.middleware
|
||||
#
|
||||
|
||||
# Indicate whether this resource may be shared with the domain received in the
|
||||
# requests "origin" header. Format: "<protocol>://<host>[:<port>]", no trailing
|
||||
# slash. Example: https://horizon.example.com (list value)
|
||||
#allowed_origin = <None>
|
||||
|
||||
# Indicate that the actual request can include user credentials (boolean value)
|
||||
#allow_credentials = true
|
||||
|
||||
# Indicate which headers are safe to expose to the API. Defaults to HTTP Simple
|
||||
# Headers. (list value)
|
||||
#expose_headers =
|
||||
|
||||
# Maximum cache age of CORS preflight requests. (integer value)
|
||||
#max_age = 3600
|
||||
|
||||
# Indicate which methods can be used during the actual request. (list value)
|
||||
#allow_methods = OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,PATCH
|
||||
|
||||
# Indicate which header field names may be used during the actual request.
|
||||
# (list value)
|
||||
#allow_headers =
|
||||
|
||||
|
||||
[healthcheck]
|
||||
|
||||
#
|
||||
# From oslo.middleware
|
||||
#
|
||||
|
||||
# DEPRECATED: The path to respond to healtcheck requests on. (string value)
|
||||
# This option is deprecated for removal.
|
||||
# Its value may be silently ignored in the future.
|
||||
#path = /healthcheck
|
||||
|
||||
# Show more detailed information as part of the response (boolean value)
|
||||
#detailed = false
|
||||
|
||||
# Additional backends that can perform health checks and report that
|
||||
# information back as part of a request. (list value)
|
||||
#backends =
|
||||
|
||||
# Check the presence of a file to determine if an application is running on a
|
||||
# port. Used by DisableByFileHealthcheck plugin. (string value)
|
||||
#disable_by_file_path = <None>
|
||||
|
||||
# Check the presence of a file based on a port to determine if an application
|
||||
# is running on a port. Expects a "port:path" list of strings. Used by
|
||||
# DisableByFilesPortsHealthcheck plugin. (list value)
|
||||
#disable_by_file_paths =
|
||||
|
||||
|
||||
[keystone_authtoken]
|
||||
|
||||
#
|
||||
# From armada.conf
|
||||
#
|
||||
|
||||
# Authentication URL (string value)
|
||||
#auth_url = <None>
|
||||
|
||||
# Domain ID to scope to (string value)
|
||||
#domain_id = <None>
|
||||
|
||||
# Domain name to scope to (string value)
|
||||
#domain_name = <None>
|
||||
|
||||
# Project ID to scope to (string value)
|
||||
# Deprecated group/name - [keystone_authtoken]/tenant_id
|
||||
#project_id = <None>
|
||||
|
||||
# Project name to scope to (string value)
|
||||
# Deprecated group/name - [keystone_authtoken]/tenant_name
|
||||
#project_name = <None>
|
||||
|
||||
# Domain ID containing project (string value)
|
||||
#project_domain_id = <None>
|
||||
|
||||
# Domain name containing project (string value)
|
||||
#project_domain_name = <None>
|
||||
|
||||
# Trust ID (string value)
|
||||
#trust_id = <None>
|
||||
|
||||
# Optional domain ID to use with v3 and v2 parameters. It will be used for both
|
||||
# the user and project domain in v3 and ignored in v2 authentication. (string
|
||||
# value)
|
||||
#default_domain_id = <None>
|
||||
|
||||
# Optional domain name to use with v3 API and v2 parameters. It will be used
|
||||
# for both the user and project domain in v3 and ignored in v2 authentication.
|
||||
# (string value)
|
||||
#default_domain_name = <None>
|
||||
|
||||
# User id (string value)
|
||||
#user_id = <None>
|
||||
|
||||
# Username (string value)
|
||||
# Deprecated group/name - [keystone_authtoken]/user_name
|
||||
#username = <None>
|
||||
|
||||
# User's domain id (string value)
|
||||
#user_domain_id = <None>
|
||||
|
||||
# User's domain name (string value)
|
||||
#user_domain_name = <None>
|
||||
|
||||
# User's password (string value)
|
||||
#password = <None>
|
||||
|
||||
#
|
||||
# From keystonemiddleware.auth_token
|
||||
#
|
||||
|
||||
# Complete "public" Identity API endpoint. This endpoint should not be an
|
||||
# "admin" endpoint, as it should be accessible by all end users.
|
||||
# Unauthenticated clients are redirected to this endpoint to authenticate.
|
||||
# Although this endpoint should ideally be unversioned, client support in the
|
||||
# wild varies. If you're using a versioned v2 endpoint here, then this should
|
||||
# *not* be the same endpoint the service user utilizes for validating tokens,
|
||||
# because normal end users may not be able to reach that endpoint. (string
|
||||
# value)
|
||||
#auth_uri = <None>
|
||||
|
||||
# API version of the admin Identity API endpoint. (string value)
|
||||
#auth_version = <None>
|
||||
|
||||
# Do not handle authorization requests within the middleware, but delegate the
|
||||
# authorization decision to downstream WSGI components. (boolean value)
|
||||
#delay_auth_decision = false
|
||||
|
||||
# Request timeout value for communicating with Identity API server. (integer
|
||||
# value)
|
||||
#http_connect_timeout = <None>
|
||||
|
||||
# How many times are we trying to reconnect when communicating with Identity
|
||||
# API Server. (integer value)
|
||||
#http_request_max_retries = 3
|
||||
|
||||
# Request environment key where the Swift cache object is stored. When
|
||||
# auth_token middleware is deployed with a Swift cache, use this option to have
|
||||
# the middleware share a caching backend with swift. Otherwise, use the
|
||||
# ``memcached_servers`` option instead. (string value)
|
||||
#cache = <None>
|
||||
|
||||
# Required if identity server requires client certificate (string value)
|
||||
#certfile = <None>
|
||||
|
||||
# Required if identity server requires client certificate (string value)
|
||||
#keyfile = <None>
|
||||
|
||||
# A PEM encoded Certificate Authority to use when verifying HTTPs connections.
|
||||
# Defaults to system CAs. (string value)
|
||||
#cafile = <None>
|
||||
|
||||
# Verify HTTPS connections. (boolean value)
|
||||
#insecure = false
|
||||
|
||||
# The region in which the identity server can be found. (string value)
|
||||
#region_name = <None>
|
||||
|
||||
# Directory used to cache files related to PKI tokens. (string value)
|
||||
#signing_dir = <None>
|
||||
|
||||
# Optionally specify a list of memcached server(s) to use for caching. If left
|
||||
# undefined, tokens will instead be cached in-process. (list value)
|
||||
# Deprecated group/name - [keystone_authtoken]/memcache_servers
|
||||
#memcached_servers = <None>
|
||||
|
||||
# In order to prevent excessive effort spent validating tokens, the middleware
|
||||
# caches previously-seen tokens for a configurable duration (in seconds). Set
|
||||
# to -1 to disable caching completely. (integer value)
|
||||
#token_cache_time = 300
|
||||
|
||||
# Determines the frequency at which the list of revoked tokens is retrieved
|
||||
# from the Identity service (in seconds). A high number of revocation events
|
||||
# combined with a low cache duration may significantly reduce performance. Only
|
||||
# valid for PKI tokens. (integer value)
|
||||
#revocation_cache_time = 10
|
||||
|
||||
# (Optional) If defined, indicate whether token data should be authenticated or
|
||||
# authenticated and encrypted. If MAC, token data is authenticated (with HMAC)
|
||||
# in the cache. If ENCRYPT, token data is encrypted and authenticated in the
|
||||
# cache. If the value is not one of these options or empty, auth_token will
|
||||
# raise an exception on initialization. (string value)
|
||||
# Allowed values: None, MAC, ENCRYPT
|
||||
#memcache_security_strategy = None
|
||||
|
||||
# (Optional, mandatory if memcache_security_strategy is defined) This string is
|
||||
# used for key derivation. (string value)
|
||||
#memcache_secret_key = <None>
|
||||
|
||||
# (Optional) Number of seconds memcached server is considered dead before it is
|
||||
# tried again. (integer value)
|
||||
#memcache_pool_dead_retry = 300
|
||||
|
||||
# (Optional) Maximum total number of open connections to every memcached
|
||||
# server. (integer value)
|
||||
#memcache_pool_maxsize = 10
|
||||
|
||||
# (Optional) Socket timeout in seconds for communicating with a memcached
|
||||
# server. (integer value)
|
||||
#memcache_pool_socket_timeout = 3
|
||||
|
||||
# (Optional) Number of seconds a connection to memcached is held unused in the
|
||||
# pool before it is closed. (integer value)
|
||||
#memcache_pool_unused_timeout = 60
|
||||
|
||||
# (Optional) Number of seconds that an operation will wait to get a memcached
|
||||
# client connection from the pool. (integer value)
|
||||
#memcache_pool_conn_get_timeout = 10
|
||||
|
||||
# (Optional) Use the advanced (eventlet safe) memcached client pool. The
|
||||
# advanced pool will only work under python 2.x. (boolean value)
|
||||
#memcache_use_advanced_pool = false
|
||||
|
||||
# (Optional) Indicate whether to set the X-Service-Catalog header. If False,
|
||||
# middleware will not ask for service catalog on token validation and will not
|
||||
# set the X-Service-Catalog header. (boolean value)
|
||||
#include_service_catalog = true
|
||||
|
||||
# Used to control the use and type of token binding. Can be set to: "disabled"
|
||||
# to not check token binding. "permissive" (default) to validate binding
|
||||
# information if the bind type is of a form known to the server and ignore it
|
||||
# if not. "strict" like "permissive" but if the bind type is unknown the token
|
||||
# will be rejected. "required" any form of token binding is needed to be
|
||||
# allowed. Finally the name of a binding method that must be present in tokens.
|
||||
# (string value)
|
||||
#enforce_token_bind = permissive
|
||||
|
||||
# If true, the revocation list will be checked for cached tokens. This requires
|
||||
# that PKI tokens are configured on the identity server. (boolean value)
|
||||
#check_revocations_for_cached = false
|
||||
|
||||
# Hash algorithms to use for hashing PKI tokens. This may be a single algorithm
|
||||
# or multiple. The algorithms are those supported by Python standard
|
||||
# hashlib.new(). The hashes will be tried in the order given, so put the
|
||||
# preferred one first for performance. The result of the first hash will be
|
||||
# stored in the cache. This will typically be set to multiple values only while
|
||||
# migrating from a less secure algorithm to a more secure one. Once all the old
|
||||
# tokens are expired this option should be set to a single value for better
|
||||
# performance. (list value)
|
||||
#hash_algorithms = md5
|
||||
|
||||
# Authentication type to load (string value)
|
||||
# Deprecated group/name - [keystone_authtoken]/auth_plugin
|
||||
#auth_type = <None>
|
||||
|
||||
# Config Section from which to load plugin specific options (string value)
|
||||
#auth_section = <None>
|
||||
|
||||
|
||||
[oslo_middleware]
|
||||
|
||||
#
|
||||
# From oslo.middleware
|
||||
#
|
||||
|
||||
# The maximum body size for each request, in bytes. (integer value)
|
||||
# Deprecated group/name - [DEFAULT]/osapi_max_request_body_size
|
||||
# Deprecated group/name - [DEFAULT]/max_request_body_size
|
||||
#max_request_body_size = 114688
|
||||
|
||||
# DEPRECATED: The HTTP Header that will be used to determine what the original
|
||||
# request protocol scheme was, even if it was hidden by a SSL termination
|
||||
# proxy. (string value)
|
||||
# This option is deprecated for removal.
|
||||
# Its value may be silently ignored in the future.
|
||||
#secure_proxy_ssl_header = X-Forwarded-Proto
|
||||
|
||||
# Whether the application is behind a proxy or not. This determines if the
|
||||
# middleware should parse the headers or not. (boolean value)
|
||||
#enable_proxy_headers_parsing = false
|
||||
|
||||
|
||||
[oslo_policy]
|
||||
|
||||
#
|
||||
# From oslo.policy
|
||||
#
|
||||
|
||||
# The file that defines policies. (string value)
|
||||
#policy_file = policy.json
|
||||
|
||||
# Default rule. Enforced when a requested rule is not found. (string value)
|
||||
#policy_default_rule = default
|
||||
|
||||
# Directories where policy configuration files are stored. They can be relative
|
||||
# to any directory in the search path defined by the config_dir option, or
|
||||
# absolute paths. The file defined by policy_file must exist for these
|
||||
# directories to be searched. Missing or empty directories are ignored. (multi
|
||||
# valued)
|
||||
#policy_dirs = policy.d
|
33
etc/armada/policy.yaml
Normal file
33
etc/armada/policy.yaml
Normal file
@ -0,0 +1,33 @@
|
||||
#
|
||||
#"admin_required": "role:admin"
|
||||
|
||||
#
|
||||
#"service_or_admin": "rule:admin_required or rule:service_role"
|
||||
|
||||
#
|
||||
#"service_role": "role:service"
|
||||
|
||||
# install manifest charts
|
||||
# POST api/v1.0/apply/
|
||||
#"armada:create_endpoints": "rule:admin_required"
|
||||
|
||||
# validate installed manifest
|
||||
# POST /api/v1.0/validate/
|
||||
#"armada:validate_manifest": "rule:admin_required"
|
||||
|
||||
# validate install manifest
|
||||
# GET /api/v1.0/test/{release}
|
||||
#"armada:test_release": "rule:admin_required"
|
||||
|
||||
# validate install manifest
|
||||
# POST /api/v1.0/tests/
|
||||
#"armada:test_manifest": "rule:admin_required"
|
||||
|
||||
# Get tiller status
|
||||
# GET /api/v1.0/status/
|
||||
#"tiller:get_status": "rule:admin_required"
|
||||
|
||||
# Get tiller release
|
||||
# GET /api/v1.0/releases/
|
||||
#"tiller:get_release": "rule:admin_required"
|
||||
|
13
examples/armada-keystone-manifest.yaml
Normal file
13
examples/armada-keystone-manifest.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
schema: armada/Chart/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: keystone
|
||||
data:
|
||||
values:
|
||||
bootstrap:
|
||||
script: |
|
||||
openstack domain create 'ucp'
|
||||
openstack project create --domain 'ucp' 'service'
|
||||
openstack user create --domain ucp --project service --project-domain 'ucp' --password armada armada
|
||||
openstack role add --project-domain ucp --user-domain ucp --user armada --project service admin
|
@ -10,7 +10,7 @@ data:
|
||||
values: {}
|
||||
source:
|
||||
type: git
|
||||
location: git://github.com/openstack/openstack-helm
|
||||
location: https://git.openstack.org/openstack/openstack-helm
|
||||
subpath: helm-toolkit
|
||||
reference: master
|
||||
dependencies: []
|
||||
@ -34,7 +34,7 @@ data:
|
||||
values: {}
|
||||
source:
|
||||
type: git
|
||||
location: git://github.com/openstack/openstack-helm
|
||||
location: https://git.openstack.org/openstack/openstack-helm
|
||||
subpath: mariadb
|
||||
reference: master
|
||||
dependencies:
|
||||
@ -59,7 +59,7 @@ data:
|
||||
values: {}
|
||||
source:
|
||||
type: git
|
||||
location: git://github.com/openstack/openstack-helm
|
||||
location: https://git.openstack.org/openstack/openstack-helm
|
||||
subpath: memcached
|
||||
reference: master
|
||||
dependencies:
|
||||
@ -82,11 +82,18 @@ data:
|
||||
no_hooks: false
|
||||
upgrade:
|
||||
no_hooks: false
|
||||
pre:
|
||||
delete:
|
||||
- name: keystone-bootstrap
|
||||
type: job
|
||||
labels:
|
||||
- application: keystone
|
||||
- component: bootstrap
|
||||
values:
|
||||
replicas: 2
|
||||
replicas: 3
|
||||
source:
|
||||
type: git
|
||||
location: git://github.com/openstack/openstack-helm
|
||||
location: https://git.openstack.org/openstack/openstack-helm
|
||||
subpath: keystone
|
||||
reference: master
|
||||
dependencies:
|
||||
|
@ -1,4 +1,4 @@
|
||||
gitpython==2.1.5
|
||||
gitpython
|
||||
grpcio==1.6.0rc1
|
||||
grpcio-tools==1.6.0rc1
|
||||
keystoneauth1==2.21.0
|
||||
@ -6,18 +6,17 @@ keystonemiddleware==4.9.1
|
||||
kubernetes>=1.0.0
|
||||
protobuf>=3.4.0
|
||||
PyYAML==3.12
|
||||
requests==2.17.3
|
||||
requests
|
||||
supermutes==0.2.5
|
||||
urllib3==1.21.1
|
||||
Paste>=2.0.3
|
||||
PasteDeploy>=1.5.2
|
||||
|
||||
# API
|
||||
falcon==1.1.0
|
||||
falcon
|
||||
uwsgi>=2.0.15
|
||||
|
||||
# CLI
|
||||
cliff==2.7.0
|
||||
click>=6.7
|
||||
|
||||
# Oslo
|
||||
oslo.cache>=1.5.0 # Apache-2.0
|
||||
|
@ -40,11 +40,6 @@ upload-dir = doc/build/html
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
armada = armada.shell:main
|
||||
armada =
|
||||
apply = armada.cli.apply:ApplyChartsCommand
|
||||
tiller = armada.cli.tiller:TillerServerCommand
|
||||
validate = armada.cli.validate:ValidateYamlCommand
|
||||
test = armada.cli.test:TestServerCommand
|
||||
oslo.config.opts =
|
||||
armada.conf = armada.conf.opts:list_opts
|
||||
oslo.policy.policies =
|
||||
|
@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -x $(which openstack) ]; then
|
||||
pip install python-openstackclient
|
||||
fi
|
||||
|
||||
openstack domain create 'ucp'
|
||||
openstack project create --domain 'ucp' 'service'
|
||||
openstack user create --domain ucp --project service --project-domain 'ucp' --password armada armada
|
||||
|
Loading…
x
Reference in New Issue
Block a user