Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion openshift/ansiblegen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
'openshift': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False
'propagate': True
},
},
'root': {
Expand Down
3 changes: 2 additions & 1 deletion openshift/ansiblegen/docstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

logger = logging.getLogger(__name__)


# Once the modules land in Ansible core, this should not change
ANSIBLE_VERSION_ADDED = "2.3.0"

Expand Down Expand Up @@ -92,7 +93,7 @@ def add_option(pname, pdict, descr=None):
if pdict.get('type') and pdict.get('type') != 'str':
doc_string['options'][pname]['type'] = pdict['type']

for param_name in sorted(self.helper.argspec.keys()):
for param_name in sorted([x for x, _ in self.helper.argspec.items()]):
param_dict = self.helper.argspec[param_name]
if param_name.endswith('params'):
descr = [self.__params_descr(param_name)]
Expand Down
3 changes: 1 addition & 2 deletions openshift/ansiblegen/examples/v1_route.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@
-----BEGIN CERTIFICATE-----
ca_certificate_contents
-----END CERTIFICATE-----
tls_destination_ca_certificate:
name: Create route
name: Replace route

- remove:
name: myroute
Expand Down
111 changes: 76 additions & 35 deletions openshift/helper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

from logging import config as logging_config

from dictdiffer import diff

from kubernetes import config, watch
from kubernetes.client.rest import ApiException
from kubernetes.config.config_exception import ConfigException
Expand Down Expand Up @@ -114,25 +116,25 @@ def enable_debug(reset_logfile=True):

def get_object(self, name, namespace=None):
k8s_obj = None
method_name = 'list' if self.kind.endswith('list') else 'read'
try:
get_method = self.lookup_method('read', namespace)
if namespace is None:
get_method = self.lookup_method(method_name, namespace)
if name and namespace is None:
k8s_obj = get_method(name)
elif namespace and not name:
k8s_obj = get_method(namespace)
else:
k8s_obj = get_method(name, namespace)
except ApiException as ex:
if ex.status != 404:
if self.base_model_name == 'Project'and ex.status == 403:
except ApiException as exc:
if exc.status != 404:
if self.base_model_name == 'Project'and exc.status == 403:
pass
else:
if ex.body:
msg = json.loads(ex.body).get('message', ex.reason)
else:
msg = str(ex)
raise OpenShiftException(msg, status=ex.status)
msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body
raise OpenShiftException(msg, status=exc.status)
return k8s_obj

def patch_object(self, name, namespace, k8s_obj, wait=False, timeout=60):
def patch_object(self, name, namespace, k8s_obj):
empty_status = self.properties['status']['class']()
k8s_obj.status = empty_status
k8s_obj.metadata.resource_version = None
Expand All @@ -142,11 +144,11 @@ def patch_object(self, name, namespace, k8s_obj, wait=False, timeout=60):
try:
patch_method = self.lookup_method('patch', namespace)
if namespace:
return_obj = patch_method(name, namespace, k8s_obj)
patch_method(name, namespace, k8s_obj)
else:
return_obj = patch_method(name, k8s_obj)
patch_method(name, k8s_obj)
except ApiException as exc:
msg = json.loads(exc.body).get('message', exc.reason)
msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body
raise OpenShiftException(msg, status=exc.status)
#return_obj = self.__read_stream(w, stream, 'patch', name, namespace)
return_obj = self.__wait_for_response(name, namespace, 'patch')
Expand All @@ -157,32 +159,49 @@ def create_project(self, metadata, display_name=None, description=None):
try:
proj_req = client.V1ProjectRequest(metadata=metadata, display_name=display_name, description=description)
client.OapiApi().create_project_request(proj_req)
except ApiException as ex:
msg = json.loads(ex.body).get('message', ex.reason)
except ApiException as exc:
msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body
raise OpenShiftException(msg, status=ex.status)

return_obj = self.__wait_for_response(metadata.name, None, 'create')

return return_obj

def create_object(self, namespace, k8s_obj):
def create_object(self, namespace, k8s_obj=None, body=None):
"""
Send a POST request to the API. Pass either k8s_obj or body.
:param namespace: namespace value or None
:param k8s_obj: optional k8s object model
:param body: optional JSON dict
:return: new object returned from the API
"""
#w, stream = self.__create_stream(namespace)
if k8s_obj:
name = k8s_obj.metadata.name
elif body:
name = body.get('metadata', {}).get('name', None)
try:
create_method = self.lookup_method('create', namespace)
if namespace is None:
create_method(k8s_obj)
if namespace:
if k8s_obj:
create_method(namespace, k8s_obj)
else:
create_method(namespace, body=body)
else:
create_method(namespace, k8s_obj)
if k8s_obj:
create_method(k8s_obj)
else:
create_method(body=body)
except ApiException as exc:
msg = json.loads(exc.body).get('message', exc.reason)
msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body
raise OpenShiftException(msg, status=exc.status)
#return_obj = self.__read_stream(w, stream, 'create', k8s_obj.metadata.name, namespace)

# Allow OpenShift annotations to be added to Namespace
if isinstance(k8s_obj, client.models.V1Namespace):
time.sleep(1)

return_obj = self.__wait_for_response(k8s_obj.metadata.name, namespace, 'create')
return_obj = self.__wait_for_response(name, namespace, 'create')
return return_obj

def delete_object(self, name, namespace):
Expand All @@ -204,38 +223,60 @@ def delete_object(self, name, namespace):
else:
delete_method(name, namespace)
except ApiException as exc:
msg = json.loads(exc.body).get('message', exc.reason)
msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body
raise OpenShiftException(msg, status=exc.status)
#self.__read_stream(w, stream, 'delete', name, namespace)
self.__wait_for_response(name, namespace, 'delete')

def replace_object(self, name, namespace, k8s_obj):
empty_status = self.properties['status']['class']()
k8s_obj.status = empty_status
self.__remove_creation_timestamps(k8s_obj)
def replace_object(self, name, namespace, k8s_obj=None, body=None):
""" Replace an existing object. Pass in a model object or request dict().
Will first lookup the existing object to get the resource version and
update the request.
"""
existing_obj = self.get_object(name, namespace)
if not existing_obj:
msg = "Error: Replacing object. Unable to find {}".format(name)
msg += " in namespace {}".format(namespace) if namespace else ""
raise OpenShiftException(msg)
if k8s_obj:
k8s_obj.status = self.properties['status']['class']()
self.__remove_creation_timestamps(k8s_obj)
k8s_obj.metadata.resource_version = existing_obj.metadata.resource_version
elif body:
body['metadata']['resourceVersion'] = existing_obj.metadata.resource_version
#w, stream = self.__create_stream(namespace)
try:
replace_method = self.lookup_method('replace', namespace)
if namespace is None:
return_obj = replace_method(name, k8s_obj)
if k8s_obj:
if namespace is None:
replace_method(name, k8s_obj)
else:
replace_method(name, namespace, k8s_obj)
else:
return_obj = replace_method(name, namespace, k8s_obj)
if namespace is None:
replace_method(name, body=body)
else:
replace_method(name, namespace, body=body)
except ApiException as exc:
msg = json.loads(exc.body).get('message', exc.reason)
msg = json.loads(exc.body).get('message', exc.reason) if exc.body.startswith('{') else exc.body
raise OpenShiftException(msg, status=exc.status)
#retur_obj = self.__read_stream(w, stream, 'replace', name, namespace)
#return_obj = self.__read_stream(w, stream, 'replace', name, namespace)
return_obj = self.__wait_for_response(name, namespace, 'replace')
return return_obj

def objects_match(self, obj_a, obj_b):
""" Test the equality of two objects. """
""" Test the equality of two objects. Returns bool, diff object. Use list(diff object) to
log or iterate over differences """
if obj_a is None and obj_b is None:
return True
if not obj_a or not obj_b:
return False
if type(obj_a).__name__ != type(obj_b).__name__:
return False
return obj_a == obj_b
dict_a = obj_a.to_dict()
dict_b = obj_b.to_dict()
diff_result = diff(dict_a, dict_b)
return obj_a == obj_b, diff_result

@classmethod
def properties_from_model_obj(cls, model_obj):
Expand Down Expand Up @@ -285,7 +326,7 @@ def lookup_method(self, operation, namespace=None):

method_name = operation
method_name += '_namespaced_' if namespace else '_'
method_name += self.kind
method_name += self.kind.replace('_list', '') if self.kind.endswith('_list') else self.kind

apis = [x for x in dir(client.apis) if VERSION_RX.search(x)]
apis.append('OapiApi')
Expand Down
Loading