mirror of
https://github.com/ansible/awx.git
synced 2026-03-20 18:37:39 -02:30
move code linting to a stricter pep8-esque auto-formatting tool, black
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
from .pages import * # NOQA
|
||||
from .client import * # NOQA
|
||||
from .pages import * # NOQA
|
||||
from .client import * # NOQA
|
||||
|
||||
@@ -49,8 +49,7 @@ class Connection(object):
|
||||
_next = kwargs.get('next')
|
||||
if _next:
|
||||
headers = self.session.headers.copy()
|
||||
self.post('/api/login/', headers=headers,
|
||||
data=dict(username=username, password=password, next=_next))
|
||||
self.post('/api/login/', headers=headers, data=dict(username=username, password=password, next=_next))
|
||||
self.session_id = self.session.cookies.get('sessionid')
|
||||
self.uses_session_cookie = True
|
||||
else:
|
||||
@@ -79,8 +78,7 @@ class Connection(object):
|
||||
use_endpoint = use_endpoint[1:]
|
||||
url = '/'.join([self.server, use_endpoint])
|
||||
|
||||
kwargs = dict(verify=self.verify, params=query_parameters, json=json, data=data,
|
||||
hooks=dict(response=log_elapsed))
|
||||
kwargs = dict(verify=self.verify, params=query_parameters, json=json, data=data, hooks=dict(response=log_elapsed))
|
||||
|
||||
if headers is not None:
|
||||
kwargs['headers'] = headers
|
||||
|
||||
@@ -3,7 +3,6 @@ from awxkit.utils import random_title
|
||||
|
||||
|
||||
class HasCopy(object):
|
||||
|
||||
def can_copy(self):
|
||||
return self.get_related('copy').can_copy
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ def dependency_graph(page, *provided_dependencies):
|
||||
return graph
|
||||
|
||||
|
||||
def optional_dependency_graph(page, *provided_dependencies):
|
||||
def optional_dependency_graph(page, *provided_dependencies):
|
||||
"""Creates a dependency graph for a page including all dependencies and optional_dependencies
|
||||
Any optional provided_dependencies will be included as if they were dependencies,
|
||||
without affecting the value of each keyed page.
|
||||
@@ -104,8 +104,7 @@ def all_instantiated_dependencies(*potential_parents):
|
||||
"""
|
||||
scope_provided_dependencies = []
|
||||
|
||||
instantiated = set([x for x in potential_parents
|
||||
if not isinstance(x, type) and not isinstance(x, tuple)])
|
||||
instantiated = set([x for x in potential_parents if not isinstance(x, type) and not isinstance(x, tuple)])
|
||||
|
||||
for potential_parent in [x for x in instantiated if hasattr(x, '_dependency_store')]:
|
||||
for dependency in potential_parent._dependency_store.values():
|
||||
@@ -178,7 +177,6 @@ class DSAdapter(object):
|
||||
# Hijack json.dumps and simplejson.dumps (used by requests)
|
||||
# to allow HasCreate.create_payload() serialization without impacting payload.ds access
|
||||
def filter_ds_from_payload(dumps):
|
||||
|
||||
def _filter_ds_from_payload(obj, *a, **kw):
|
||||
if hasattr(obj, 'get') and isinstance(obj.get('ds'), DSAdapter):
|
||||
filtered = obj.copy()
|
||||
@@ -191,10 +189,12 @@ def filter_ds_from_payload(dumps):
|
||||
|
||||
|
||||
import json # noqa
|
||||
|
||||
json.dumps = filter_ds_from_payload(json.dumps)
|
||||
|
||||
try:
|
||||
import simplejson # noqa
|
||||
|
||||
simplejson.dumps = filter_ds_from_payload(simplejson.dumps)
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -299,8 +299,7 @@ class HasCreate(object):
|
||||
# remove falsy values
|
||||
provided_and_desired_dependencies = [x for x in provided_and_desired_dependencies if x]
|
||||
# (HasCreate(), True) tells HasCreate._update_dependencies to link
|
||||
provided_dependencies = [(x, True) for x in provided_and_desired_dependencies
|
||||
if not isinstance(x, type) and not isinstance(x, tuple)]
|
||||
provided_dependencies = [(x, True) for x in provided_and_desired_dependencies if not isinstance(x, type) and not isinstance(x, tuple)]
|
||||
|
||||
# Since dependencies are often declared at runtime, we need to use some introspection
|
||||
# to determine previously created ones for proper dependency store linking.
|
||||
@@ -374,12 +373,7 @@ class HasCreate(object):
|
||||
to_teardown = all_instantiated_dependencies(self)
|
||||
to_teardown_types = set(map(get_class_if_instance, to_teardown))
|
||||
order = [
|
||||
set(
|
||||
[
|
||||
potential for potential in (
|
||||
get_class_if_instance(x) for x in group) if potential in to_teardown_types
|
||||
]
|
||||
)
|
||||
set([potential for potential in (get_class_if_instance(x) for x in group) if potential in to_teardown_types])
|
||||
for group in page_creation_order(self, *to_teardown)
|
||||
]
|
||||
order.reverse()
|
||||
|
||||
@@ -3,7 +3,6 @@ import awxkit.exceptions as exc
|
||||
|
||||
|
||||
class HasInstanceGroups(object):
|
||||
|
||||
def add_instance_group(self, instance_group):
|
||||
with suppress(exc.NoContent):
|
||||
self.related['instance_groups'].post(dict(id=instance_group.id))
|
||||
|
||||
@@ -2,29 +2,25 @@ from awxkit.utils import suppress
|
||||
import awxkit.exceptions as exc
|
||||
|
||||
|
||||
notification_endpoints = ("notification_templates", "notification_templates_started", "notification_templates_error",
|
||||
"notification_templates_success")
|
||||
notification_endpoints = ("notification_templates", "notification_templates_started", "notification_templates_error", "notification_templates_success")
|
||||
wfjt_notification_endpoints = notification_endpoints + ('notification_templates_approvals',)
|
||||
|
||||
|
||||
class HasNotifications(object):
|
||||
|
||||
def add_notification_template(self, notification_template, endpoint="notification_templates_success"):
|
||||
from awxkit.api.pages.workflow_job_templates import WorkflowJobTemplate
|
||||
supported_endpoints = wfjt_notification_endpoints if isinstance(self, WorkflowJobTemplate) \
|
||||
else notification_endpoints
|
||||
|
||||
supported_endpoints = wfjt_notification_endpoints if isinstance(self, WorkflowJobTemplate) else notification_endpoints
|
||||
if endpoint not in supported_endpoints:
|
||||
raise ValueError('Unsupported notification endpoint "{0}". Please use one of {1}.'
|
||||
.format(endpoint, notification_endpoints))
|
||||
raise ValueError('Unsupported notification endpoint "{0}". Please use one of {1}.'.format(endpoint, notification_endpoints))
|
||||
with suppress(exc.NoContent):
|
||||
self.related[endpoint].post(dict(id=notification_template.id))
|
||||
|
||||
def remove_notification_template(self, notification_template, endpoint="notification_templates_success"):
|
||||
from awxkit.api.pages.workflow_job_templates import WorkflowJobTemplate
|
||||
supported_endpoints = wfjt_notification_endpoints if isinstance(self, WorkflowJobTemplate) \
|
||||
else notification_endpoints
|
||||
|
||||
supported_endpoints = wfjt_notification_endpoints if isinstance(self, WorkflowJobTemplate) else notification_endpoints
|
||||
if endpoint not in supported_endpoints:
|
||||
raise ValueError('Unsupported notification endpoint "{0}". Please use one of {1}.'
|
||||
.format(endpoint, notification_endpoints))
|
||||
raise ValueError('Unsupported notification endpoint "{0}". Please use one of {1}.'.format(endpoint, notification_endpoints))
|
||||
with suppress(exc.NoContent):
|
||||
self.related[endpoint].post(dict(id=notification_template.id, disassociate=notification_template.id))
|
||||
|
||||
@@ -40,8 +40,7 @@ class HasStatus(object):
|
||||
if not getattr(self, 'event_processing_finished', True):
|
||||
elapsed = datetime.utcnow() - start_time
|
||||
time_left = timeout - elapsed.total_seconds()
|
||||
poll_until(lambda: getattr(self.get(), 'event_processing_finished', True),
|
||||
interval=interval, timeout=time_left, **kwargs)
|
||||
poll_until(lambda: getattr(self.get(), 'event_processing_finished', True), interval=interval, timeout=time_left, **kwargs)
|
||||
return self
|
||||
|
||||
def wait_until_started(self, interval=1, timeout=60):
|
||||
@@ -65,9 +64,7 @@ class HasStatus(object):
|
||||
msg = ''
|
||||
else:
|
||||
msg += '\n'
|
||||
msg += '{0}-{1} has status of {2}, which is not in {3}.'.format(
|
||||
self.type.title(), self.id, self.status, status_list
|
||||
)
|
||||
msg += '{0}-{1} has status of {2}, which is not in {3}.'.format(self.type.title(), self.id, self.status, status_list)
|
||||
if getattr(self, 'job_explanation', ''):
|
||||
msg += '\njob_explanation: {}'.format(bytes_to_str(self.job_explanation))
|
||||
if getattr(self, 'result_traceback', ''):
|
||||
@@ -79,10 +76,8 @@ class HasStatus(object):
|
||||
try:
|
||||
data = json.loads(self.job_explanation.replace('Previous Task Failed: ', ''))
|
||||
dep_output = self.connection.get(
|
||||
'{0}/api/v2/{1}s/{2}/stdout/'.format(
|
||||
self.endpoint.split('/api')[0], data['job_type'], data['job_id']
|
||||
),
|
||||
query_parameters=dict(format='txt_download')
|
||||
'{0}/api/v2/{1}s/{2}/stdout/'.format(self.endpoint.split('/api')[0], data['job_type'], data['job_id']),
|
||||
query_parameters=dict(format='txt_download'),
|
||||
).content
|
||||
msg += '\nDependency output:\n{}'.format(bytes_to_str(dep_output))
|
||||
except Exception as e:
|
||||
|
||||
@@ -3,13 +3,11 @@ from awxkit.utils import random_title
|
||||
|
||||
class HasSurvey(object):
|
||||
def add_survey(self, spec=None, name=None, description=None, required=False, enabled=True):
|
||||
payload = dict(name=name or 'Survey - {}'.format(random_title()),
|
||||
description=description or random_title(10),
|
||||
spec=spec or [dict(required=required,
|
||||
question_name="What's the password?",
|
||||
variable="secret",
|
||||
type="password",
|
||||
default="foo")])
|
||||
payload = dict(
|
||||
name=name or 'Survey - {}'.format(random_title()),
|
||||
description=description or random_title(10),
|
||||
spec=spec or [dict(required=required, question_name="What's the password?", variable="secret", type="password", default="foo")],
|
||||
)
|
||||
if enabled != self.survey_enabled:
|
||||
self.patch(survey_enabled=enabled)
|
||||
return self.related.survey_spec.post(payload).get()
|
||||
|
||||
@@ -4,7 +4,6 @@ from awxkit.utils import PseudoNamespace
|
||||
|
||||
|
||||
class HasVariables(object):
|
||||
|
||||
@property
|
||||
def variables(self):
|
||||
return PseudoNamespace(yaml.safe_load(self.json.variables))
|
||||
|
||||
@@ -33,7 +33,7 @@ from .workflow_job_templates import * # NOQA
|
||||
from .workflow_job_template_nodes import * # NOQA
|
||||
from .workflow_jobs import * # NOQA
|
||||
from .workflow_job_nodes import * # NOQA
|
||||
from .workflow_approvals import * # NOQA
|
||||
from .workflow_approvals import * # NOQA
|
||||
from .settings import * # NOQA
|
||||
from .instances import * # NOQA
|
||||
from .instance_groups import * # NOQA
|
||||
|
||||
@@ -8,11 +8,16 @@ class AccessList(page.PageList, users.User):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.organization_access_list,
|
||||
resources.user_access_list,
|
||||
resources.inventory_access_list,
|
||||
resources.group_access_list,
|
||||
resources.credential_access_list,
|
||||
resources.project_access_list,
|
||||
resources.job_template_access_list,
|
||||
resources.team_access_list], AccessList)
|
||||
page.register_page(
|
||||
[
|
||||
resources.organization_access_list,
|
||||
resources.user_access_list,
|
||||
resources.inventory_access_list,
|
||||
resources.group_access_list,
|
||||
resources.credential_access_list,
|
||||
resources.project_access_list,
|
||||
resources.job_template_access_list,
|
||||
resources.team_access_list,
|
||||
],
|
||||
AccessList,
|
||||
)
|
||||
|
||||
@@ -16,5 +16,4 @@ class ActivityStreams(page.PageList, ActivityStream):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.activity_stream,
|
||||
resources.object_activity_stream], ActivityStreams)
|
||||
page.register_page([resources.activity_stream, resources.object_activity_stream], ActivityStreams)
|
||||
|
||||
@@ -24,31 +24,40 @@ class AdHocCommand(HasCreate, UnifiedJob):
|
||||
return self.walk(result.url)
|
||||
|
||||
def payload(self, inventory, credential, module_name='ping', **kwargs):
|
||||
payload = PseudoNamespace(inventory=inventory.id,
|
||||
credential=credential.id,
|
||||
module_name=module_name)
|
||||
payload = PseudoNamespace(inventory=inventory.id, credential=credential.id, module_name=module_name)
|
||||
|
||||
optional_fields = ('diff_mode', 'extra_vars', 'module_args', 'job_type', 'limit', 'forks',
|
||||
'verbosity')
|
||||
optional_fields = ('diff_mode', 'extra_vars', 'module_args', 'job_type', 'limit', 'forks', 'verbosity')
|
||||
return update_payload(payload, optional_fields, kwargs)
|
||||
|
||||
def create_payload(self, module_name='ping', module_args=np, job_type=np, limit=np, verbosity=np,
|
||||
inventory=Inventory, credential=Credential, **kwargs):
|
||||
def create_payload(self, module_name='ping', module_args=np, job_type=np, limit=np, verbosity=np, inventory=Inventory, credential=Credential, **kwargs):
|
||||
|
||||
self.create_and_update_dependencies(inventory, credential)
|
||||
|
||||
payload = self.payload(module_name=module_name, module_args=module_args, job_type=job_type, limit=limit,
|
||||
verbosity=verbosity, inventory=self.ds.inventory, credential=self.ds.credential,
|
||||
**kwargs)
|
||||
payload = self.payload(
|
||||
module_name=module_name,
|
||||
module_args=module_args,
|
||||
job_type=job_type,
|
||||
limit=limit,
|
||||
verbosity=verbosity,
|
||||
inventory=self.ds.inventory,
|
||||
credential=self.ds.credential,
|
||||
**kwargs
|
||||
)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(self, module_name='ping', module_args=np, job_type=np, limit=np, verbosity=np,
|
||||
inventory=Inventory, credential=Credential, **kwargs):
|
||||
def create(self, module_name='ping', module_args=np, job_type=np, limit=np, verbosity=np, inventory=Inventory, credential=Credential, **kwargs):
|
||||
|
||||
payload = self.create_payload(module_name=module_name, module_args=module_args,
|
||||
job_type=job_type, limit=limit, verbosity=verbosity,
|
||||
inventory=inventory, credential=credential, **kwargs)
|
||||
payload = self.create_payload(
|
||||
module_name=module_name,
|
||||
module_args=module_args,
|
||||
job_type=job_type,
|
||||
limit=limit,
|
||||
verbosity=verbosity,
|
||||
inventory=inventory,
|
||||
credential=credential,
|
||||
**kwargs
|
||||
)
|
||||
return self.update_identity(AdHocCommands(self.connection).post(payload))
|
||||
|
||||
|
||||
@@ -60,7 +69,7 @@ class AdHocCommands(page.PageList, AdHocCommand):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.ad_hoc_commands,
|
||||
resources.inventory_related_ad_hoc_commands,
|
||||
resources.group_related_ad_hoc_commands,
|
||||
resources.host_related_ad_hoc_commands], AdHocCommands)
|
||||
page.register_page(
|
||||
[resources.ad_hoc_commands, resources.inventory_related_ad_hoc_commands, resources.group_related_ad_hoc_commands, resources.host_related_ad_hoc_commands],
|
||||
AdHocCommands,
|
||||
)
|
||||
|
||||
@@ -90,18 +90,14 @@ class ApiV2(base.Base):
|
||||
return None
|
||||
|
||||
# Note: doing _page[key] automatically parses json blob strings, which can be a problem.
|
||||
fields = {
|
||||
key: _page.json[key] for key in post_fields
|
||||
if key in _page.json and key not in _page.related and key != 'id'
|
||||
}
|
||||
fields = {key: _page.json[key] for key in post_fields if key in _page.json and key not in _page.related and key != 'id'}
|
||||
|
||||
for key in post_fields:
|
||||
if key in _page.related:
|
||||
related = _page.related[key]
|
||||
else:
|
||||
if post_fields[key]['type'] == 'id' and _page.json.get(key) is not None:
|
||||
log.warning("Related link %r missing from %s, attempting to reconstruct endpoint.",
|
||||
key, _page.endpoint)
|
||||
log.warning("Related link %r missing from %s, attempting to reconstruct endpoint.", key, _page.endpoint)
|
||||
resource = getattr(self, key, None)
|
||||
if resource is None:
|
||||
log.error("Unable to infer endpoint for %r on %s.", key, _page.endpoint)
|
||||
@@ -119,8 +115,7 @@ class ApiV2(base.Base):
|
||||
continue
|
||||
rel_natural_key = rel_endpoint.get_natural_key(self._cache)
|
||||
if rel_natural_key is None:
|
||||
log.error("Unable to construct a natural key for foreign key %r of object %s.",
|
||||
key, _page.endpoint)
|
||||
log.error("Unable to construct a natural key for foreign key %r of object %s.", key, _page.endpoint)
|
||||
return None # This foreign key has unresolvable dependencies
|
||||
fields[key] = rel_natural_key
|
||||
|
||||
@@ -154,10 +149,7 @@ class ApiV2(base.Base):
|
||||
continue
|
||||
|
||||
if 'results' in rel_page:
|
||||
results = (
|
||||
x.get_natural_key(self._cache) if by_natural_key else self._export(x, rel_post_fields)
|
||||
for x in rel_page.results
|
||||
)
|
||||
results = (x.get_natural_key(self._cache) if by_natural_key else self._export(x, rel_post_fields) for x in rel_page.results)
|
||||
related[key] = [x for x in results if x is not None]
|
||||
else:
|
||||
related[key] = rel_page.json
|
||||
@@ -190,8 +182,7 @@ class ApiV2(base.Base):
|
||||
if isinstance(value, int) or value.isdecimal():
|
||||
return endpoint.get(id=int(value))
|
||||
options = self._cache.get_options(endpoint)
|
||||
identifier = next(field for field in options['search_fields']
|
||||
if field in ('name', 'username', 'hostname'))
|
||||
identifier = next(field for field in options['search_fields'] if field in ('name', 'username', 'hostname'))
|
||||
return endpoint.get(**{identifier: value})
|
||||
|
||||
def export_assets(self, **kwargs):
|
||||
@@ -214,8 +205,7 @@ class ApiV2(base.Base):
|
||||
# Import methods
|
||||
|
||||
def _dependent_resources(self, data):
|
||||
page_resource = {getattr(self, resource)._create().__item_class__: resource
|
||||
for resource in self.json}
|
||||
page_resource = {getattr(self, resource)._create().__item_class__: resource for resource in self.json}
|
||||
data_pages = [getattr(self, resource)._create().__item_class__ for resource in EXPORTABLE_RESOURCES]
|
||||
|
||||
for page_cls in itertools.chain(*has_create.page_creation_order(*data_pages)):
|
||||
|
||||
@@ -12,10 +12,12 @@ class OAuth2Application(HasCreate, base.Base):
|
||||
dependencies = [Organization]
|
||||
|
||||
def payload(self, **kwargs):
|
||||
payload = PseudoNamespace(name=kwargs.get('name') or 'OAuth2Application - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
client_type=kwargs.get('client_type', 'public'),
|
||||
authorization_grant_type=kwargs.get('authorization_grant_type', 'password'))
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'OAuth2Application - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
client_type=kwargs.get('client_type', 'public'),
|
||||
authorization_grant_type=kwargs.get('authorization_grant_type', 'password'),
|
||||
)
|
||||
if kwargs.get('organization'):
|
||||
payload.organization = kwargs['organization'].id
|
||||
|
||||
@@ -35,8 +37,7 @@ class OAuth2Application(HasCreate, base.Base):
|
||||
return self.update_identity(OAuth2Applications(self.connection).post(payload))
|
||||
|
||||
|
||||
page.register_page((resources.application,
|
||||
(resources.applications, 'post')), OAuth2Application)
|
||||
page.register_page((resources.application, (resources.applications, 'post')), OAuth2Application)
|
||||
|
||||
|
||||
class OAuth2Applications(page.PageList, OAuth2Application):
|
||||
@@ -51,8 +52,7 @@ class OAuth2AccessToken(HasCreate, base.Base):
|
||||
optional_dependencies = [OAuth2Application]
|
||||
|
||||
def payload(self, **kwargs):
|
||||
payload = PseudoNamespace(description=kwargs.get('description') or random_title(10),
|
||||
scope=kwargs.get('scope', 'write'))
|
||||
payload = PseudoNamespace(description=kwargs.get('description') or random_title(10), scope=kwargs.get('scope', 'write'))
|
||||
|
||||
if kwargs.get('oauth_2_application'):
|
||||
payload.application = kwargs['oauth_2_application'].id
|
||||
@@ -73,8 +73,7 @@ class OAuth2AccessToken(HasCreate, base.Base):
|
||||
return self.update_identity(OAuth2AccessTokens(self.connection).post(payload))
|
||||
|
||||
|
||||
page.register_page((resources.token,
|
||||
(resources.tokens, 'post')), OAuth2AccessToken)
|
||||
page.register_page((resources.token, (resources.tokens, 'post')), OAuth2AccessToken)
|
||||
|
||||
|
||||
class OAuth2AccessTokens(page.PageList, OAuth2AccessToken):
|
||||
|
||||
@@ -3,11 +3,7 @@ import logging
|
||||
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
from awxkit.api.pages import (
|
||||
Page,
|
||||
get_registered_page,
|
||||
exception_from_status_code
|
||||
)
|
||||
from awxkit.api.pages import Page, get_registered_page, exception_from_status_code
|
||||
from awxkit.config import config
|
||||
from awxkit.api.resources import resources
|
||||
import awxkit.exceptions as exc
|
||||
@@ -17,7 +13,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Base(Page):
|
||||
|
||||
def silent_delete(self):
|
||||
"""Delete the object. If it's already deleted, ignore the error"""
|
||||
try:
|
||||
@@ -129,14 +124,14 @@ class Base(Page):
|
||||
@property
|
||||
def object_roles(self):
|
||||
from awxkit.api.pages import Roles, Role
|
||||
|
||||
url = self.get().json.related.object_roles
|
||||
for obj_role in Roles(self.connection, endpoint=url).get().json.results:
|
||||
yield Role(self.connection, endpoint=obj_role.url).get()
|
||||
|
||||
def get_authtoken(self, username='', password=''):
|
||||
default_cred = config.credentials.default
|
||||
payload = dict(username=username or default_cred.username,
|
||||
password=password or default_cred.password)
|
||||
payload = dict(username=username or default_cred.username, password=password or default_cred.password)
|
||||
auth_url = resources.authtoken
|
||||
return get_registered_page(auth_url)(self.connection, endpoint=auth_url).post(payload).token
|
||||
|
||||
@@ -146,9 +141,7 @@ class Base(Page):
|
||||
|
||||
load_default_authtoken = load_authtoken
|
||||
|
||||
def get_oauth2_token(self, username='', password='', client_id=None,
|
||||
description='AWX CLI',
|
||||
client_secret=None, scope='write'):
|
||||
def get_oauth2_token(self, username='', password='', client_id=None, description='AWX CLI', client_secret=None, scope='write'):
|
||||
default_cred = config.credentials.default
|
||||
username = username or default_cred.username
|
||||
password = password or default_cred.password
|
||||
@@ -157,38 +150,21 @@ class Base(Page):
|
||||
HTTPBasicAuth(client_id, client_secret)(req)
|
||||
req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||
resp = self.connection.post(
|
||||
'/api/o/token/',
|
||||
data={
|
||||
"grant_type": "password",
|
||||
"username": username,
|
||||
"password": password,
|
||||
"scope": scope
|
||||
},
|
||||
headers=req.headers
|
||||
'/api/o/token/', data={"grant_type": "password", "username": username, "password": password, "scope": scope}, headers=req.headers
|
||||
)
|
||||
elif client_id:
|
||||
req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||
resp = self.connection.post(
|
||||
'/api/o/token/',
|
||||
data={
|
||||
"grant_type": "password",
|
||||
"username": username,
|
||||
"password": password,
|
||||
"client_id": client_id,
|
||||
"scope": scope
|
||||
},
|
||||
headers=req.headers
|
||||
data={"grant_type": "password", "username": username, "password": password, "client_id": client_id, "scope": scope},
|
||||
headers=req.headers,
|
||||
)
|
||||
else:
|
||||
HTTPBasicAuth(username, password)(req)
|
||||
resp = self.connection.post(
|
||||
'/api/v2/users/{}/personal_tokens/'.format(username),
|
||||
json={
|
||||
"description": description,
|
||||
"application": None,
|
||||
"scope": scope
|
||||
},
|
||||
headers=req.headers
|
||||
json={"description": description, "application": None, "scope": scope},
|
||||
headers=req.headers,
|
||||
)
|
||||
if resp.ok:
|
||||
result = resp.json()
|
||||
@@ -201,9 +177,9 @@ class Base(Page):
|
||||
|
||||
def load_session(self, username='', password=''):
|
||||
default_cred = config.credentials.default
|
||||
self.connection.login(username=username or default_cred.username,
|
||||
password=password or default_cred.password,
|
||||
**self.connection.get_session_requirements())
|
||||
self.connection.login(
|
||||
username=username or default_cred.username, password=password or default_cred.password, **self.connection.get_session_requirements()
|
||||
)
|
||||
return self
|
||||
|
||||
def cleanup(self):
|
||||
|
||||
@@ -4,22 +4,17 @@ from . import page
|
||||
|
||||
|
||||
class Config(base.Base):
|
||||
|
||||
@property
|
||||
def is_aws_license(self):
|
||||
return self.license_info.get('is_aws', False) or \
|
||||
'ami-id' in self.license_info or \
|
||||
'instance-id' in self.license_info
|
||||
return self.license_info.get('is_aws', False) or 'ami-id' in self.license_info or 'instance-id' in self.license_info
|
||||
|
||||
@property
|
||||
def is_valid_license(self):
|
||||
return self.license_info.get('valid_key', False) and \
|
||||
'instance_count' in self.license_info
|
||||
return self.license_info.get('valid_key', False) and 'instance_count' in self.license_info
|
||||
|
||||
@property
|
||||
def is_trial_license(self):
|
||||
return self.is_valid_license and \
|
||||
self.license_info.get('trial', False)
|
||||
return self.is_valid_license and self.license_info.get('trial', False)
|
||||
|
||||
@property
|
||||
def is_awx_license(self):
|
||||
@@ -27,8 +22,7 @@ class Config(base.Base):
|
||||
|
||||
@property
|
||||
def is_enterprise_license(self):
|
||||
return self.is_valid_license and \
|
||||
self.license_info.get('license_type', None) == 'enterprise'
|
||||
return self.is_valid_license and self.license_info.get('license_type', None) == 'enterprise'
|
||||
|
||||
@property
|
||||
def features(self):
|
||||
@@ -37,7 +31,6 @@ class Config(base.Base):
|
||||
|
||||
|
||||
class ConfigAttach(page.Page):
|
||||
|
||||
def attach(self, **kwargs):
|
||||
return self.post(json=kwargs).json
|
||||
|
||||
|
||||
@@ -16,5 +16,4 @@ class CredentialInputSources(page.PageList, CredentialInputSource):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.credential_input_sources,
|
||||
resources.related_input_sources], CredentialInputSources)
|
||||
page.register_page([resources.credential_input_sources, resources.related_input_sources], CredentialInputSources)
|
||||
|
||||
@@ -44,7 +44,8 @@ credential_input_fields = (
|
||||
'tenant',
|
||||
'username',
|
||||
'vault_password',
|
||||
'vault_id')
|
||||
'vault_id',
|
||||
)
|
||||
|
||||
|
||||
def generate_private_key():
|
||||
@@ -52,15 +53,9 @@ def generate_private_key():
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
|
||||
key = rsa.generate_private_key(
|
||||
public_exponent=65537,
|
||||
key_size=4096,
|
||||
backend=default_backend()
|
||||
)
|
||||
key = rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend())
|
||||
return key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()
|
||||
).decode('utf-8')
|
||||
|
||||
|
||||
@@ -98,11 +93,10 @@ credential_type_name_to_config_kind_map = {
|
||||
'source control': 'scm',
|
||||
'machine': 'ssh',
|
||||
'vault': 'vault',
|
||||
'vmware vcenter': 'vmware'}
|
||||
'vmware vcenter': 'vmware',
|
||||
}
|
||||
|
||||
config_kind_to_credential_type_name_map = {
|
||||
kind: name
|
||||
for name, kind in credential_type_name_to_config_kind_map.items()}
|
||||
config_kind_to_credential_type_name_map = {kind: name for name, kind in credential_type_name_to_config_kind_map.items()}
|
||||
|
||||
|
||||
def kind_and_config_cred_from_credential_type(credential_type):
|
||||
@@ -115,8 +109,7 @@ def kind_and_config_cred_from_credential_type(credential_type):
|
||||
config_cred = config.credentials.network
|
||||
kind = 'net'
|
||||
elif credential_type.kind == 'cloud':
|
||||
kind = credential_type_name_to_config_kind_map[credential_type.name.lower(
|
||||
)]
|
||||
kind = credential_type_name_to_config_kind_map[credential_type.name.lower()]
|
||||
config_kind = kind if kind != 'azure_rm' else 'azure'
|
||||
config_cred = config.credentials.cloud[config_kind]
|
||||
else:
|
||||
@@ -127,11 +120,8 @@ def kind_and_config_cred_from_credential_type(credential_type):
|
||||
return kind, PseudoNamespace()
|
||||
|
||||
|
||||
def get_payload_field_and_value_from_kwargs_or_config_cred(
|
||||
field, kind, kwargs, config_cred):
|
||||
if field in (
|
||||
'project_id',
|
||||
'project_name'): # Needed to prevent Project kwarg collision
|
||||
def get_payload_field_and_value_from_kwargs_or_config_cred(field, kind, kwargs, config_cred):
|
||||
if field in ('project_id', 'project_name'): # Needed to prevent Project kwarg collision
|
||||
config_field = 'project'
|
||||
elif field == 'subscription' and 'azure' in kind:
|
||||
config_field = 'subscription_id'
|
||||
@@ -159,10 +149,8 @@ class CredentialType(HasCreate, base.Base):
|
||||
|
||||
def payload(self, kind='cloud', **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'CredentialType - {}'.format(
|
||||
random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
kind=kind)
|
||||
name=kwargs.get('name') or 'CredentialType - {}'.format(random_title()), description=kwargs.get('description') or random_title(10), kind=kind
|
||||
)
|
||||
fields = ('inputs', 'injectors')
|
||||
update_payload(payload, fields, kwargs)
|
||||
return payload
|
||||
@@ -174,17 +162,13 @@ class CredentialType(HasCreate, base.Base):
|
||||
|
||||
def create(self, kind='cloud', **kwargs):
|
||||
payload = self.create_payload(kind=kind, **kwargs)
|
||||
return self.update_identity(
|
||||
CredentialTypes(
|
||||
self.connection).post(payload))
|
||||
return self.update_identity(CredentialTypes(self.connection).post(payload))
|
||||
|
||||
def test(self, data):
|
||||
"""Test the credential type endpoint."""
|
||||
response = self.connection.post(urljoin(str(self.url), 'test/'), data)
|
||||
exception = exception_from_status_code(response.status_code)
|
||||
exc_str = "%s (%s) received" % (
|
||||
http.responses[response.status_code], response.status_code
|
||||
)
|
||||
exc_str = "%s (%s) received" % (http.responses[response.status_code], response.status_code)
|
||||
if exception:
|
||||
raise exception(exc_str, response.json())
|
||||
elif response.status_code == http.FORBIDDEN:
|
||||
@@ -192,8 +176,7 @@ class CredentialType(HasCreate, base.Base):
|
||||
return response
|
||||
|
||||
|
||||
page.register_page([resources.credential_type,
|
||||
(resources.credential_types, 'post')], CredentialType)
|
||||
page.register_page([resources.credential_type, (resources.credential_types, 'post')], CredentialType)
|
||||
|
||||
|
||||
class CredentialTypes(page.PageList, CredentialType):
|
||||
@@ -210,27 +193,19 @@ class Credential(HasCopy, HasCreate, base.Base):
|
||||
optional_dependencies = [Organization, User, Team]
|
||||
NATURAL_KEY = ('organization', 'name', 'credential_type')
|
||||
|
||||
def payload(
|
||||
self,
|
||||
credential_type,
|
||||
user=None,
|
||||
team=None,
|
||||
organization=None,
|
||||
inputs=None,
|
||||
**kwargs):
|
||||
def payload(self, credential_type, user=None, team=None, organization=None, inputs=None, **kwargs):
|
||||
if not any((user, team, organization)):
|
||||
raise TypeError(
|
||||
'{0.__class__.__name__} requires user, team, and/or organization instances.'.format(self))
|
||||
raise TypeError('{0.__class__.__name__} requires user, team, and/or organization instances.'.format(self))
|
||||
|
||||
if inputs is None:
|
||||
inputs = {}
|
||||
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Credential - {}'.format(
|
||||
random_title()),
|
||||
name=kwargs.get('name') or 'Credential - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
credential_type=credential_type.id,
|
||||
inputs=inputs)
|
||||
inputs=inputs,
|
||||
)
|
||||
if user:
|
||||
payload.user = user.id
|
||||
if team:
|
||||
@@ -238,38 +213,26 @@ class Credential(HasCopy, HasCreate, base.Base):
|
||||
if organization:
|
||||
payload.organization = organization.id
|
||||
|
||||
kind, config_cred = kind_and_config_cred_from_credential_type(
|
||||
credential_type)
|
||||
kind, config_cred = kind_and_config_cred_from_credential_type(credential_type)
|
||||
|
||||
for field in credential_input_fields:
|
||||
field, value = get_payload_field_and_value_from_kwargs_or_config_cred(
|
||||
field, kind, inputs or kwargs, config_cred)
|
||||
field, value = get_payload_field_and_value_from_kwargs_or_config_cred(field, kind, inputs or kwargs, config_cred)
|
||||
if value != not_provided:
|
||||
payload.inputs[field] = value
|
||||
|
||||
if kind == 'net':
|
||||
payload.inputs.authorize = inputs.get(
|
||||
'authorize', bool(inputs.get('authorize_password')))
|
||||
payload.inputs.authorize = inputs.get('authorize', bool(inputs.get('authorize_password')))
|
||||
|
||||
if kind in ('ssh', 'net') and 'ssh_key_data' not in payload.inputs:
|
||||
payload.inputs.ssh_key_data = inputs.get(
|
||||
'ssh_key_data', generate_private_key())
|
||||
payload.inputs.ssh_key_data = inputs.get('ssh_key_data', generate_private_key())
|
||||
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
credential_type=CredentialType,
|
||||
user=None,
|
||||
team=None,
|
||||
organization=Organization,
|
||||
inputs=None,
|
||||
**kwargs):
|
||||
def create_payload(self, credential_type=CredentialType, user=None, team=None, organization=Organization, inputs=None, **kwargs):
|
||||
if isinstance(credential_type, int):
|
||||
# if an int was passed, it is assumed to be the pk id of a
|
||||
# credential type
|
||||
credential_type = CredentialTypes(
|
||||
self.connection).get(id=credential_type).results.pop()
|
||||
credential_type = CredentialTypes(self.connection).get(id=credential_type).results.pop()
|
||||
|
||||
if credential_type == CredentialType:
|
||||
kind = kwargs.pop('kind', 'ssh')
|
||||
@@ -282,57 +245,29 @@ class Credential(HasCopy, HasCreate, base.Base):
|
||||
inputs = config.credentials.cloud['openstack']
|
||||
else:
|
||||
credential_type_name = config_kind_to_credential_type_name_map[kind]
|
||||
credential_type = CredentialTypes(
|
||||
self.connection).get(
|
||||
managed_by_tower=True,
|
||||
name__icontains=credential_type_name).results.pop()
|
||||
credential_type = CredentialTypes(self.connection).get(managed_by_tower=True, name__icontains=credential_type_name).results.pop()
|
||||
|
||||
credential_type, organization, user, team = filter_by_class(
|
||||
(credential_type, CredentialType), (organization, Organization), (user, User), (team, Team))
|
||||
credential_type, organization, user, team = filter_by_class((credential_type, CredentialType), (organization, Organization), (user, User), (team, Team))
|
||||
if not any((user, team, organization)):
|
||||
organization = Organization
|
||||
self.create_and_update_dependencies(
|
||||
credential_type, organization, user, team)
|
||||
self.create_and_update_dependencies(credential_type, organization, user, team)
|
||||
user = self.ds.user if user else None
|
||||
team = self.ds.team if team else None
|
||||
organization = self.ds.organization if organization else None
|
||||
|
||||
payload = self.payload(
|
||||
self.ds.credential_type,
|
||||
user=user,
|
||||
team=team,
|
||||
organization=organization,
|
||||
inputs=inputs,
|
||||
**kwargs)
|
||||
payload = self.payload(self.ds.credential_type, user=user, team=team, organization=organization, inputs=inputs, **kwargs)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
credential_type=CredentialType,
|
||||
user=None,
|
||||
team=None,
|
||||
organization=None,
|
||||
inputs=None,
|
||||
**kwargs):
|
||||
payload = self.create_payload(
|
||||
credential_type=credential_type,
|
||||
user=user,
|
||||
team=team,
|
||||
organization=organization,
|
||||
inputs=inputs,
|
||||
**kwargs)
|
||||
return self.update_identity(
|
||||
Credentials(
|
||||
self.connection)).post(payload)
|
||||
def create(self, credential_type=CredentialType, user=None, team=None, organization=None, inputs=None, **kwargs):
|
||||
payload = self.create_payload(credential_type=credential_type, user=user, team=team, organization=organization, inputs=inputs, **kwargs)
|
||||
return self.update_identity(Credentials(self.connection)).post(payload)
|
||||
|
||||
def test(self, data):
|
||||
"""Test the credential endpoint."""
|
||||
response = self.connection.post(urljoin(str(self.url), 'test/'), data)
|
||||
exception = exception_from_status_code(response.status_code)
|
||||
exc_str = "%s (%s) received" % (
|
||||
http.responses[response.status_code], response.status_code
|
||||
)
|
||||
exc_str = "%s (%s) received" % (http.responses[response.status_code], response.status_code)
|
||||
if exception:
|
||||
raise exception(exc_str, response.json())
|
||||
elif response.status_code == http.FORBIDDEN:
|
||||
@@ -343,11 +278,7 @@ class Credential(HasCopy, HasCreate, base.Base):
|
||||
def expected_passwords_needed_to_start(self):
|
||||
"""Return a list of expected passwords needed to start a job using this credential."""
|
||||
passwords = []
|
||||
for field in (
|
||||
'password',
|
||||
'become_password',
|
||||
'ssh_key_unlock',
|
||||
'vault_password'):
|
||||
for field in ('password', 'become_password', 'ssh_key_unlock', 'vault_password'):
|
||||
if getattr(self.inputs, field, None) == 'ASK':
|
||||
if field == 'password':
|
||||
passwords.append('ssh_password')
|
||||
@@ -356,9 +287,7 @@ class Credential(HasCopy, HasCreate, base.Base):
|
||||
return passwords
|
||||
|
||||
|
||||
page.register_page([resources.credential,
|
||||
(resources.credentials, 'post'),
|
||||
(resources.credential_copy, 'post')], Credential)
|
||||
page.register_page([resources.credential, (resources.credentials, 'post'), (resources.credential_copy, 'post')], Credential)
|
||||
|
||||
|
||||
class Credentials(page.PageList, Credential):
|
||||
@@ -366,9 +295,7 @@ class Credentials(page.PageList, Credential):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.credentials,
|
||||
resources.related_credentials],
|
||||
Credentials)
|
||||
page.register_page([resources.credentials, resources.related_credentials], Credentials)
|
||||
|
||||
|
||||
class CredentialCopy(base.Base):
|
||||
|
||||
@@ -46,14 +46,13 @@ class ExecutionEnvironment(HasCreate, HasCopy, base.Base):
|
||||
return payload
|
||||
|
||||
|
||||
page.register_page([resources.execution_environment,
|
||||
(resources.execution_environments, 'post'),
|
||||
(resources.organization_execution_environments, 'post')], ExecutionEnvironment)
|
||||
page.register_page(
|
||||
[resources.execution_environment, (resources.execution_environments, 'post'), (resources.organization_execution_environments, 'post')], ExecutionEnvironment
|
||||
)
|
||||
|
||||
|
||||
class ExecutionEnvironments(page.PageList, ExecutionEnvironment):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.execution_environments,
|
||||
resources.organization_execution_environments], ExecutionEnvironments)
|
||||
page.register_page([resources.execution_environments, resources.organization_execution_environments], ExecutionEnvironments)
|
||||
|
||||
@@ -7,7 +7,6 @@ from . import page
|
||||
|
||||
|
||||
class InstanceGroup(HasCreate, base.Base):
|
||||
|
||||
def add_instance(self, instance):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.instances.post(dict(id=instance.id))
|
||||
@@ -17,8 +16,7 @@ class InstanceGroup(HasCreate, base.Base):
|
||||
self.related.instances.post(dict(id=instance.id, disassociate=True))
|
||||
|
||||
def payload(self, **kwargs):
|
||||
payload = PseudoNamespace(name=kwargs.get('name') or
|
||||
'Instance Group - {}'.format(random_title()))
|
||||
payload = PseudoNamespace(name=kwargs.get('name') or 'Instance Group - {}'.format(random_title()))
|
||||
fields = ('policy_instance_percentage', 'policy_instance_minimum', 'policy_instance_list', 'is_container_group')
|
||||
update_payload(payload, fields, kwargs)
|
||||
|
||||
@@ -35,8 +33,7 @@ class InstanceGroup(HasCreate, base.Base):
|
||||
return self.update_identity(InstanceGroups(self.connection).post(payload))
|
||||
|
||||
|
||||
page.register_page([resources.instance_group,
|
||||
(resources.instance_groups, 'post')], InstanceGroup)
|
||||
page.register_page([resources.instance_group, (resources.instance_groups, 'post')], InstanceGroup)
|
||||
|
||||
|
||||
class InstanceGroups(page.PageList, InstanceGroup):
|
||||
@@ -44,5 +41,4 @@ class InstanceGroups(page.PageList, InstanceGroup):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.instance_groups,
|
||||
resources.related_instance_groups], InstanceGroups)
|
||||
page.register_page([resources.instance_groups, resources.related_instance_groups], InstanceGroups)
|
||||
|
||||
@@ -16,5 +16,4 @@ class Instances(page.PageList, Instance):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.instances,
|
||||
resources.related_instances], Instances)
|
||||
page.register_page([resources.instances, resources.related_instances], Instances)
|
||||
|
||||
@@ -2,23 +2,8 @@ import logging
|
||||
import json
|
||||
import re
|
||||
|
||||
from awxkit.api.pages import (
|
||||
Credential,
|
||||
Organization,
|
||||
Project,
|
||||
UnifiedJob,
|
||||
UnifiedJobTemplate
|
||||
)
|
||||
from awxkit.utils import (
|
||||
filter_by_class,
|
||||
random_title,
|
||||
update_payload,
|
||||
suppress,
|
||||
not_provided,
|
||||
PseudoNamespace,
|
||||
poll_until,
|
||||
random_utf8
|
||||
)
|
||||
from awxkit.api.pages import Credential, Organization, Project, UnifiedJob, UnifiedJobTemplate
|
||||
from awxkit.utils import filter_by_class, random_title, update_payload, suppress, not_provided, PseudoNamespace, poll_until, random_utf8
|
||||
from awxkit.api.mixins import DSAdapter, HasCreate, HasInstanceGroups, HasNotifications, HasVariables, HasCopy
|
||||
from awxkit.api.resources import resources
|
||||
import awxkit.exceptions as exc
|
||||
@@ -68,56 +53,31 @@ class Inventory(HasCopy, HasCreate, HasInstanceGroups, HasVariables, base.Base):
|
||||
|
||||
def payload(self, organization, **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Inventory - {}'.format(
|
||||
random_title()),
|
||||
name=kwargs.get('name') or 'Inventory - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
organization=organization.id)
|
||||
organization=organization.id,
|
||||
)
|
||||
|
||||
optional_fields = (
|
||||
'host_filter',
|
||||
'insights_credential',
|
||||
'kind',
|
||||
'variables')
|
||||
optional_fields = ('host_filter', 'insights_credential', 'kind', 'variables')
|
||||
|
||||
update_payload(payload, optional_fields, kwargs)
|
||||
|
||||
if 'variables' in payload and isinstance(payload.variables, dict):
|
||||
payload.variables = json.dumps(payload.variables)
|
||||
if 'insights_credential' in payload and isinstance(
|
||||
payload.insights_credential, Credential):
|
||||
if 'insights_credential' in payload and isinstance(payload.insights_credential, Credential):
|
||||
payload.insights_credential = payload.insights_credential.id
|
||||
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
organization=Organization,
|
||||
**kwargs):
|
||||
def create_payload(self, name='', description='', organization=Organization, **kwargs):
|
||||
self.create_and_update_dependencies(organization)
|
||||
payload = self.payload(
|
||||
name=name,
|
||||
description=description,
|
||||
organization=self.ds.organization,
|
||||
**kwargs)
|
||||
payload = self.payload(name=name, description=description, organization=self.ds.organization, **kwargs)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
organization=Organization,
|
||||
**kwargs):
|
||||
payload = self.create_payload(
|
||||
name=name,
|
||||
description=description,
|
||||
organization=organization,
|
||||
**kwargs)
|
||||
return self.update_identity(
|
||||
Inventories(
|
||||
self.connection).post(payload))
|
||||
def create(self, name='', description='', organization=Organization, **kwargs):
|
||||
payload = self.create_payload(name=name, description=description, organization=organization, **kwargs)
|
||||
return self.update_identity(Inventories(self.connection).post(payload))
|
||||
|
||||
def add_host(self, host=None):
|
||||
if host is None:
|
||||
@@ -135,17 +95,16 @@ class Inventory(HasCopy, HasCreate, HasInstanceGroups, HasVariables, base.Base):
|
||||
self.get()
|
||||
except exc.NotFound:
|
||||
return True
|
||||
|
||||
poll_until(_wait, interval=1, timeout=60)
|
||||
|
||||
def update_inventory_sources(self, wait=False):
|
||||
response = self.related.update_inventory_sources.post()
|
||||
source_ids = [entry['inventory_source']
|
||||
for entry in response if entry['status'] == 'started']
|
||||
source_ids = [entry['inventory_source'] for entry in response if entry['status'] == 'started']
|
||||
|
||||
inv_updates = []
|
||||
for source_id in source_ids:
|
||||
inv_source = self.related.inventory_sources.get(
|
||||
id=source_id).results.pop()
|
||||
inv_source = self.related.inventory_sources.get(id=source_id).results.pop()
|
||||
inv_updates.append(inv_source.related.current_job.get())
|
||||
|
||||
if wait:
|
||||
@@ -154,9 +113,7 @@ class Inventory(HasCopy, HasCreate, HasInstanceGroups, HasVariables, base.Base):
|
||||
return inv_updates
|
||||
|
||||
|
||||
page.register_page([resources.inventory,
|
||||
(resources.inventories, 'post'),
|
||||
(resources.inventory_copy, 'post')], Inventory)
|
||||
page.register_page([resources.inventory, (resources.inventories, 'post'), (resources.inventory_copy, 'post')], Inventory)
|
||||
|
||||
|
||||
class Inventories(page.PageList, Inventory):
|
||||
@@ -164,8 +121,7 @@ class Inventories(page.PageList, Inventory):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.inventories,
|
||||
resources.related_inventories], Inventories)
|
||||
page.register_page([resources.inventories, resources.related_inventories], Inventories)
|
||||
|
||||
|
||||
class InventoryScript(HasCopy, HasCreate, base.Base):
|
||||
@@ -174,77 +130,48 @@ class InventoryScript(HasCopy, HasCreate, base.Base):
|
||||
|
||||
def payload(self, organization, **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Inventory Script - {}'.format(
|
||||
random_title()),
|
||||
name=kwargs.get('name') or 'Inventory Script - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
organization=organization.id,
|
||||
script=kwargs.get('script') or self._generate_script())
|
||||
script=kwargs.get('script') or self._generate_script(),
|
||||
)
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
organization=Organization,
|
||||
script='',
|
||||
**kwargs):
|
||||
def create_payload(self, name='', description='', organization=Organization, script='', **kwargs):
|
||||
self.create_and_update_dependencies(organization)
|
||||
payload = self.payload(
|
||||
name=name,
|
||||
description=description,
|
||||
organization=self.ds.organization,
|
||||
script=script,
|
||||
**kwargs)
|
||||
payload = self.payload(name=name, description=description, organization=self.ds.organization, script=script, **kwargs)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
organization=Organization,
|
||||
script='',
|
||||
**kwargs):
|
||||
payload = self.create_payload(
|
||||
name=name,
|
||||
description=description,
|
||||
organization=organization,
|
||||
script=script,
|
||||
**kwargs)
|
||||
return self.update_identity(
|
||||
InventoryScripts(
|
||||
self.connection).post(payload))
|
||||
def create(self, name='', description='', organization=Organization, script='', **kwargs):
|
||||
payload = self.create_payload(name=name, description=description, organization=organization, script=script, **kwargs)
|
||||
return self.update_identity(InventoryScripts(self.connection).post(payload))
|
||||
|
||||
def _generate_script(self):
|
||||
script = '\n'.join([
|
||||
'#!/usr/bin/env python',
|
||||
'# -*- coding: utf-8 -*-',
|
||||
'import json',
|
||||
'inventory = dict()',
|
||||
'inventory["{0}"] = dict()',
|
||||
'inventory["{0}"]["hosts"] = list()',
|
||||
'inventory["{0}"]["hosts"].append("{1}")',
|
||||
'inventory["{0}"]["hosts"].append("{2}")',
|
||||
'inventory["{0}"]["hosts"].append("{3}")',
|
||||
'inventory["{0}"]["hosts"].append("{4}")',
|
||||
'inventory["{0}"]["hosts"].append("{5}")',
|
||||
'inventory["{0}"]["vars"] = dict(ansible_host="127.0.0.1", ansible_connection="local")',
|
||||
'print(json.dumps(inventory))'
|
||||
])
|
||||
script = '\n'.join(
|
||||
[
|
||||
'#!/usr/bin/env python',
|
||||
'# -*- coding: utf-8 -*-',
|
||||
'import json',
|
||||
'inventory = dict()',
|
||||
'inventory["{0}"] = dict()',
|
||||
'inventory["{0}"]["hosts"] = list()',
|
||||
'inventory["{0}"]["hosts"].append("{1}")',
|
||||
'inventory["{0}"]["hosts"].append("{2}")',
|
||||
'inventory["{0}"]["hosts"].append("{3}")',
|
||||
'inventory["{0}"]["hosts"].append("{4}")',
|
||||
'inventory["{0}"]["hosts"].append("{5}")',
|
||||
'inventory["{0}"]["vars"] = dict(ansible_host="127.0.0.1", ansible_connection="local")',
|
||||
'print(json.dumps(inventory))',
|
||||
]
|
||||
)
|
||||
group_name = re.sub(r"[\']", "", "group_{}".format(random_title(non_ascii=False)))
|
||||
host_names = [
|
||||
re.sub(
|
||||
r"[\':]",
|
||||
"",
|
||||
"host_{}".format(
|
||||
random_utf8())) for _ in range(5)]
|
||||
host_names = [re.sub(r"[\':]", "", "host_{}".format(random_utf8())) for _ in range(5)]
|
||||
|
||||
return script.format(group_name, *host_names)
|
||||
|
||||
|
||||
page.register_page([resources.inventory_script,
|
||||
(resources.inventory_scripts, 'post'),
|
||||
(resources.inventory_script_copy, 'post')], InventoryScript)
|
||||
page.register_page([resources.inventory_script, (resources.inventory_scripts, 'post'), (resources.inventory_script_copy, 'post')], InventoryScript)
|
||||
|
||||
|
||||
class InventoryScripts(page.PageList, InventoryScript):
|
||||
@@ -272,11 +199,10 @@ class Group(HasCreate, HasVariables, base.Base):
|
||||
|
||||
def payload(self, inventory, credential=None, **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Group{}'.format(
|
||||
random_title(
|
||||
non_ascii=False)),
|
||||
name=kwargs.get('name') or 'Group{}'.format(random_title(non_ascii=False)),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
inventory=inventory.id)
|
||||
inventory=inventory.id,
|
||||
)
|
||||
|
||||
if credential:
|
||||
payload.credential = credential.id
|
||||
@@ -288,38 +214,19 @@ class Group(HasCreate, HasVariables, base.Base):
|
||||
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
inventory=Inventory,
|
||||
credential=None,
|
||||
source_script=None,
|
||||
**kwargs):
|
||||
credential, source_script = filter_by_class(
|
||||
(credential, Credential), (source_script, InventoryScript))
|
||||
self.create_and_update_dependencies(
|
||||
inventory, credential, source_script)
|
||||
def create_payload(self, name='', description='', inventory=Inventory, credential=None, source_script=None, **kwargs):
|
||||
credential, source_script = filter_by_class((credential, Credential), (source_script, InventoryScript))
|
||||
self.create_and_update_dependencies(inventory, credential, source_script)
|
||||
credential = self.ds.credential if credential else None
|
||||
payload = self.payload(
|
||||
inventory=self.ds.inventory,
|
||||
credential=credential,
|
||||
name=name,
|
||||
description=description,
|
||||
**kwargs)
|
||||
payload = self.payload(inventory=self.ds.inventory, credential=credential, name=name, description=description, **kwargs)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(self, name='', description='', inventory=Inventory, **kwargs):
|
||||
payload = self.create_payload(
|
||||
name=name,
|
||||
description=description,
|
||||
inventory=inventory,
|
||||
**kwargs)
|
||||
payload = self.create_payload(name=name, description=description, inventory=inventory, **kwargs)
|
||||
|
||||
parent = kwargs.get('parent', None) # parent must be a Group instance
|
||||
resource = parent.related.children if parent else Groups(
|
||||
self.connection)
|
||||
resource = parent.related.children if parent else Groups(self.connection)
|
||||
return self.update_identity(resource.post(payload))
|
||||
|
||||
def add_host(self, host=None):
|
||||
@@ -348,8 +255,7 @@ class Group(HasCreate, HasVariables, base.Base):
|
||||
self.related.children.post(dict(id=group.id, disassociate=True))
|
||||
|
||||
|
||||
page.register_page([resources.group,
|
||||
(resources.groups, 'post')], Group)
|
||||
page.register_page([resources.group, (resources.groups, 'post')], Group)
|
||||
|
||||
|
||||
class Groups(page.PageList, Group):
|
||||
@@ -357,12 +263,17 @@ class Groups(page.PageList, Group):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.groups,
|
||||
resources.host_groups,
|
||||
resources.inventory_related_groups,
|
||||
resources.inventory_related_root_groups,
|
||||
resources.group_children,
|
||||
resources.group_potential_children], Groups)
|
||||
page.register_page(
|
||||
[
|
||||
resources.groups,
|
||||
resources.host_groups,
|
||||
resources.inventory_related_groups,
|
||||
resources.inventory_related_root_groups,
|
||||
resources.group_children,
|
||||
resources.group_potential_children,
|
||||
],
|
||||
Groups,
|
||||
)
|
||||
|
||||
|
||||
class Host(HasCreate, HasVariables, base.Base):
|
||||
@@ -372,11 +283,10 @@ class Host(HasCreate, HasVariables, base.Base):
|
||||
|
||||
def payload(self, inventory, **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Host{}'.format(
|
||||
random_title(
|
||||
non_ascii=False)),
|
||||
name=kwargs.get('name') or 'Host{}'.format(random_title(non_ascii=False)),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
inventory=inventory.id)
|
||||
inventory=inventory.id,
|
||||
)
|
||||
|
||||
optional_fields = ('enabled', 'instance_id')
|
||||
|
||||
@@ -385,9 +295,7 @@ class Host(HasCreate, HasVariables, base.Base):
|
||||
variables = kwargs.get('variables', not_provided)
|
||||
|
||||
if variables is None:
|
||||
variables = dict(
|
||||
ansible_host='127.0.0.1',
|
||||
ansible_connection='local')
|
||||
variables = dict(ansible_host='127.0.0.1', ansible_connection='local')
|
||||
|
||||
if variables != not_provided:
|
||||
if isinstance(variables, dict):
|
||||
@@ -396,42 +304,18 @@ class Host(HasCreate, HasVariables, base.Base):
|
||||
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
variables=None,
|
||||
inventory=Inventory,
|
||||
**kwargs):
|
||||
self.create_and_update_dependencies(
|
||||
*filter_by_class((inventory, Inventory)))
|
||||
payload = self.payload(
|
||||
inventory=self.ds.inventory,
|
||||
name=name,
|
||||
description=description,
|
||||
variables=variables,
|
||||
**kwargs)
|
||||
def create_payload(self, name='', description='', variables=None, inventory=Inventory, **kwargs):
|
||||
self.create_and_update_dependencies(*filter_by_class((inventory, Inventory)))
|
||||
payload = self.payload(inventory=self.ds.inventory, name=name, description=description, variables=variables, **kwargs)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
variables=None,
|
||||
inventory=Inventory,
|
||||
**kwargs):
|
||||
payload = self.create_payload(
|
||||
name=name,
|
||||
description=description,
|
||||
variables=variables,
|
||||
inventory=inventory,
|
||||
**kwargs)
|
||||
def create(self, name='', description='', variables=None, inventory=Inventory, **kwargs):
|
||||
payload = self.create_payload(name=name, description=description, variables=variables, inventory=inventory, **kwargs)
|
||||
return self.update_identity(Hosts(self.connection).post(payload))
|
||||
|
||||
|
||||
page.register_page([resources.host,
|
||||
(resources.hosts, 'post')], Host)
|
||||
page.register_page([resources.host, (resources.hosts, 'post')], Host)
|
||||
|
||||
|
||||
class Hosts(page.PageList, Host):
|
||||
@@ -439,10 +323,7 @@ class Hosts(page.PageList, Host):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.hosts,
|
||||
resources.group_related_hosts,
|
||||
resources.inventory_related_hosts,
|
||||
resources.inventory_sources_related_hosts], Hosts)
|
||||
page.register_page([resources.hosts, resources.group_related_hosts, resources.inventory_related_hosts, resources.inventory_sources_related_hosts], Hosts)
|
||||
|
||||
|
||||
class FactVersion(base.Base):
|
||||
@@ -454,7 +335,6 @@ page.register_page(resources.host_related_fact_version, FactVersion)
|
||||
|
||||
|
||||
class FactVersions(page.PageList, FactVersion):
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
return len(self.results)
|
||||
@@ -478,20 +358,13 @@ class InventorySource(HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
optional_dependencies = [Credential, InventoryScript, Project]
|
||||
NATURAL_KEY = ('organization', 'name', 'inventory')
|
||||
|
||||
def payload(
|
||||
self,
|
||||
inventory,
|
||||
source='custom',
|
||||
credential=None,
|
||||
source_script=None,
|
||||
project=None,
|
||||
**kwargs):
|
||||
def payload(self, inventory, source='custom', credential=None, source_script=None, project=None, **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'InventorySource - {}'.format(
|
||||
random_title()),
|
||||
name=kwargs.get('name') or 'InventorySource - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
inventory=inventory.id,
|
||||
source=source)
|
||||
source=source,
|
||||
)
|
||||
|
||||
if credential:
|
||||
payload.credential = credential.id
|
||||
@@ -509,22 +382,16 @@ class InventorySource(HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
'update_cache_timeout',
|
||||
'update_on_launch',
|
||||
'update_on_project_update',
|
||||
'verbosity')
|
||||
'verbosity',
|
||||
)
|
||||
|
||||
update_payload(payload, optional_fields, kwargs)
|
||||
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
source='custom',
|
||||
inventory=Inventory,
|
||||
credential=None,
|
||||
source_script=InventoryScript,
|
||||
project=None,
|
||||
**kwargs):
|
||||
self, name='', description='', source='custom', inventory=Inventory, credential=None, source_script=InventoryScript, project=None, **kwargs
|
||||
):
|
||||
if source != 'custom' and source_script == InventoryScript:
|
||||
source_script = None
|
||||
if source == 'scm':
|
||||
@@ -532,12 +399,10 @@ class InventorySource(HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
if project is None:
|
||||
project = Project
|
||||
|
||||
inventory, credential, source_script, project = filter_by_class((inventory, Inventory),
|
||||
(credential, Credential),
|
||||
(source_script, InventoryScript),
|
||||
(project, Project))
|
||||
self.create_and_update_dependencies(
|
||||
inventory, credential, source_script, project)
|
||||
inventory, credential, source_script, project = filter_by_class(
|
||||
(inventory, Inventory), (credential, Credential), (source_script, InventoryScript), (project, Project)
|
||||
)
|
||||
self.create_and_update_dependencies(inventory, credential, source_script, project)
|
||||
|
||||
if credential:
|
||||
credential = self.ds.credential
|
||||
@@ -554,20 +419,12 @@ class InventorySource(HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
project=project,
|
||||
name=name,
|
||||
description=description,
|
||||
**kwargs)
|
||||
**kwargs
|
||||
)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
source='custom',
|
||||
inventory=Inventory,
|
||||
credential=None,
|
||||
source_script=InventoryScript,
|
||||
project=None,
|
||||
**kwargs):
|
||||
def create(self, name='', description='', source='custom', inventory=Inventory, credential=None, source_script=InventoryScript, project=None, **kwargs):
|
||||
payload = self.create_payload(
|
||||
name=name,
|
||||
description=description,
|
||||
@@ -576,10 +433,9 @@ class InventorySource(HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
credential=credential,
|
||||
source_script=source_script,
|
||||
project=project,
|
||||
**kwargs)
|
||||
return self.update_identity(
|
||||
InventorySources(
|
||||
self.connection).post(payload))
|
||||
**kwargs
|
||||
)
|
||||
return self.update_identity(InventorySources(self.connection).post(payload))
|
||||
|
||||
def update(self):
|
||||
"""Update the inventory_source using related->update endpoint"""
|
||||
@@ -587,45 +443,37 @@ class InventorySource(HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
update_pg = self.get_related('update')
|
||||
|
||||
# assert can_update == True
|
||||
assert update_pg.can_update, \
|
||||
"The specified inventory_source (id:%s) is not able to update (can_update:%s)" % \
|
||||
(self.id, update_pg.can_update)
|
||||
assert update_pg.can_update, "The specified inventory_source (id:%s) is not able to update (can_update:%s)" % (self.id, update_pg.can_update)
|
||||
|
||||
# start the inventory_update
|
||||
result = update_pg.post()
|
||||
|
||||
# assert JSON response
|
||||
assert 'inventory_update' in result.json, \
|
||||
"Unexpected JSON response when starting an inventory_update.\n%s" % \
|
||||
json.dumps(result.json, indent=2)
|
||||
assert 'inventory_update' in result.json, "Unexpected JSON response when starting an inventory_update.\n%s" % json.dumps(result.json, indent=2)
|
||||
|
||||
# locate and return the inventory_update
|
||||
jobs_pg = self.related.inventory_updates.get(
|
||||
id=result.json['inventory_update'])
|
||||
assert jobs_pg.count == 1, \
|
||||
"An inventory_update started (id:%s) but job not found in response at %s/inventory_updates/" % \
|
||||
(result.json['inventory_update'], self.url)
|
||||
jobs_pg = self.related.inventory_updates.get(id=result.json['inventory_update'])
|
||||
assert jobs_pg.count == 1, "An inventory_update started (id:%s) but job not found in response at %s/inventory_updates/" % (
|
||||
result.json['inventory_update'],
|
||||
self.url,
|
||||
)
|
||||
return jobs_pg.results[0]
|
||||
|
||||
@property
|
||||
def is_successful(self):
|
||||
"""An inventory_source is considered successful when source != "" and super().is_successful ."""
|
||||
return self.source != "" and super(
|
||||
InventorySource, self).is_successful
|
||||
return self.source != "" and super(InventorySource, self).is_successful
|
||||
|
||||
def add_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
dict(id=credential.id, associate=True))
|
||||
self.related.credentials.post(dict(id=credential.id, associate=True))
|
||||
|
||||
def remove_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
dict(id=credential.id, disassociate=True))
|
||||
self.related.credentials.post(dict(id=credential.id, disassociate=True))
|
||||
|
||||
|
||||
page.register_page([resources.inventory_source,
|
||||
(resources.inventory_sources, 'post')], InventorySource)
|
||||
page.register_page([resources.inventory_source, (resources.inventory_sources, 'post')], InventorySource)
|
||||
|
||||
|
||||
class InventorySources(page.PageList, InventorySource):
|
||||
@@ -633,9 +481,7 @@ class InventorySources(page.PageList, InventorySource):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.inventory_sources,
|
||||
resources.related_inventory_sources],
|
||||
InventorySources)
|
||||
page.register_page([resources.inventory_sources, resources.related_inventory_sources], InventorySources)
|
||||
|
||||
|
||||
class InventorySourceGroups(page.PageList, Group):
|
||||
@@ -643,9 +489,7 @@ class InventorySourceGroups(page.PageList, Group):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page(
|
||||
resources.inventory_sources_related_groups,
|
||||
InventorySourceGroups)
|
||||
page.register_page(resources.inventory_sources_related_groups, InventorySourceGroups)
|
||||
|
||||
|
||||
class InventorySourceUpdate(base.Base):
|
||||
@@ -653,9 +497,7 @@ class InventorySourceUpdate(base.Base):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.inventory_sources_related_update,
|
||||
resources.inventory_related_update_inventory_sources],
|
||||
InventorySourceUpdate)
|
||||
page.register_page([resources.inventory_sources_related_update, resources.inventory_related_update_inventory_sources], InventorySourceUpdate)
|
||||
|
||||
|
||||
class InventoryUpdate(UnifiedJob):
|
||||
@@ -671,10 +513,7 @@ class InventoryUpdates(page.PageList, InventoryUpdate):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.inventory_updates,
|
||||
resources.inventory_source_updates,
|
||||
resources.project_update_scm_inventory_updates],
|
||||
InventoryUpdates)
|
||||
page.register_page([resources.inventory_updates, resources.inventory_source_updates, resources.project_update_scm_inventory_updates], InventoryUpdates)
|
||||
|
||||
|
||||
class InventoryUpdateCancel(base.Base):
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import json
|
||||
|
||||
from awxkit.utils import (
|
||||
filter_by_class,
|
||||
not_provided,
|
||||
random_title,
|
||||
suppress,
|
||||
update_payload,
|
||||
set_payload_foreign_key_args,
|
||||
PseudoNamespace)
|
||||
from awxkit.utils import filter_by_class, not_provided, random_title, suppress, update_payload, set_payload_foreign_key_args, PseudoNamespace
|
||||
from awxkit.api.pages import Credential, Inventory, Project, UnifiedJobTemplate
|
||||
from awxkit.api.mixins import HasCreate, HasInstanceGroups, HasNotifications, HasSurvey, HasCopy, DSAdapter
|
||||
from awxkit.api.resources import resources
|
||||
@@ -16,13 +9,7 @@ from . import base
|
||||
from . import page
|
||||
|
||||
|
||||
class JobTemplate(
|
||||
HasCopy,
|
||||
HasCreate,
|
||||
HasInstanceGroups,
|
||||
HasNotifications,
|
||||
HasSurvey,
|
||||
UnifiedJobTemplate):
|
||||
class JobTemplate(HasCopy, HasCreate, HasInstanceGroups, HasNotifications, HasSurvey, UnifiedJobTemplate):
|
||||
|
||||
optional_dependencies = [Inventory, Credential, Project]
|
||||
NATURAL_KEY = ('organization', 'name')
|
||||
@@ -38,16 +25,13 @@ class JobTemplate(
|
||||
# return job
|
||||
if result.json['type'] == 'job':
|
||||
jobs_pg = self.get_related('jobs', id=result.json['job'])
|
||||
assert jobs_pg.count == 1, \
|
||||
"job_template launched (id:%s) but job not found in response at %s/jobs/" % \
|
||||
(result.json['job'], self.url)
|
||||
assert jobs_pg.count == 1, "job_template launched (id:%s) but job not found in response at %s/jobs/" % (result.json['job'], self.url)
|
||||
return jobs_pg.results[0]
|
||||
elif result.json['type'] == 'workflow_job':
|
||||
slice_workflow_jobs = self.get_related(
|
||||
'slice_workflow_jobs', id=result.json['id'])
|
||||
assert slice_workflow_jobs.count == 1, (
|
||||
"job_template launched sliced job (id:%s) but not found in related %s/slice_workflow_jobs/" %
|
||||
(result.json['id'], self.url)
|
||||
slice_workflow_jobs = self.get_related('slice_workflow_jobs', id=result.json['id'])
|
||||
assert slice_workflow_jobs.count == 1, "job_template launched sliced job (id:%s) but not found in related %s/slice_workflow_jobs/" % (
|
||||
result.json['id'],
|
||||
self.url,
|
||||
)
|
||||
return slice_workflow_jobs.results[0]
|
||||
else:
|
||||
@@ -56,10 +40,7 @@ class JobTemplate(
|
||||
def payload(self, job_type='run', playbook='ping.yml', **kwargs):
|
||||
name = kwargs.get('name') or 'JobTemplate - {}'.format(random_title())
|
||||
description = kwargs.get('description') or random_title(10)
|
||||
payload = PseudoNamespace(
|
||||
name=name,
|
||||
description=description,
|
||||
job_type=job_type)
|
||||
payload = PseudoNamespace(name=name, description=description, job_type=job_type)
|
||||
|
||||
optional_fields = (
|
||||
'ask_scm_branch_on_launch',
|
||||
@@ -90,7 +71,8 @@ class JobTemplate(
|
||||
'job_slice_count',
|
||||
'webhook_service',
|
||||
'webhook_credential',
|
||||
'scm_branch')
|
||||
'scm_branch',
|
||||
)
|
||||
|
||||
update_payload(payload, optional_fields, kwargs)
|
||||
|
||||
@@ -113,94 +95,53 @@ class JobTemplate(
|
||||
with suppress(exc.NoContent):
|
||||
self.related.labels.post(label)
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
job_type='run',
|
||||
playbook='ping.yml',
|
||||
credential=Credential,
|
||||
inventory=Inventory,
|
||||
project=None,
|
||||
**kwargs):
|
||||
def create_payload(self, name='', description='', job_type='run', playbook='ping.yml', credential=Credential, inventory=Inventory, project=None, **kwargs):
|
||||
if not project:
|
||||
project = Project
|
||||
if not inventory and not kwargs.get('ask_inventory_on_launch', False):
|
||||
inventory = Inventory
|
||||
|
||||
self.create_and_update_dependencies(
|
||||
*
|
||||
filter_by_class(
|
||||
(credential,
|
||||
Credential),
|
||||
(inventory,
|
||||
Inventory),
|
||||
(project,
|
||||
Project)))
|
||||
self.create_and_update_dependencies(*filter_by_class((credential, Credential), (inventory, Inventory), (project, Project)))
|
||||
project = self.ds.project if project else None
|
||||
inventory = self.ds.inventory if inventory else None
|
||||
credential = self.ds.credential if credential else None
|
||||
|
||||
payload = self.payload(
|
||||
name=name,
|
||||
description=description,
|
||||
job_type=job_type,
|
||||
playbook=playbook,
|
||||
credential=credential,
|
||||
inventory=inventory,
|
||||
project=project,
|
||||
**kwargs)
|
||||
name=name, description=description, job_type=job_type, playbook=playbook, credential=credential, inventory=inventory, project=project, **kwargs
|
||||
)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload, credential
|
||||
|
||||
def create(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
job_type='run',
|
||||
playbook='ping.yml',
|
||||
credential=Credential,
|
||||
inventory=Inventory,
|
||||
project=None,
|
||||
**kwargs):
|
||||
payload, credential = self.create_payload(name=name, description=description, job_type=job_type,
|
||||
playbook=playbook, credential=credential, inventory=inventory,
|
||||
project=project, **kwargs)
|
||||
ret = self.update_identity(
|
||||
JobTemplates(
|
||||
self.connection).post(payload))
|
||||
def create(self, name='', description='', job_type='run', playbook='ping.yml', credential=Credential, inventory=Inventory, project=None, **kwargs):
|
||||
payload, credential = self.create_payload(
|
||||
name=name, description=description, job_type=job_type, playbook=playbook, credential=credential, inventory=inventory, project=project, **kwargs
|
||||
)
|
||||
ret = self.update_identity(JobTemplates(self.connection).post(payload))
|
||||
if credential:
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(dict(id=credential.id))
|
||||
if 'vault_credential' in kwargs:
|
||||
with suppress(exc.NoContent):
|
||||
if not isinstance(kwargs['vault_credential'], int):
|
||||
raise ValueError(
|
||||
"Expected 'vault_credential' value to be an integer, the id of the desired vault credential")
|
||||
self.related.credentials.post(
|
||||
dict(id=kwargs['vault_credential']))
|
||||
raise ValueError("Expected 'vault_credential' value to be an integer, the id of the desired vault credential")
|
||||
self.related.credentials.post(dict(id=kwargs['vault_credential']))
|
||||
return ret
|
||||
|
||||
def add_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
dict(id=credential.id, associate=True))
|
||||
self.related.credentials.post(dict(id=credential.id, associate=True))
|
||||
|
||||
def remove_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
dict(id=credential.id, disassociate=True))
|
||||
self.related.credentials.post(dict(id=credential.id, disassociate=True))
|
||||
|
||||
def remove_all_credentials(self):
|
||||
for cred in self.related.credentials.get().results:
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
dict(id=cred.id, disassociate=True))
|
||||
self.related.credentials.post(dict(id=cred.id, disassociate=True))
|
||||
|
||||
|
||||
page.register_page([resources.job_template,
|
||||
(resources.job_templates, 'post'),
|
||||
(resources.job_template_copy, 'post')], JobTemplate)
|
||||
page.register_page([resources.job_template, (resources.job_templates, 'post'), (resources.job_template_copy, 'post')], JobTemplate)
|
||||
|
||||
|
||||
class JobTemplates(page.PageList, JobTemplate):
|
||||
@@ -208,8 +149,7 @@ class JobTemplates(page.PageList, JobTemplate):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.job_templates,
|
||||
resources.related_job_templates], JobTemplates)
|
||||
page.register_page([resources.job_templates, resources.related_job_templates], JobTemplates)
|
||||
|
||||
|
||||
class JobTemplateCallback(base.Base):
|
||||
|
||||
@@ -5,7 +5,6 @@ from . import page
|
||||
|
||||
|
||||
class Job(UnifiedJob):
|
||||
|
||||
def relaunch(self, payload={}):
|
||||
result = self.related.relaunch.post(payload)
|
||||
return self.walk(result.endpoint)
|
||||
@@ -19,9 +18,7 @@ class Jobs(page.PageList, Job):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.jobs,
|
||||
resources.job_template_jobs,
|
||||
resources.system_job_template_jobs], Jobs)
|
||||
page.register_page([resources.jobs, resources.job_template_jobs, resources.system_job_template_jobs], Jobs)
|
||||
|
||||
|
||||
class JobCancel(UnifiedJob):
|
||||
@@ -37,8 +34,7 @@ class JobEvent(base.Base):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.job_event,
|
||||
resources.job_job_event], JobEvent)
|
||||
page.register_page([resources.job_event, resources.job_job_event], JobEvent)
|
||||
|
||||
|
||||
class JobEvents(page.PageList, JobEvent):
|
||||
@@ -46,10 +42,7 @@ class JobEvents(page.PageList, JobEvent):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.job_events,
|
||||
resources.job_job_events,
|
||||
resources.job_event_children,
|
||||
resources.group_related_job_events], JobEvents)
|
||||
page.register_page([resources.job_events, resources.job_job_events, resources.job_event_children, resources.group_related_job_events], JobEvents)
|
||||
|
||||
|
||||
class JobPlay(base.Base):
|
||||
@@ -97,8 +90,7 @@ class JobHostSummaries(page.PageList, JobHostSummary):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.job_host_summaries,
|
||||
resources.group_related_job_host_summaries], JobHostSummaries)
|
||||
page.register_page([resources.job_host_summaries, resources.group_related_job_host_summaries], JobHostSummaries)
|
||||
|
||||
|
||||
class JobRelaunch(base.Base):
|
||||
|
||||
@@ -19,43 +19,24 @@ class Label(HasCreate, base.Base):
|
||||
|
||||
def payload(self, organization, **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Label - {}'.format(
|
||||
random_title()),
|
||||
name=kwargs.get('name') or 'Label - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
organization=organization.id)
|
||||
organization=organization.id,
|
||||
)
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
organization=Organization,
|
||||
**kwargs):
|
||||
def create_payload(self, name='', description='', organization=Organization, **kwargs):
|
||||
self.create_and_update_dependencies(organization)
|
||||
payload = self.payload(
|
||||
organization=self.ds.organization,
|
||||
name=name,
|
||||
description=description,
|
||||
**kwargs)
|
||||
payload = self.payload(organization=self.ds.organization, name=name, description=description, **kwargs)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
organization=Organization,
|
||||
**kwargs):
|
||||
payload = self.create_payload(
|
||||
name=name,
|
||||
description=description,
|
||||
organization=organization,
|
||||
**kwargs)
|
||||
def create(self, name='', description='', organization=Organization, **kwargs):
|
||||
payload = self.create_payload(name=name, description=description, organization=organization, **kwargs)
|
||||
return self.update_identity(Labels(self.connection).post(payload))
|
||||
|
||||
|
||||
page.register_page([resources.label,
|
||||
(resources.labels, 'post')], Label)
|
||||
page.register_page([resources.label, (resources.labels, 'post')], Label)
|
||||
|
||||
|
||||
class Labels(page.PageList, Label):
|
||||
@@ -63,7 +44,4 @@ class Labels(page.PageList, Label):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.labels,
|
||||
resources.job_labels,
|
||||
resources.job_template_labels,
|
||||
resources.workflow_job_template_labels], Labels)
|
||||
page.register_page([resources.labels, resources.job_labels, resources.job_template_labels, resources.workflow_job_template_labels], Labels)
|
||||
|
||||
@@ -4,12 +4,9 @@ from . import page
|
||||
|
||||
|
||||
class Metrics(base.Base):
|
||||
|
||||
def get(self, **query_parameters):
|
||||
request = self.connection.get(self.endpoint, query_parameters,
|
||||
headers={'Accept': 'application/json'})
|
||||
request = self.connection.get(self.endpoint, query_parameters, headers={'Accept': 'application/json'})
|
||||
return self.page_identity(request)
|
||||
|
||||
|
||||
page.register_page([resources.metrics,
|
||||
(resources.metrics, 'get')], Metrics)
|
||||
page.register_page([resources.metrics, (resources.metrics, 'get')], Metrics)
|
||||
|
||||
@@ -9,16 +9,7 @@ from . import page
|
||||
|
||||
|
||||
job_results = ('any', 'error', 'success')
|
||||
notification_types = (
|
||||
'email',
|
||||
'irc',
|
||||
'pagerduty',
|
||||
'slack',
|
||||
'twilio',
|
||||
'webhook',
|
||||
'mattermost',
|
||||
'grafana',
|
||||
'rocketchat')
|
||||
notification_types = ('email', 'irc', 'pagerduty', 'slack', 'twilio', 'webhook', 'mattermost', 'grafana', 'rocketchat')
|
||||
|
||||
|
||||
class NotificationTemplate(HasCopy, HasCreate, base.Base):
|
||||
@@ -28,18 +19,17 @@ class NotificationTemplate(HasCopy, HasCreate, base.Base):
|
||||
|
||||
def test(self):
|
||||
"""Create test notification"""
|
||||
assert 'test' in self.related, \
|
||||
"No such related attribute 'test'"
|
||||
assert 'test' in self.related, "No such related attribute 'test'"
|
||||
|
||||
# trigger test notification
|
||||
notification_id = self.related.test.post().notification
|
||||
|
||||
# return notification page
|
||||
notifications_pg = self.get_related(
|
||||
'notifications', id=notification_id).wait_until_count(1)
|
||||
assert notifications_pg.count == 1, \
|
||||
"test notification triggered (id:%s) but notification not found in response at %s/notifications/" % \
|
||||
(notification_id, self.url)
|
||||
notifications_pg = self.get_related('notifications', id=notification_id).wait_until_count(1)
|
||||
assert notifications_pg.count == 1, "test notification triggered (id:%s) but notification not found in response at %s/notifications/" % (
|
||||
notification_id,
|
||||
self.url,
|
||||
)
|
||||
return notifications_pg.results[0]
|
||||
|
||||
def silent_delete(self):
|
||||
@@ -53,41 +43,25 @@ class NotificationTemplate(HasCopy, HasCreate, base.Base):
|
||||
|
||||
def payload(self, organization, notification_type='slack', messages=not_provided, **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'NotificationTemplate ({0}) - {1}' .format(
|
||||
notification_type,
|
||||
random_title()),
|
||||
name=kwargs.get('name') or 'NotificationTemplate ({0}) - {1}'.format(notification_type, random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
organization=organization.id,
|
||||
notification_type=notification_type)
|
||||
notification_type=notification_type,
|
||||
)
|
||||
if messages != not_provided:
|
||||
payload['messages'] = messages
|
||||
|
||||
notification_configuration = kwargs.get(
|
||||
'notification_configuration', {})
|
||||
notification_configuration = kwargs.get('notification_configuration', {})
|
||||
payload.notification_configuration = notification_configuration
|
||||
|
||||
if payload.notification_configuration == {}:
|
||||
services = config.credentials.notification_services
|
||||
|
||||
if notification_type == 'email':
|
||||
fields = (
|
||||
'host',
|
||||
'username',
|
||||
'password',
|
||||
'port',
|
||||
'use_ssl',
|
||||
'use_tls',
|
||||
'sender',
|
||||
'recipients')
|
||||
fields = ('host', 'username', 'password', 'port', 'use_ssl', 'use_tls', 'sender', 'recipients')
|
||||
cred = services.email
|
||||
elif notification_type == 'irc':
|
||||
fields = (
|
||||
'server',
|
||||
'port',
|
||||
'use_ssl',
|
||||
'password',
|
||||
'nickname',
|
||||
'targets')
|
||||
fields = ('server', 'port', 'use_ssl', 'password', 'nickname', 'targets')
|
||||
cred = services.irc
|
||||
elif notification_type == 'pagerduty':
|
||||
fields = ('client_name', 'service_key', 'subdomain', 'token')
|
||||
@@ -96,34 +70,22 @@ class NotificationTemplate(HasCopy, HasCreate, base.Base):
|
||||
fields = ('channels', 'token')
|
||||
cred = services.slack
|
||||
elif notification_type == 'twilio':
|
||||
fields = (
|
||||
'account_sid',
|
||||
'account_token',
|
||||
'from_number',
|
||||
'to_numbers')
|
||||
fields = ('account_sid', 'account_token', 'from_number', 'to_numbers')
|
||||
cred = services.twilio
|
||||
elif notification_type == 'webhook':
|
||||
fields = ('url', 'headers')
|
||||
cred = services.webhook
|
||||
elif notification_type == 'mattermost':
|
||||
fields = (
|
||||
'mattermost_url',
|
||||
'mattermost_username',
|
||||
'mattermost_channel',
|
||||
'mattermost_icon_url',
|
||||
'mattermost_no_verify_ssl')
|
||||
fields = ('mattermost_url', 'mattermost_username', 'mattermost_channel', 'mattermost_icon_url', 'mattermost_no_verify_ssl')
|
||||
cred = services.mattermost
|
||||
elif notification_type == 'grafana':
|
||||
fields = ('grafana_url',
|
||||
'grafana_key')
|
||||
fields = ('grafana_url', 'grafana_key')
|
||||
cred = services.grafana
|
||||
elif notification_type == 'rocketchat':
|
||||
fields = ('rocketchat_url',
|
||||
'rocketchat_no_verify_ssl')
|
||||
fields = ('rocketchat_url', 'rocketchat_no_verify_ssl')
|
||||
cred = services.rocketchat
|
||||
else:
|
||||
raise ValueError(
|
||||
'Unknown notification_type {0}'.format(notification_type))
|
||||
raise ValueError('Unknown notification_type {0}'.format(notification_type))
|
||||
|
||||
for field in fields:
|
||||
if field == 'bot_token':
|
||||
@@ -136,47 +98,21 @@ class NotificationTemplate(HasCopy, HasCreate, base.Base):
|
||||
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
notification_type='slack',
|
||||
organization=Organization,
|
||||
messages=not_provided,
|
||||
**kwargs):
|
||||
def create_payload(self, name='', description='', notification_type='slack', organization=Organization, messages=not_provided, **kwargs):
|
||||
if notification_type not in notification_types:
|
||||
raise ValueError(
|
||||
'Unsupported notification type "{0}". Please use one of {1}.' .format(
|
||||
notification_type, notification_types))
|
||||
raise ValueError('Unsupported notification type "{0}". Please use one of {1}.'.format(notification_type, notification_types))
|
||||
self.create_and_update_dependencies(organization)
|
||||
payload = self.payload(
|
||||
organization=self.ds.organization,
|
||||
notification_type=notification_type,
|
||||
name=name,
|
||||
description=description,
|
||||
messages=messages,
|
||||
**kwargs)
|
||||
organization=self.ds.organization, notification_type=notification_type, name=name, description=description, messages=messages, **kwargs
|
||||
)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
notification_type='slack',
|
||||
organization=Organization,
|
||||
messages=not_provided,
|
||||
**kwargs):
|
||||
def create(self, name='', description='', notification_type='slack', organization=Organization, messages=not_provided, **kwargs):
|
||||
payload = self.create_payload(
|
||||
name=name,
|
||||
description=description,
|
||||
notification_type=notification_type,
|
||||
organization=organization,
|
||||
messages=messages,
|
||||
**kwargs)
|
||||
return self.update_identity(
|
||||
NotificationTemplates(
|
||||
self.connection).post(payload))
|
||||
name=name, description=description, notification_type=notification_type, organization=organization, messages=messages, **kwargs
|
||||
)
|
||||
return self.update_identity(NotificationTemplates(self.connection).post(payload))
|
||||
|
||||
def associate(self, resource, job_result='any'):
|
||||
"""Associates a NotificationTemplate with the provided resource"""
|
||||
@@ -188,15 +124,11 @@ class NotificationTemplate(HasCopy, HasCreate, base.Base):
|
||||
|
||||
def _associate(self, resource, job_result='any', disassociate=False):
|
||||
if job_result not in job_results:
|
||||
raise ValueError(
|
||||
'Unsupported job_result type "{0}". Please use one of {1}.' .format(
|
||||
job_result, job_results))
|
||||
raise ValueError('Unsupported job_result type "{0}". Please use one of {1}.'.format(job_result, job_results))
|
||||
|
||||
result_attr = 'notification_templates_{0}'.format(job_result)
|
||||
if result_attr not in resource.related:
|
||||
raise ValueError(
|
||||
'Unsupported resource "{0}". Does not have a related {1} field.' .format(
|
||||
resource, result_attr))
|
||||
raise ValueError('Unsupported resource "{0}". Does not have a related {1} field.'.format(resource, result_attr))
|
||||
|
||||
payload = dict(id=self.id)
|
||||
if disassociate:
|
||||
@@ -206,14 +138,19 @@ class NotificationTemplate(HasCopy, HasCreate, base.Base):
|
||||
getattr(resource.related, result_attr).post(payload)
|
||||
|
||||
|
||||
page.register_page([resources.notification_template,
|
||||
(resources.notification_templates, 'post'),
|
||||
(resources.notification_template_copy, 'post'),
|
||||
resources.notification_template_any,
|
||||
resources.notification_template_started,
|
||||
resources.notification_template_error,
|
||||
resources.notification_template_success,
|
||||
resources.notification_template_approval], NotificationTemplate)
|
||||
page.register_page(
|
||||
[
|
||||
resources.notification_template,
|
||||
(resources.notification_templates, 'post'),
|
||||
(resources.notification_template_copy, 'post'),
|
||||
resources.notification_template_any,
|
||||
resources.notification_template_started,
|
||||
resources.notification_template_error,
|
||||
resources.notification_template_success,
|
||||
resources.notification_template_approval,
|
||||
],
|
||||
NotificationTemplate,
|
||||
)
|
||||
|
||||
|
||||
class NotificationTemplates(page.PageList, NotificationTemplate):
|
||||
@@ -221,14 +158,18 @@ class NotificationTemplates(page.PageList, NotificationTemplate):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.notification_templates,
|
||||
resources.related_notification_templates,
|
||||
resources.notification_templates_any,
|
||||
resources.notification_templates_started,
|
||||
resources.notification_templates_error,
|
||||
resources.notification_templates_success,
|
||||
resources.notification_templates_approvals],
|
||||
NotificationTemplates)
|
||||
page.register_page(
|
||||
[
|
||||
resources.notification_templates,
|
||||
resources.related_notification_templates,
|
||||
resources.notification_templates_any,
|
||||
resources.notification_templates_started,
|
||||
resources.notification_templates_error,
|
||||
resources.notification_templates_success,
|
||||
resources.notification_templates_approvals,
|
||||
],
|
||||
NotificationTemplates,
|
||||
)
|
||||
|
||||
|
||||
class NotificationTemplateCopy(base.Base):
|
||||
@@ -244,6 +185,4 @@ class NotificationTemplateTest(base.Base):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page(
|
||||
resources.notification_template_test,
|
||||
NotificationTemplateTest)
|
||||
page.register_page(resources.notification_template_test, NotificationTemplateTest)
|
||||
|
||||
@@ -6,10 +6,8 @@ from . import page
|
||||
|
||||
|
||||
class Notification(HasStatus, base.Base):
|
||||
|
||||
def __str__(self):
|
||||
items = ['id', 'notification_type', 'status', 'error', 'notifications_sent',
|
||||
'subject', 'recipients']
|
||||
items = ['id', 'notification_type', 'status', 'error', 'notifications_sent', 'subject', 'recipients']
|
||||
info = []
|
||||
for item in [x for x in items if hasattr(self, x)]:
|
||||
info.append('{0}:{1}'.format(item, getattr(self, item)))
|
||||
@@ -40,13 +38,10 @@ page.register_page(resources.notification, Notification)
|
||||
|
||||
|
||||
class Notifications(page.PageList, Notification):
|
||||
|
||||
def wait_until_count(self, count, interval=10, timeout=60, **kw):
|
||||
"""Poll notifications page until it is populated with `count` number of notifications."""
|
||||
poll_until(lambda: getattr(self.get(), 'count') == count,
|
||||
interval=interval, timeout=timeout, **kw)
|
||||
poll_until(lambda: getattr(self.get(), 'count') == count, interval=interval, timeout=timeout, **kw)
|
||||
return self
|
||||
|
||||
|
||||
page.register_page([resources.notifications,
|
||||
resources.related_notifications], Notifications)
|
||||
page.register_page([resources.notifications, resources.related_notifications], Notifications)
|
||||
|
||||
@@ -26,22 +26,27 @@ class Organization(HasCreate, HasInstanceGroups, HasNotifications, base.Base):
|
||||
if isinstance(credential, page.Page):
|
||||
credential = credential.json
|
||||
with suppress(exc.NoContent):
|
||||
self.related.galaxy_credentials.post({
|
||||
"id": credential.id,
|
||||
})
|
||||
self.related.galaxy_credentials.post(
|
||||
{
|
||||
"id": credential.id,
|
||||
}
|
||||
)
|
||||
|
||||
def remove_galaxy_credential(self, credential):
|
||||
if isinstance(credential, page.Page):
|
||||
credential = credential.json
|
||||
with suppress(exc.NoContent):
|
||||
self.related.galaxy_credentials.post({
|
||||
"id": credential.id,
|
||||
"disassociate": True,
|
||||
})
|
||||
self.related.galaxy_credentials.post(
|
||||
{
|
||||
"id": credential.id,
|
||||
"disassociate": True,
|
||||
}
|
||||
)
|
||||
|
||||
def payload(self, **kwargs):
|
||||
payload = PseudoNamespace(name=kwargs.get('name') or 'Organization - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10))
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Organization - {}'.format(random_title()), description=kwargs.get('description') or random_title(10)
|
||||
)
|
||||
|
||||
payload = set_payload_foreign_key_args(payload, ('default_environment',), kwargs)
|
||||
|
||||
@@ -57,8 +62,7 @@ class Organization(HasCreate, HasInstanceGroups, HasNotifications, base.Base):
|
||||
return self.update_identity(Organizations(self.connection).post(payload))
|
||||
|
||||
|
||||
page.register_page([resources.organization,
|
||||
(resources.organizations, 'post')], Organization)
|
||||
page.register_page([resources.organization, (resources.organizations, 'post')], Organization)
|
||||
|
||||
|
||||
class Organizations(page.PageList, Organization):
|
||||
@@ -66,6 +70,4 @@ class Organizations(page.PageList, Organization):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.organizations,
|
||||
resources.user_organizations,
|
||||
resources.project_organizations], Organizations)
|
||||
page.register_page([resources.organizations, resources.user_organizations, resources.project_organizations], Organizations)
|
||||
|
||||
@@ -6,15 +6,7 @@ import re
|
||||
from requests import Response
|
||||
import http.client as http
|
||||
|
||||
from awxkit.utils import (
|
||||
PseudoNamespace,
|
||||
is_relative_endpoint,
|
||||
are_same_endpoint,
|
||||
super_dir_set,
|
||||
suppress,
|
||||
is_list_or_tuple,
|
||||
to_str
|
||||
)
|
||||
from awxkit.utils import PseudoNamespace, is_relative_endpoint, are_same_endpoint, super_dir_set, suppress, is_list_or_tuple, to_str
|
||||
from awxkit.api import utils
|
||||
from awxkit.api.client import Connection
|
||||
from awxkit.api.registry import URLRegistry
|
||||
@@ -41,17 +33,11 @@ def is_license_invalid(response):
|
||||
|
||||
|
||||
def is_license_exceeded(response):
|
||||
if re.match(
|
||||
r".*license range of.*instances has been exceeded.*",
|
||||
response.text):
|
||||
if re.match(r".*license range of.*instances has been exceeded.*", response.text):
|
||||
return True
|
||||
if re.match(
|
||||
r".*License count of.*instances has been reached.*",
|
||||
response.text):
|
||||
if re.match(r".*License count of.*instances has been reached.*", response.text):
|
||||
return True
|
||||
if re.match(
|
||||
r".*License count of.*instances has been exceeded.*",
|
||||
response.text):
|
||||
if re.match(r".*License count of.*instances has been exceeded.*", response.text):
|
||||
return True
|
||||
if re.match(r".*License has expired.*", response.text):
|
||||
return True
|
||||
@@ -67,6 +53,7 @@ def is_duplicate_error(response):
|
||||
def register_page(urls, page_cls):
|
||||
if not _page_registry.default:
|
||||
from awxkit.api.pages import Base
|
||||
|
||||
_page_registry.setdefault(Base)
|
||||
|
||||
if not is_list_or_tuple(urls):
|
||||
@@ -108,32 +95,23 @@ class Page(object):
|
||||
if 'endpoint' in kw:
|
||||
self.endpoint = kw['endpoint']
|
||||
|
||||
self.connection = connection or Connection(
|
||||
config.base_url, kw.get(
|
||||
'verify', not config.assume_untrusted))
|
||||
self.connection = connection or Connection(config.base_url, kw.get('verify', not config.assume_untrusted))
|
||||
|
||||
self.r = kw.get('r', None)
|
||||
self.json = kw.get(
|
||||
'json', objectify_response_json(
|
||||
self.r) if self.r else {})
|
||||
self.json = kw.get('json', objectify_response_json(self.r) if self.r else {})
|
||||
self.last_elapsed = kw.get('last_elapsed', None)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if 'json' in self.__dict__ and name in self.json:
|
||||
value = self.json[name]
|
||||
if not isinstance(
|
||||
value,
|
||||
TentativePage) and is_relative_endpoint(value):
|
||||
if not isinstance(value, TentativePage) and is_relative_endpoint(value):
|
||||
value = TentativePage(value, self.connection)
|
||||
elif isinstance(value, dict):
|
||||
for key, item in value.items():
|
||||
if not isinstance(
|
||||
item, TentativePage) and is_relative_endpoint(item):
|
||||
if not isinstance(item, TentativePage) and is_relative_endpoint(item):
|
||||
value[key] = TentativePage(item, self.connection)
|
||||
return value
|
||||
raise AttributeError(
|
||||
"{!r} object has no attribute {!r}".format(
|
||||
self.__class__.__name__, name))
|
||||
raise AttributeError("{!r} object has no attribute {!r}".format(self.__class__.__name__, name))
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if 'json' in self.__dict__ and name in self.json:
|
||||
@@ -200,20 +178,15 @@ class Page(object):
|
||||
text = response.text
|
||||
if len(text) > 1024:
|
||||
text = text[:1024] + '... <<< Truncated >>> ...'
|
||||
log.debug(
|
||||
"Unable to parse JSON response ({0.status_code}): {1} - '{2}'".format(response, e, text))
|
||||
log.debug("Unable to parse JSON response ({0.status_code}): {1} - '{2}'".format(response, e, text))
|
||||
|
||||
exc_str = "%s (%s) received" % (
|
||||
http.responses[response.status_code], response.status_code)
|
||||
exc_str = "%s (%s) received" % (http.responses[response.status_code], response.status_code)
|
||||
|
||||
exception = exception_from_status_code(response.status_code)
|
||||
if exception:
|
||||
raise exception(exc_str, data)
|
||||
|
||||
if response.status_code in (
|
||||
http.OK,
|
||||
http.CREATED,
|
||||
http.ACCEPTED):
|
||||
if response.status_code in (http.OK, http.CREATED, http.ACCEPTED):
|
||||
|
||||
# Not all JSON responses include a URL. Grab it from the request
|
||||
# object, if needed.
|
||||
@@ -232,13 +205,7 @@ class Page(object):
|
||||
return self
|
||||
|
||||
registered_type = get_registered_page(request_path, request_method)
|
||||
return registered_type(
|
||||
self.connection,
|
||||
endpoint=endpoint,
|
||||
json=data,
|
||||
last_elapsed=response.elapsed,
|
||||
r=response,
|
||||
ds=ds)
|
||||
return registered_type(self.connection, endpoint=endpoint, json=data, last_elapsed=response.elapsed, r=response, ds=ds)
|
||||
|
||||
elif response.status_code == http.FORBIDDEN:
|
||||
if is_license_invalid(response):
|
||||
@@ -341,14 +308,16 @@ class Page(object):
|
||||
return natural_key
|
||||
|
||||
|
||||
_exception_map = {http.NO_CONTENT: exc.NoContent,
|
||||
http.NOT_FOUND: exc.NotFound,
|
||||
http.INTERNAL_SERVER_ERROR: exc.InternalServerError,
|
||||
http.BAD_GATEWAY: exc.BadGateway,
|
||||
http.METHOD_NOT_ALLOWED: exc.MethodNotAllowed,
|
||||
http.UNAUTHORIZED: exc.Unauthorized,
|
||||
http.PAYMENT_REQUIRED: exc.PaymentRequired,
|
||||
http.CONFLICT: exc.Conflict}
|
||||
_exception_map = {
|
||||
http.NO_CONTENT: exc.NoContent,
|
||||
http.NOT_FOUND: exc.NotFound,
|
||||
http.INTERNAL_SERVER_ERROR: exc.InternalServerError,
|
||||
http.BAD_GATEWAY: exc.BadGateway,
|
||||
http.METHOD_NOT_ALLOWED: exc.MethodNotAllowed,
|
||||
http.UNAUTHORIZED: exc.Unauthorized,
|
||||
http.PAYMENT_REQUIRED: exc.PaymentRequired,
|
||||
http.CONFLICT: exc.Conflict,
|
||||
}
|
||||
|
||||
|
||||
def exception_from_status_code(status_code):
|
||||
@@ -380,12 +349,7 @@ class PageList(object):
|
||||
registered_type = self.__item_class__
|
||||
else:
|
||||
registered_type = get_registered_page(endpoint)
|
||||
items.append(
|
||||
registered_type(
|
||||
self.connection,
|
||||
endpoint=endpoint,
|
||||
json=item,
|
||||
r=self.r))
|
||||
items.append(registered_type(self.connection, endpoint=endpoint, json=item, r=self.r))
|
||||
return items
|
||||
|
||||
def go_to_next(self):
|
||||
@@ -407,7 +371,6 @@ class PageList(object):
|
||||
|
||||
|
||||
class TentativePage(str):
|
||||
|
||||
def __new__(cls, endpoint, connection):
|
||||
return super(TentativePage, cls).__new__(cls, to_str(endpoint))
|
||||
|
||||
@@ -416,10 +379,7 @@ class TentativePage(str):
|
||||
self.connection = connection
|
||||
|
||||
def _create(self):
|
||||
return get_registered_page(
|
||||
self.endpoint)(
|
||||
self.connection,
|
||||
endpoint=self.endpoint)
|
||||
return get_registered_page(self.endpoint)(self.connection, endpoint=self.endpoint)
|
||||
|
||||
def get(self, **params):
|
||||
return self._create().get(**params)
|
||||
@@ -436,21 +396,15 @@ class TentativePage(str):
|
||||
page = None
|
||||
# look up users by username not name
|
||||
if 'users' in self:
|
||||
assert query_parameters.get(
|
||||
'username'), 'For this resource, you must call this method with a "username" to look up the object by'
|
||||
assert query_parameters.get('username'), 'For this resource, you must call this method with a "username" to look up the object by'
|
||||
page = self.get(username=query_parameters['username'])
|
||||
else:
|
||||
assert query_parameters.get(
|
||||
'name'), 'For this resource, you must call this method with a "name" to look up the object by'
|
||||
assert query_parameters.get('name'), 'For this resource, you must call this method with a "name" to look up the object by'
|
||||
if query_parameters.get('organization'):
|
||||
if isinstance(query_parameters.get('organization'), int):
|
||||
page = self.get(
|
||||
name=query_parameters['name'],
|
||||
organization=query_parameters.get('organization'))
|
||||
page = self.get(name=query_parameters['name'], organization=query_parameters.get('organization'))
|
||||
else:
|
||||
page = self.get(
|
||||
name=query_parameters['name'],
|
||||
organization=query_parameters.get('organization').id)
|
||||
page = self.get(name=query_parameters['name'], organization=query_parameters.get('organization').id)
|
||||
else:
|
||||
page = self.get(name=query_parameters['name'])
|
||||
if page and page.results:
|
||||
@@ -476,13 +430,9 @@ class TentativePage(str):
|
||||
if query_parameters.get('name'):
|
||||
if query_parameters.get('organization'):
|
||||
if isinstance(query_parameters.get('organization'), int):
|
||||
page = self.get(
|
||||
name=query_parameters['name'],
|
||||
organization=query_parameters.get('organization'))
|
||||
page = self.get(name=query_parameters['name'], organization=query_parameters.get('organization'))
|
||||
else:
|
||||
page = self.get(
|
||||
name=query_parameters['name'],
|
||||
organization=query_parameters.get('organization').id)
|
||||
page = self.get(name=query_parameters['name'], organization=query_parameters.get('organization').id)
|
||||
else:
|
||||
page = self.get(name=query_parameters['name'])
|
||||
|
||||
|
||||
@@ -18,13 +18,11 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
|
||||
def payload(self, organization, scm_type='git', **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Project - {}'.format(
|
||||
random_title()),
|
||||
name=kwargs.get('name') or 'Project - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
scm_type=scm_type,
|
||||
scm_url=kwargs.get('scm_url') or config.project_urls.get(
|
||||
scm_type,
|
||||
''))
|
||||
scm_url=kwargs.get('scm_url') or config.project_urls.get(scm_type, ''),
|
||||
)
|
||||
|
||||
if organization is not None:
|
||||
payload.organization = organization.id
|
||||
@@ -40,43 +38,25 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
'scm_update_cache_timeout',
|
||||
'scm_update_on_launch',
|
||||
'scm_refspec',
|
||||
'allow_override')
|
||||
'allow_override',
|
||||
)
|
||||
update_payload(payload, fields, kwargs)
|
||||
|
||||
payload = set_payload_foreign_key_args(payload, ('execution_environment', 'default_environment'), kwargs)
|
||||
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
scm_type='git',
|
||||
scm_url='',
|
||||
scm_branch='',
|
||||
organization=Organization,
|
||||
credential=None,
|
||||
**kwargs):
|
||||
def create_payload(self, name='', description='', scm_type='git', scm_url='', scm_branch='', organization=Organization, credential=None, **kwargs):
|
||||
if credential:
|
||||
if isinstance(credential, Credential):
|
||||
if credential.ds.credential_type.namespace not in (
|
||||
'scm', 'insights'):
|
||||
if credential.ds.credential_type.namespace not in ('scm', 'insights'):
|
||||
credential = None # ignore incompatible credential from HasCreate dependency injection
|
||||
elif credential in (Credential,):
|
||||
credential = (
|
||||
Credential, dict(
|
||||
credential_type=(
|
||||
True, dict(
|
||||
kind='scm'))))
|
||||
credential = (Credential, dict(credential_type=(True, dict(kind='scm'))))
|
||||
elif credential is True:
|
||||
credential = (
|
||||
Credential, dict(
|
||||
credential_type=(
|
||||
True, dict(
|
||||
kind='scm'))))
|
||||
credential = (Credential, dict(credential_type=(True, dict(kind='scm'))))
|
||||
|
||||
self.create_and_update_dependencies(
|
||||
*filter_by_class((credential, Credential), (organization, Organization)))
|
||||
self.create_and_update_dependencies(*filter_by_class((credential, Credential), (organization, Organization)))
|
||||
|
||||
credential = self.ds.credential if credential else None
|
||||
organization = self.ds.organization if organization else None
|
||||
@@ -89,20 +69,12 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
scm_url=scm_url,
|
||||
scm_branch=scm_branch,
|
||||
credential=credential,
|
||||
**kwargs)
|
||||
**kwargs
|
||||
)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
scm_type='git',
|
||||
scm_url='',
|
||||
scm_branch='',
|
||||
organization=Organization,
|
||||
credential=None,
|
||||
**kwargs):
|
||||
def create(self, name='', description='', scm_type='git', scm_url='', scm_branch='', organization=Organization, credential=None, **kwargs):
|
||||
payload = self.create_payload(
|
||||
name=name,
|
||||
description=description,
|
||||
@@ -111,7 +83,8 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
scm_branch=scm_branch,
|
||||
organization=organization,
|
||||
credential=credential,
|
||||
**kwargs)
|
||||
**kwargs
|
||||
)
|
||||
self.update_identity(Projects(self.connection).post(payload))
|
||||
|
||||
if kwargs.get('wait', True):
|
||||
@@ -127,25 +100,20 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
update_pg = self.get_related('update')
|
||||
|
||||
# assert can_update == True
|
||||
assert update_pg.can_update, \
|
||||
"The specified project (id:%s) is not able to update (can_update:%s)" % \
|
||||
(self.id, update_pg.can_update)
|
||||
assert update_pg.can_update, "The specified project (id:%s) is not able to update (can_update:%s)" % (self.id, update_pg.can_update)
|
||||
|
||||
# start the update
|
||||
result = update_pg.post()
|
||||
|
||||
# assert JSON response
|
||||
assert 'project_update' in result.json, \
|
||||
"Unexpected JSON response when starting an project_update.\n%s" % \
|
||||
json.dumps(result.json, indent=2)
|
||||
assert 'project_update' in result.json, "Unexpected JSON response when starting an project_update.\n%s" % json.dumps(result.json, indent=2)
|
||||
|
||||
# locate and return the specific update
|
||||
jobs_pg = self.get_related(
|
||||
'project_updates',
|
||||
id=result.json['project_update'])
|
||||
assert jobs_pg.count == 1, \
|
||||
"An project_update started (id:%s) but job not found in response at %s/inventory_updates/" % \
|
||||
(result.json['project_update'], self.url)
|
||||
jobs_pg = self.get_related('project_updates', id=result.json['project_update'])
|
||||
assert jobs_pg.count == 1, "An project_update started (id:%s) but job not found in response at %s/inventory_updates/" % (
|
||||
result.json['project_update'],
|
||||
self.url,
|
||||
)
|
||||
return jobs_pg.results[0]
|
||||
|
||||
@property
|
||||
@@ -154,13 +122,10 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
0) scm_type != ""
|
||||
1) unified_job_template.is_successful
|
||||
"""
|
||||
return self.scm_type != "" and \
|
||||
super(Project, self).is_successful
|
||||
return self.scm_type != "" and super(Project, self).is_successful
|
||||
|
||||
|
||||
page.register_page([resources.project,
|
||||
(resources.projects, 'post'),
|
||||
(resources.project_copy, 'post')], Project)
|
||||
page.register_page([resources.project, (resources.projects, 'post'), (resources.project_copy, 'post')], Project)
|
||||
|
||||
|
||||
class Projects(page.PageList, Project):
|
||||
@@ -168,8 +133,7 @@ class Projects(page.PageList, Project):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.projects,
|
||||
resources.related_projects], Projects)
|
||||
page.register_page([resources.projects, resources.related_projects], Projects)
|
||||
|
||||
|
||||
class ProjectUpdate(UnifiedJob):
|
||||
@@ -185,8 +149,7 @@ class ProjectUpdates(page.PageList, ProjectUpdate):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.project_updates,
|
||||
resources.project_project_updates], ProjectUpdates)
|
||||
page.register_page([resources.project_updates, resources.project_project_updates], ProjectUpdates)
|
||||
|
||||
|
||||
class ProjectUpdateLaunch(base.Base):
|
||||
|
||||
@@ -18,15 +18,11 @@ class Role(base.Base):
|
||||
cache = page.PageCache()
|
||||
|
||||
natural_key = super(Role, self).get_natural_key(cache=cache)
|
||||
related_objs = [
|
||||
related for name, related in self.related.items()
|
||||
if name not in ('users', 'teams')
|
||||
]
|
||||
related_objs = [related for name, related in self.related.items() if name not in ('users', 'teams')]
|
||||
if related_objs:
|
||||
related_endpoint = cache.get_page(related_objs[0])
|
||||
if related_endpoint is None:
|
||||
log.error("Unable to obtain content_object %s for role %s",
|
||||
related_objs[0], self.endpoint)
|
||||
log.error("Unable to obtain content_object %s for role %s", related_objs[0], self.endpoint)
|
||||
return None
|
||||
natural_key['content_object'] = related_endpoint.get_natural_key(cache=cache)
|
||||
|
||||
@@ -41,6 +37,4 @@ class Roles(page.PageList, Role):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.roles,
|
||||
resources.related_roles,
|
||||
resources.related_object_roles], Roles)
|
||||
page.register_page([resources.roles, resources.related_roles, resources.related_object_roles], Roles)
|
||||
|
||||
@@ -11,12 +11,10 @@ class Schedule(UnifiedJob):
|
||||
NATURAL_KEY = ('unified_job_template', 'name')
|
||||
|
||||
|
||||
page.register_page([resources.schedule,
|
||||
resources.related_schedule], Schedule)
|
||||
page.register_page([resources.schedule, resources.related_schedule], Schedule)
|
||||
|
||||
|
||||
class Schedules(page.PageList, Schedule):
|
||||
|
||||
def get_zoneinfo(self):
|
||||
return SchedulesZoneInfo(self.connection).get()
|
||||
|
||||
@@ -33,8 +31,7 @@ class Schedules(page.PageList, Schedule):
|
||||
self.related.credentials.post(dict(id=cred.id, disassociate=True))
|
||||
|
||||
|
||||
page.register_page([resources.schedules,
|
||||
resources.related_schedules], Schedules)
|
||||
page.register_page([resources.schedules, resources.related_schedules], Schedules)
|
||||
|
||||
|
||||
class SchedulesPreview(base.Base):
|
||||
@@ -46,7 +43,6 @@ page.register_page(((resources.schedules_preview, 'post'),), SchedulesPreview)
|
||||
|
||||
|
||||
class SchedulesZoneInfo(base.Base):
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self.json[idx]
|
||||
|
||||
|
||||
@@ -8,27 +8,31 @@ class Setting(base.Base):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.setting,
|
||||
resources.settings_all,
|
||||
resources.settings_authentication,
|
||||
resources.settings_changed,
|
||||
resources.settings_github,
|
||||
resources.settings_github_org,
|
||||
resources.settings_github_team,
|
||||
resources.settings_google_oauth2,
|
||||
resources.settings_jobs,
|
||||
resources.settings_ldap,
|
||||
resources.settings_radius,
|
||||
resources.settings_saml,
|
||||
resources.settings_system,
|
||||
resources.settings_tacacsplus,
|
||||
resources.settings_ui,
|
||||
resources.settings_user,
|
||||
resources.settings_user_defaults], Setting)
|
||||
page.register_page(
|
||||
[
|
||||
resources.setting,
|
||||
resources.settings_all,
|
||||
resources.settings_authentication,
|
||||
resources.settings_changed,
|
||||
resources.settings_github,
|
||||
resources.settings_github_org,
|
||||
resources.settings_github_team,
|
||||
resources.settings_google_oauth2,
|
||||
resources.settings_jobs,
|
||||
resources.settings_ldap,
|
||||
resources.settings_radius,
|
||||
resources.settings_saml,
|
||||
resources.settings_system,
|
||||
resources.settings_tacacsplus,
|
||||
resources.settings_ui,
|
||||
resources.settings_user,
|
||||
resources.settings_user_defaults,
|
||||
],
|
||||
Setting,
|
||||
)
|
||||
|
||||
|
||||
class Settings(page.PageList, Setting):
|
||||
|
||||
def get_endpoint(self, endpoint):
|
||||
"""Helper method used to navigate to a specific settings endpoint.
|
||||
(Pdb) settings_pg.get_endpoint('all')
|
||||
|
||||
@@ -3,7 +3,6 @@ from . import page
|
||||
|
||||
|
||||
class Subscriptions(page.Page):
|
||||
|
||||
def get_possible_licenses(self, **kwargs):
|
||||
return self.post(json=kwargs).json
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ from awxkit.api.resources import resources
|
||||
|
||||
|
||||
class SurveySpec(base.Base):
|
||||
|
||||
def get_variable_default(self, var):
|
||||
for item in self.spec:
|
||||
if item.get('variable') == var:
|
||||
@@ -26,5 +25,4 @@ class SurveySpec(base.Base):
|
||||
return required_vars
|
||||
|
||||
|
||||
page.register_page([resources.job_template_survey_spec,
|
||||
resources.workflow_job_template_survey_spec], SurveySpec)
|
||||
page.register_page([resources.job_template_survey_spec, resources.workflow_job_template_survey_spec], SurveySpec)
|
||||
|
||||
@@ -5,16 +5,13 @@ from . import page
|
||||
|
||||
|
||||
class SystemJobTemplate(UnifiedJobTemplate, HasNotifications):
|
||||
|
||||
def launch(self, payload={}):
|
||||
"""Launch the system_job_template using related->launch endpoint."""
|
||||
result = self.related.launch.post(payload)
|
||||
|
||||
# return job
|
||||
jobs_pg = self.get_related('jobs', id=result.json['system_job'])
|
||||
assert jobs_pg.count == 1, \
|
||||
"system_job_template launched (id:%s) but unable to find matching " \
|
||||
"job at %s/jobs/" % (result.json['job'], self.url)
|
||||
assert jobs_pg.count == 1, "system_job_template launched (id:%s) but unable to find matching " "job at %s/jobs/" % (result.json['job'], self.url)
|
||||
return jobs_pg.results[0]
|
||||
|
||||
|
||||
|
||||
@@ -20,9 +20,11 @@ class Team(HasCreate, base.Base):
|
||||
self.related.users.post(user)
|
||||
|
||||
def payload(self, organization, **kwargs):
|
||||
payload = PseudoNamespace(name=kwargs.get('name') or 'Team - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
organization=organization.id)
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'Team - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10),
|
||||
organization=organization.id,
|
||||
)
|
||||
return payload
|
||||
|
||||
def create_payload(self, name='', description='', organization=Organization, **kwargs):
|
||||
@@ -36,8 +38,7 @@ class Team(HasCreate, base.Base):
|
||||
return self.update_identity(Teams(self.connection).post(payload))
|
||||
|
||||
|
||||
page.register_page([resources.team,
|
||||
(resources.teams, 'post')], Team)
|
||||
page.register_page([resources.team, (resources.teams, 'post')], Team)
|
||||
|
||||
|
||||
class Teams(page.PageList, Team):
|
||||
@@ -45,6 +46,4 @@ class Teams(page.PageList, Team):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.teams,
|
||||
resources.credential_owner_teams,
|
||||
resources.related_teams], Teams)
|
||||
page.register_page([resources.teams, resources.credential_owner_teams, resources.related_teams], Teams)
|
||||
|
||||
@@ -26,38 +26,19 @@ class UnifiedJobTemplate(HasStatus, base.Base):
|
||||
# formatting issue where result_stdout contained '%s'. This later caused
|
||||
# a python traceback when attempting to display output from this
|
||||
# method.
|
||||
items = [
|
||||
'id',
|
||||
'name',
|
||||
'status',
|
||||
'source',
|
||||
'last_update_failed',
|
||||
'last_updated',
|
||||
'result_traceback',
|
||||
'job_explanation',
|
||||
'job_args']
|
||||
items = ['id', 'name', 'status', 'source', 'last_update_failed', 'last_updated', 'result_traceback', 'job_explanation', 'job_args']
|
||||
info = []
|
||||
for item in [x for x in items if hasattr(self, x)]:
|
||||
info.append('{0}:{1}'.format(item, getattr(self, item)))
|
||||
output = '<{0.__class__.__name__} {1}>'.format(self, ', '.join(info))
|
||||
return output.replace('%', '%%')
|
||||
|
||||
def add_schedule(
|
||||
self,
|
||||
name='',
|
||||
description='',
|
||||
enabled=True,
|
||||
rrule=None,
|
||||
**kwargs):
|
||||
def add_schedule(self, name='', description='', enabled=True, rrule=None, **kwargs):
|
||||
if rrule is None:
|
||||
rrule = "DTSTART:30180101T000000Z RRULE:FREQ=YEARLY;INTERVAL=1"
|
||||
payload = dict(
|
||||
name=name or "{0} Schedule {1}".format(
|
||||
self.name,
|
||||
random_title()),
|
||||
description=description or random_title(10),
|
||||
enabled=enabled,
|
||||
rrule=str(rrule))
|
||||
name=name or "{0} Schedule {1}".format(self.name, random_title()), description=description or random_title(10), enabled=enabled, rrule=str(rrule)
|
||||
)
|
||||
|
||||
update_payload(payload, self.optional_schedule_fields, kwargs)
|
||||
|
||||
@@ -70,9 +51,7 @@ class UnifiedJobTemplate(HasStatus, base.Base):
|
||||
2) not last_update_failed
|
||||
3) last_updated
|
||||
"""
|
||||
return super(
|
||||
UnifiedJobTemplate,
|
||||
self).is_successful and not self.last_update_failed and self.last_updated is not None
|
||||
return super(UnifiedJobTemplate, self).is_successful and not self.last_update_failed and self.last_updated is not None
|
||||
|
||||
|
||||
page.register_page(resources.unified_job_template, UnifiedJobTemplate)
|
||||
|
||||
@@ -21,8 +21,7 @@ class UnifiedJob(HasStatus, base.Base):
|
||||
# NOTE: I use .replace('%', '%%') to workaround an odd string
|
||||
# formatting issue where result_stdout contained '%s'. This later caused
|
||||
# a python traceback when attempting to display output from this method.
|
||||
items = ['id', 'name', 'status', 'failed', 'result_stdout', 'result_traceback',
|
||||
'job_explanation', 'job_args']
|
||||
items = ['id', 'name', 'status', 'failed', 'result_stdout', 'result_traceback', 'job_explanation', 'job_args']
|
||||
info = []
|
||||
for item in [x for x in items if hasattr(self, x)]:
|
||||
info.append('{0}:{1}'.format(item, getattr(self, item)))
|
||||
@@ -32,9 +31,7 @@ class UnifiedJob(HasStatus, base.Base):
|
||||
@property
|
||||
def result_stdout(self):
|
||||
if 'result_stdout' not in self.json and 'stdout' in self.related:
|
||||
return self.connection.get(
|
||||
self.related.stdout, query_parameters=dict(format='txt_download')
|
||||
).content.decode()
|
||||
return self.connection.get(self.related.stdout, query_parameters=dict(format='txt_download')).content.decode()
|
||||
return self.json.result_stdout.decode()
|
||||
|
||||
def assert_text_in_stdout(self, expected_text, replace_spaces=None, replace_newlines=' '):
|
||||
@@ -55,9 +52,7 @@ class UnifiedJob(HasStatus, base.Base):
|
||||
stdout = stdout.replace(' ', replace_spaces)
|
||||
if expected_text not in stdout:
|
||||
pretty_stdout = pformat(stdout)
|
||||
raise AssertionError(
|
||||
'Expected "{}", but it was not found in stdout. Full stdout:\n {}'.format(expected_text, pretty_stdout)
|
||||
)
|
||||
raise AssertionError('Expected "{}", but it was not found in stdout. Full stdout:\n {}'.format(expected_text, pretty_stdout))
|
||||
|
||||
@property
|
||||
def is_successful(self):
|
||||
@@ -103,7 +98,7 @@ class UnifiedJob(HasStatus, base.Base):
|
||||
# Race condition where job finishes between can_cancel
|
||||
# check and post.
|
||||
if not any("not allowed" in field for field in e.msg.values()):
|
||||
raise(e)
|
||||
raise (e)
|
||||
return self.get()
|
||||
|
||||
@property
|
||||
@@ -114,6 +109,7 @@ class UnifiedJob(HasStatus, base.Base):
|
||||
```assert dict(extra_var=extra_var_val) in unified_job.job_args```
|
||||
If you need to ensure the job_args are of awx-provided format use raw unified_job.json.job_args.
|
||||
"""
|
||||
|
||||
def attempt_yaml_load(arg):
|
||||
try:
|
||||
return yaml.safe_load(arg)
|
||||
@@ -151,10 +147,7 @@ class UnifiedJob(HasStatus, base.Base):
|
||||
if host_loc.startswith(expected_prefix):
|
||||
return host_loc
|
||||
raise RuntimeError(
|
||||
'Could not find a controller private_data_dir for this job. '
|
||||
'Searched for volume mount to {} inside of args {}'.format(
|
||||
expected_prefix, job_args
|
||||
)
|
||||
'Could not find a controller private_data_dir for this job. ' 'Searched for volume mount to {} inside of args {}'.format(expected_prefix, job_args)
|
||||
)
|
||||
|
||||
|
||||
@@ -163,7 +156,4 @@ class UnifiedJobs(page.PageList, UnifiedJob):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.unified_jobs,
|
||||
resources.instance_related_jobs,
|
||||
resources.instance_group_related_jobs,
|
||||
resources.schedules_jobs], UnifiedJobs)
|
||||
page.register_page([resources.unified_jobs, resources.instance_related_jobs, resources.instance_group_related_jobs, resources.schedules_jobs], UnifiedJobs)
|
||||
|
||||
@@ -13,26 +13,13 @@ class User(HasCreate, base.Base):
|
||||
|
||||
def payload(self, **kwargs):
|
||||
payload = PseudoNamespace(
|
||||
username=kwargs.get('username') or 'User-{}'.format(
|
||||
random_title(
|
||||
non_ascii=False)),
|
||||
username=kwargs.get('username') or 'User-{}'.format(random_title(non_ascii=False)),
|
||||
password=kwargs.get('password') or config.credentials.default.password,
|
||||
is_superuser=kwargs.get(
|
||||
'is_superuser',
|
||||
False),
|
||||
is_system_auditor=kwargs.get(
|
||||
'is_system_auditor',
|
||||
False),
|
||||
first_name=kwargs.get(
|
||||
'first_name',
|
||||
random_title()),
|
||||
last_name=kwargs.get(
|
||||
'last_name',
|
||||
random_title()),
|
||||
email=kwargs.get(
|
||||
'email',
|
||||
'{}@example.com'.format(random_title(5, non_ascii=False))
|
||||
)
|
||||
is_superuser=kwargs.get('is_superuser', False),
|
||||
is_system_auditor=kwargs.get('is_system_auditor', False),
|
||||
first_name=kwargs.get('first_name', random_title()),
|
||||
last_name=kwargs.get('last_name', random_title()),
|
||||
email=kwargs.get('email', '{}@example.com'.format(random_title(5, non_ascii=False))),
|
||||
)
|
||||
return payload
|
||||
|
||||
@@ -42,8 +29,7 @@ class User(HasCreate, base.Base):
|
||||
return payload
|
||||
|
||||
def create(self, username='', password='', organization=None, **kwargs):
|
||||
payload = self.create_payload(
|
||||
username=username, password=password, **kwargs)
|
||||
payload = self.create_payload(username=username, password=password, **kwargs)
|
||||
self.password = payload.password
|
||||
|
||||
self.update_identity(Users(self.connection).post(payload))
|
||||
@@ -54,8 +40,7 @@ class User(HasCreate, base.Base):
|
||||
return self
|
||||
|
||||
|
||||
page.register_page([resources.user,
|
||||
(resources.users, 'post')], User)
|
||||
page.register_page([resources.user, (resources.users, 'post')], User)
|
||||
|
||||
|
||||
class Users(page.PageList, User):
|
||||
@@ -63,11 +48,9 @@ class Users(page.PageList, User):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.users,
|
||||
resources.organization_admins,
|
||||
resources.related_users,
|
||||
resources.credential_owner_users,
|
||||
resources.user_admin_organizations], Users)
|
||||
page.register_page(
|
||||
[resources.users, resources.organization_admins, resources.related_users, resources.credential_owner_users, resources.user_admin_organizations], Users
|
||||
)
|
||||
|
||||
|
||||
class Me(Users):
|
||||
|
||||
@@ -5,7 +5,6 @@ from awxkit import exceptions
|
||||
|
||||
|
||||
class WorkflowApproval(UnifiedJob):
|
||||
|
||||
def approve(self):
|
||||
try:
|
||||
self.related.approve.post()
|
||||
|
||||
@@ -5,7 +5,6 @@ from . import page
|
||||
|
||||
|
||||
class WorkflowJobNode(base.Base):
|
||||
|
||||
def wait_for_job(self, interval=5, timeout=60, **kw):
|
||||
"""Waits until node's job exists"""
|
||||
adjusted_timeout = timeout - seconds_since_date_string(self.created)
|
||||
@@ -30,8 +29,13 @@ class WorkflowJobNodes(page.PageList, WorkflowJobNode):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.workflow_job_nodes,
|
||||
resources.workflow_job_workflow_nodes,
|
||||
resources.workflow_job_node_always_nodes,
|
||||
resources.workflow_job_node_failure_nodes,
|
||||
resources.workflow_job_node_success_nodes], WorkflowJobNodes)
|
||||
page.register_page(
|
||||
[
|
||||
resources.workflow_job_nodes,
|
||||
resources.workflow_job_workflow_nodes,
|
||||
resources.workflow_job_node_always_nodes,
|
||||
resources.workflow_job_node_failure_nodes,
|
||||
resources.workflow_job_node_success_nodes,
|
||||
],
|
||||
WorkflowJobNodes,
|
||||
)
|
||||
|
||||
@@ -15,12 +15,9 @@ class WorkflowJobTemplateNode(HasCreate, base.Base):
|
||||
def payload(self, workflow_job_template, unified_job_template, **kwargs):
|
||||
if not unified_job_template:
|
||||
# May pass "None" to explicitly create an approval node
|
||||
payload = PseudoNamespace(
|
||||
workflow_job_template=workflow_job_template.id)
|
||||
payload = PseudoNamespace(workflow_job_template=workflow_job_template.id)
|
||||
else:
|
||||
payload = PseudoNamespace(
|
||||
workflow_job_template=workflow_job_template.id,
|
||||
unified_job_template=unified_job_template.id)
|
||||
payload = PseudoNamespace(workflow_job_template=workflow_job_template.id, unified_job_template=unified_job_template.id)
|
||||
|
||||
optional_fields = (
|
||||
'diff_mode',
|
||||
@@ -33,7 +30,8 @@ class WorkflowJobTemplateNode(HasCreate, base.Base):
|
||||
'verbosity',
|
||||
'extra_data',
|
||||
'identifier',
|
||||
'all_parents_must_converge')
|
||||
'all_parents_must_converge',
|
||||
)
|
||||
|
||||
update_payload(payload, optional_fields, kwargs)
|
||||
|
||||
@@ -42,45 +40,23 @@ class WorkflowJobTemplateNode(HasCreate, base.Base):
|
||||
|
||||
return payload
|
||||
|
||||
def create_payload(
|
||||
self,
|
||||
workflow_job_template=WorkflowJobTemplate,
|
||||
unified_job_template=JobTemplate,
|
||||
**kwargs):
|
||||
def create_payload(self, workflow_job_template=WorkflowJobTemplate, unified_job_template=JobTemplate, **kwargs):
|
||||
if not unified_job_template:
|
||||
self.create_and_update_dependencies(workflow_job_template)
|
||||
payload = self.payload(
|
||||
workflow_job_template=self.ds.workflow_job_template,
|
||||
unified_job_template=None,
|
||||
**kwargs)
|
||||
payload = self.payload(workflow_job_template=self.ds.workflow_job_template, unified_job_template=None, **kwargs)
|
||||
else:
|
||||
self.create_and_update_dependencies(
|
||||
workflow_job_template, unified_job_template)
|
||||
payload = self.payload(
|
||||
workflow_job_template=self.ds.workflow_job_template,
|
||||
unified_job_template=self.ds.unified_job_template,
|
||||
**kwargs)
|
||||
self.create_and_update_dependencies(workflow_job_template, unified_job_template)
|
||||
payload = self.payload(workflow_job_template=self.ds.workflow_job_template, unified_job_template=self.ds.unified_job_template, **kwargs)
|
||||
payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store)
|
||||
return payload
|
||||
|
||||
def create(
|
||||
self,
|
||||
workflow_job_template=WorkflowJobTemplate,
|
||||
unified_job_template=JobTemplate,
|
||||
**kwargs):
|
||||
payload = self.create_payload(
|
||||
workflow_job_template=workflow_job_template,
|
||||
unified_job_template=unified_job_template,
|
||||
**kwargs)
|
||||
return self.update_identity(
|
||||
WorkflowJobTemplateNodes(
|
||||
self.connection).post(payload))
|
||||
def create(self, workflow_job_template=WorkflowJobTemplate, unified_job_template=JobTemplate, **kwargs):
|
||||
payload = self.create_payload(workflow_job_template=workflow_job_template, unified_job_template=unified_job_template, **kwargs)
|
||||
return self.update_identity(WorkflowJobTemplateNodes(self.connection).post(payload))
|
||||
|
||||
def _add_node(self, endpoint, unified_job_template, **kwargs):
|
||||
node = endpoint.post(
|
||||
dict(unified_job_template=unified_job_template.id, **kwargs))
|
||||
node.create_and_update_dependencies(
|
||||
self.ds.workflow_job_template, unified_job_template)
|
||||
node = endpoint.post(dict(unified_job_template=unified_job_template.id, **kwargs))
|
||||
node.create_and_update_dependencies(self.ds.workflow_job_template, unified_job_template)
|
||||
return node
|
||||
|
||||
def add_always_node(self, unified_job_template, **kwargs):
|
||||
@@ -94,24 +70,18 @@ class WorkflowJobTemplateNode(HasCreate, base.Base):
|
||||
|
||||
def add_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
dict(id=credential.id, associate=True))
|
||||
self.related.credentials.post(dict(id=credential.id, associate=True))
|
||||
|
||||
def remove_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
dict(id=credential.id, disassociate=True))
|
||||
self.related.credentials.post(dict(id=credential.id, disassociate=True))
|
||||
|
||||
def remove_all_credentials(self):
|
||||
for cred in self.related.credentials.get().results:
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
dict(id=cred.id, disassociate=True))
|
||||
self.related.credentials.post(dict(id=cred.id, disassociate=True))
|
||||
|
||||
def make_approval_node(
|
||||
self,
|
||||
**kwargs
|
||||
):
|
||||
def make_approval_node(self, **kwargs):
|
||||
if 'name' not in kwargs:
|
||||
kwargs['name'] = 'approval node {}'.format(random_title())
|
||||
self.related.create_approval_template.post(kwargs)
|
||||
@@ -122,10 +92,10 @@ class WorkflowJobTemplateNode(HasCreate, base.Base):
|
||||
return candidates.results.pop()
|
||||
|
||||
|
||||
page.register_page([resources.workflow_job_template_node,
|
||||
(resources.workflow_job_template_nodes, 'post'),
|
||||
(resources.workflow_job_template_workflow_nodes, 'post')],
|
||||
WorkflowJobTemplateNode)
|
||||
page.register_page(
|
||||
[resources.workflow_job_template_node, (resources.workflow_job_template_nodes, 'post'), (resources.workflow_job_template_workflow_nodes, 'post')],
|
||||
WorkflowJobTemplateNode,
|
||||
)
|
||||
|
||||
|
||||
class WorkflowJobTemplateNodes(page.PageList, WorkflowJobTemplateNode):
|
||||
@@ -133,9 +103,13 @@ class WorkflowJobTemplateNodes(page.PageList, WorkflowJobTemplateNode):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.workflow_job_template_nodes,
|
||||
resources.workflow_job_template_workflow_nodes,
|
||||
resources.workflow_job_template_node_always_nodes,
|
||||
resources.workflow_job_template_node_failure_nodes,
|
||||
resources.workflow_job_template_node_success_nodes],
|
||||
WorkflowJobTemplateNodes)
|
||||
page.register_page(
|
||||
[
|
||||
resources.workflow_job_template_nodes,
|
||||
resources.workflow_job_template_workflow_nodes,
|
||||
resources.workflow_job_template_node_always_nodes,
|
||||
resources.workflow_job_template_node_failure_nodes,
|
||||
resources.workflow_job_template_node_success_nodes,
|
||||
],
|
||||
WorkflowJobTemplateNodes,
|
||||
)
|
||||
|
||||
@@ -26,15 +26,14 @@ class WorkflowJobTemplate(HasCopy, HasCreate, HasNotifications, HasSurvey, Unifi
|
||||
# return job
|
||||
jobs_pg = self.related.workflow_jobs.get(id=result.workflow_job)
|
||||
if jobs_pg.count != 1:
|
||||
msg = "workflow_job_template launched (id:{}) but job not found in response at {}/workflow_jobs/".format(
|
||||
result.json['workflow_job'], self.url
|
||||
)
|
||||
msg = "workflow_job_template launched (id:{}) but job not found in response at {}/workflow_jobs/".format(result.json['workflow_job'], self.url)
|
||||
raise exc.UnexpectedAWXState(msg)
|
||||
return jobs_pg.results[0]
|
||||
|
||||
def payload(self, **kwargs):
|
||||
payload = PseudoNamespace(name=kwargs.get('name') or 'WorkflowJobTemplate - {}'.format(random_title()),
|
||||
description=kwargs.get('description') or random_title(10))
|
||||
payload = PseudoNamespace(
|
||||
name=kwargs.get('name') or 'WorkflowJobTemplate - {}'.format(random_title()), description=kwargs.get('description') or random_title(10)
|
||||
)
|
||||
|
||||
optional_fields = (
|
||||
"allow_simultaneous",
|
||||
@@ -91,9 +90,9 @@ class WorkflowJobTemplate(HasCopy, HasCreate, HasNotifications, HasSurvey, Unifi
|
||||
self.related.labels.post(label)
|
||||
|
||||
|
||||
page.register_page([resources.workflow_job_template,
|
||||
(resources.workflow_job_templates, 'post'),
|
||||
(resources.workflow_job_template_copy, 'post')], WorkflowJobTemplate)
|
||||
page.register_page(
|
||||
[resources.workflow_job_template, (resources.workflow_job_templates, 'post'), (resources.workflow_job_template_copy, 'post')], WorkflowJobTemplate
|
||||
)
|
||||
|
||||
|
||||
class WorkflowJobTemplates(page.PageList, WorkflowJobTemplate):
|
||||
@@ -101,8 +100,7 @@ class WorkflowJobTemplates(page.PageList, WorkflowJobTemplate):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.workflow_job_templates,
|
||||
resources.related_workflow_job_templates], WorkflowJobTemplates)
|
||||
page.register_page([resources.workflow_job_templates, resources.related_workflow_job_templates], WorkflowJobTemplates)
|
||||
|
||||
|
||||
class WorkflowJobTemplateLaunch(base.Base):
|
||||
|
||||
@@ -4,7 +4,6 @@ from . import page
|
||||
|
||||
|
||||
class WorkflowJob(UnifiedJob):
|
||||
|
||||
def __str__(self):
|
||||
# TODO: Update after endpoint's fields are finished filling out
|
||||
return super(UnifiedJob, self).__str__()
|
||||
@@ -56,7 +55,4 @@ class WorkflowJobs(page.PageList, WorkflowJob):
|
||||
pass
|
||||
|
||||
|
||||
page.register_page([resources.workflow_jobs,
|
||||
resources.workflow_job_template_jobs,
|
||||
resources.job_template_slice_workflow_jobs],
|
||||
WorkflowJobs)
|
||||
page.register_page([resources.workflow_jobs, resources.workflow_job_template_jobs, resources.job_template_slice_workflow_jobs], WorkflowJobs)
|
||||
|
||||
@@ -8,7 +8,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class URLRegistry(object):
|
||||
|
||||
def __init__(self):
|
||||
self.store = defaultdict(dict)
|
||||
self.default = {}
|
||||
@@ -81,8 +80,7 @@ class URLRegistry(object):
|
||||
if method_pattern.pattern == not_provided:
|
||||
exc_msg = '"{0.pattern}" already has methodless registration.'.format(url_pattern)
|
||||
else:
|
||||
exc_msg = ('"{0.pattern}" already has registered method "{1.pattern}"'
|
||||
.format(url_pattern, method_pattern))
|
||||
exc_msg = '"{0.pattern}" already has registered method "{1.pattern}"'.format(url_pattern, method_pattern)
|
||||
raise TypeError(exc_msg)
|
||||
self.store[url_pattern][method_pattern] = resource
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
class Resources(object):
|
||||
|
||||
_activity = r'activity_stream/\d+/'
|
||||
|
||||
@@ -15,12 +15,11 @@ def freeze(key):
|
||||
|
||||
def parse_description(desc):
|
||||
options = {}
|
||||
for line in desc[desc.index('POST'):].splitlines():
|
||||
for line in desc[desc.index('POST') :].splitlines():
|
||||
match = descRE.match(line)
|
||||
if not match:
|
||||
continue
|
||||
options[match.group(1)] = {'type': match.group(2),
|
||||
'required': match.group(3) == 'required'}
|
||||
options[match.group(1)] = {'type': match.group(2), 'required': match.group(3) == 'required'}
|
||||
return options
|
||||
|
||||
|
||||
@@ -45,6 +44,5 @@ def get_post_fields(page, cache):
|
||||
if 'POST' in options_page.json['actions']:
|
||||
return options_page.json['actions']['POST']
|
||||
else:
|
||||
log.warning(
|
||||
"Insufficient privileges on %s, inferring POST fields from description.", options_page.endpoint)
|
||||
log.warning("Insufficient privileges on %s, inferring POST fields from description.", options_page.endpoint)
|
||||
return parse_description(options_page.json['description'])
|
||||
|
||||
Reference in New Issue
Block a user