diff --git a/cloudcafe/cloudkeep/barbican/verifications/__init__.py b/cloudcafe/cloudkeep/barbican/verifications/__init__.py new file mode 100644 index 00000000..59ab77fa --- /dev/null +++ b/cloudcafe/cloudkeep/barbican/verifications/__init__.py @@ -0,0 +1,15 @@ +""" +Copyright 2013 Rackspace + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" diff --git a/cloudcafe/cloudkeep/barbican/verifications/behaviors.py b/cloudcafe/cloudkeep/barbican/verifications/behaviors.py new file mode 100644 index 00000000..43f6ee22 --- /dev/null +++ b/cloudcafe/cloudkeep/barbican/verifications/behaviors.py @@ -0,0 +1,146 @@ +""" +Copyright 2013 Rackspace + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from httplib import BadStatusLine +from requests.exceptions import ConnectionError +from cloudcafe.cloudkeep.common.responses import CloudkeepResponse + + +class VerificationsBehavior(object): + + def __init__(self, verifications_client, config): + super(VerificationsBehavior, self).__init__() + self.verifications_client = verifications_client + self.config = config + self.created_verifications = [] + + def create_and_check_verification(self, resource_type=None, + resource_ref=None, + resource_action=None, + impersonation_allowed=False): + """Creates verification, gets verification.""" + resp = self.create_verification_overriding_cfg( + resource_type=resource_type, resource_ref=resource_ref, + resource_action=resource_action, + impersonation_allowed=impersonation_allowed) + + get_verification_resp = self.verifications_client.get_verification( + verification_id=resp.id) + behavior_response = CloudkeepResponse(resp=resp.create_resp, + get_resp=get_verification_resp) + return behavior_response + + def create_verification_from_config(self): + """Creates verification from configuration.""" + + resp = self.create_verification( + resource_type=self.config.resource_type, + resource_ref=self.config.resource_ref, + resource_action=self.config.resource_action, + impersonation_allowed=self.config.impersonation_allowed) + return resp + + def create_verification_overriding_cfg(self, resource_type=None, + resource_ref=None, + resource_action=None, + impersonation_allowed=False): + """Creates verification using provided parameters or default + configurations. Allows for testing individual parameters on creation. + """ + if impersonation_allowed is None: + imp_allowed = False + else: + imp_allowed = impersonation_allowed + + resp = self.create_verification( + resource_type=resource_type or self.config.resource_type, + resource_ref=resource_ref or self.config.resource_ref, + resource_action=resource_action or self.config.resource_action, + impersonation_allowed=imp_allowed) + + return resp + + def create_verification(self, + resource_type=None, + resource_ref=None, + resource_action=None, + impersonation_allowed=False): + try: + resp = self.verifications_client.create_verification( + resource_type=resource_type, + resource_ref=resource_ref, + resource_action=resource_action, + impersonation_allowed=impersonation_allowed) + except ConnectionError as e: + # Gracefully handling when Falcon doesn't properly handle our req + if type(e.message.reason) is BadStatusLine: + return {'status_code': 0} + raise e + + behavior_response = CloudkeepResponse(resp=resp) + verification_id = behavior_response.id + if verification_id is not None: + self.created_verifications.append(behavior_response.id) + return behavior_response + + def delete_verification(self, verification_id): + resp = self.verifications_client.delete_verification(verification_id) + if verification_id in self.created_verifications: + self.created_verifications.remove(verification_id) + return resp + + def delete_all_verifications_in_db(self): + verification_group = \ + self.verifications_client.get_verifications().entity + found_ids = [] + found_ids.extend(verification_group.get_ids()) + + while verification_group.next is not None: + query = verification_group.get_next_query_data() + verification_group = self.verifications_client.get_verifications( + limit=query.get('limit'), + offset=query.get('offset')).entity + found_ids.extend(verification_group.get_ids()) + + for verification_id in found_ids: + self.delete_verification(verification_id) + + def delete_all_created_verifications(self): + for verification_id in list(self.created_verifications): + self.delete_verification(verification_id) + self.created_verifications = [] + + def remove_from_created_verifications(self, verification_id): + if verification_id in self.created_verifications: + self.created_verifications.remove(verification_id) + + def find_verification(self, verification_id): + verification_group = \ + self.verifications_client.get_verifications().entity + + ids = verification_group.get_ids() + while verification_id not in ids and \ + verification_group.next is not None: + query = verification_group.get_next_query_data() + verification_group = self.verifications_client.get_verifications( + limit=query.get('limit'), + offset=query.get('offset')).entity + ids = verification_group.get_ids() + + for verification in verification_group.verifications: + if verification.get_id() == verification_id: + return verification + else: + return None diff --git a/cloudcafe/cloudkeep/barbican/verifications/client.py b/cloudcafe/cloudkeep/barbican/verifications/client.py new file mode 100644 index 00000000..9860d3e0 --- /dev/null +++ b/cloudcafe/cloudkeep/barbican/verifications/client.py @@ -0,0 +1,86 @@ +""" +Copyright 2013 Rackspace + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from cloudcafe.cloudkeep.barbican.client import BarbicanRestClient +from cloudcafe.cloudkeep.barbican.verifications.models.verification \ + import Verification, VerificationRequest, \ + VerificationRef, VerificationGroup + + +class VerificationsClient(BarbicanRestClient): + + def __init__(self, url, api_version, tenant_id, token=None, + serialize_format=None, deserialize_format=None): + super(VerificationsClient, self).__init__( + token=token, serialize_format=serialize_format, + deserialize_format=deserialize_format) + self.url = url + self.api_version = api_version + self.tenant_id = tenant_id + + def _get_base_url(self): + return '{base}/{api_version}/{tenant_id}/verifications'.format( + base=self.url, + api_version=self.api_version, + tenant_id=self.tenant_id) + + def _get_verification_url(self, verification_id): + return '{base}/{verification_id}'.format( + base=self._get_base_url(), verification_id=verification_id) + + def create_verification(self, resource_type=None, resource_ref=None, + resource_action=None, impersonation_allowed=False): + """ + POST http://.../v1/{tenant_id}/verifications + Creates a request to verify a resource + """ + remote_url = self._get_base_url() + req_obj = VerificationRequest(resource_type=resource_type, + resource_ref=resource_ref, + resource_action=resource_action, + impersonation_allowed= + impersonation_allowed) + + resp = self.request('POST', remote_url, request_entity=req_obj, + response_entity_type=VerificationRef) + return resp + + def get_verification(self, verification_id=None, ref=None): + """ + GET http://.../v1/{tenant_id}/verifications/{verification_uuid} + Retrieves a verification + """ + remote_url = ref or self._get_verification_url(verification_id) + return self.request('GET', remote_url, + response_entity_type=Verification) + + def delete_verification(self, verification_id): + """ + DELETE http://.../v1/{tenant_id}/verifications/{verification_uuid} + Cancels a verification + """ + return self.request('DELETE', + self._get_verification_url(verification_id)) + + def get_verifications(self, limit=None, offset=None, ref=None): + """ + GET http://.../v1/verifications?limit={limit}&offset={offset} or {ref} + Gets a list of verifications + """ + remote_url = ref or self._get_base_url() + resp = self.request('GET', remote_url, + params={'limit': limit, 'offset': offset}, + response_entity_type=VerificationGroup) + return resp diff --git a/cloudcafe/cloudkeep/barbican/verifications/models/__init__.py b/cloudcafe/cloudkeep/barbican/verifications/models/__init__.py new file mode 100644 index 00000000..59ab77fa --- /dev/null +++ b/cloudcafe/cloudkeep/barbican/verifications/models/__init__.py @@ -0,0 +1,15 @@ +""" +Copyright 2013 Rackspace + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" diff --git a/cloudcafe/cloudkeep/barbican/verifications/models/verification.py b/cloudcafe/cloudkeep/barbican/verifications/models/verification.py new file mode 100644 index 00000000..002c8f7b --- /dev/null +++ b/cloudcafe/cloudkeep/barbican/verifications/models/verification.py @@ -0,0 +1,175 @@ +""" +Copyright 2013 Rackspace + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +import re +from os import path +from json import dumps as dict_to_str, loads as str_to_dict + +from cafe.engine.models.base import AutoMarshallingModel + + +class VerificationRequest(AutoMarshallingModel): + + def __init__(self, + resource_action=None, + resource_ref=None, + impersonation_allowed=False, + resource_type=None): + super(VerificationRequest, self).__init__() + self.resource_action = resource_action + self.resource_ref = resource_ref + self.impersonation_allowed = impersonation_allowed + self.resource_type = resource_type + + def get_id_from_ref(self, ref): + """Returns id from reference.""" + ref_id = None + if ref is not None and len(ref) > 0: + ref_id = path.split(ref)[1] + return ref_id + + def get_id(self): + """Returns verification id.""" + return self.get_id_from_ref(ref=self.verification_ref) + + def _obj_to_json(self): + the_dict = { + 'resource_action': self.resource_action, + 'resource_ref': self.resource_ref, + 'impersonation_allowed': self.impersonation_allowed, + 'resource_type': self.resource_type + } + return dict_to_str(the_dict) + + @classmethod + def _json_to_obj(cls, serialized_str): + json_dict = str_to_dict(serialized_str) + return cls._dict_to_obj(json_dict) + + @classmethod + def _dict_to_obj(cls, json_dict): + args = { + 'resource_action': json_dict.get('resource_action'), + 'resource_ref': json_dict.get('resource_ref'), + 'impersonation_allowed': json_dict.get('impersonation_allowed'), + 'resource_type': json_dict.get('resource_type') + } + return Verification(**args) + + +class Verification(AutoMarshallingModel): + + def __init__(self, status=None, updated=None, created=None, + resource_action=None, resource_ref=None, + impersonation_allowed=False, verification_ref=None, + is_verified=None, resource_type=None): + super(Verification, self).__init__() + self.status = status + self.updated = updated + self.created = created + self.resource_action = resource_action + self.resource_ref = resource_ref + self.impersonation_allowed = impersonation_allowed + self.verification_ref = verification_ref + self.is_verified = is_verified + self.resource_type = resource_type + + def get_id_from_ref(self, ref): + """Returns id from reference.""" + ref_id = None + if ref is not None and len(ref) > 0: + ref_id = path.split(ref)[1] + return ref_id + + def get_id(self): + """Returns verification id.""" + return self.get_id_from_ref(ref=self.verification_ref) + + def _obj_to_json(self): + return dict_to_str(self._obj_to_dict()) + + @classmethod + def _json_to_obj(cls, serialized_str): + json_dict = str_to_dict(serialized_str) + return cls._dict_to_obj(json_dict) + + @classmethod + def _dict_to_obj(cls, json_dict): + args = { + 'status': json_dict.get('status'), + 'updated': json_dict.get('updated'), + 'created': json_dict.get('created'), + 'resource_action': json_dict.get('resource_action'), + 'resource_ref': json_dict.get('resource_ref'), + 'impersonation_allowed': json_dict.get('impersonation_allowed'), + 'verification_ref': json_dict.get('verification_ref'), + 'is_verified': json_dict.get('is_verified'), + 'resource_type': json_dict.get('resource_type') + } + return Verification(**args) + + +class VerificationRef(AutoMarshallingModel): + + def __init__(self, reference): + super(VerificationRef, self).__init__() + self.reference = reference + + @classmethod + def _json_to_obj(cls, serialized_str): + json_dict = str_to_dict(serialized_str) + return cls._dict_to_obj(json_dict) + + @classmethod + def _dict_to_obj(cls, json_dict): + return VerificationRef(reference=json_dict.get('verification_ref')) + + +class VerificationGroup(AutoMarshallingModel): + + def __init__(self, verifications, next_list=None, previous_list=None): + super(VerificationGroup, self).__init__() + + self.verifications = verifications + self.next = next_list + self.previous = previous_list + + def get_ids(self): + return [verification.get_id() for verification in self.verifications] + + def get_next_query_data(self): + matches = re.search('.*\?(.*?)\=(\d*)&(.*?)\=(\d*)', self.next) + return { + 'limit': matches.group(2), + 'offset': matches.group(4) + } + + @classmethod + def _json_to_obj(cls, serialized_str): + json_dict = str_to_dict(serialized_str) + return cls._dict_to_obj(json_dict) + + @classmethod + def _dict_to_obj(cls, json_dict): + verifications, next_list, prev_list = [], None, None + + for verification_dict in json_dict.get('verifications'): + verifications.append(Verification._dict_to_obj(verification_dict)) + + if 'next' in json_dict: + next_list = json_dict.get('next') + if 'previous' in json_dict: + prev_list = json_dict.get('previous') + return VerificationGroup(verifications, next_list, prev_list) diff --git a/cloudcafe/cloudkeep/common/states.py b/cloudcafe/cloudkeep/common/states.py index 5a6c2c5b..fab27d2e 100644 --- a/cloudcafe/cloudkeep/common/states.py +++ b/cloudcafe/cloudkeep/common/states.py @@ -22,3 +22,7 @@ class SecretsStates(object): class OrdersStates(SecretsStates): PENDING = "PENDING" + + +class VerificationsStates(SecretsStates): + PENDING = "PENDING" diff --git a/cloudcafe/cloudkeep/config.py b/cloudcafe/cloudkeep/config.py index 1fff8f8a..ad52f835 100644 --- a/cloudcafe/cloudkeep/config.py +++ b/cloudcafe/cloudkeep/config.py @@ -123,3 +123,23 @@ class CloudKeepRBACRoleConfig(ConfigSectionInterface): @property def audit(self): return self.get('audit') + + +class CloudKeepVerificationsConfig(ConfigSectionInterface): + SECTION_NAME = 'cloudkeep-verifications' + + @property + def resource_type(self): + return self.get("resource_type") + + @property + def resource_ref(self): + return self.get("resource_ref") + + @property + def resource_action(self): + return self.get("resource_action") + + @property + def impersonation_allowed(self): + return self.get("impersonation_allowed") diff --git a/configs/cloudkeep/reference.config b/configs/cloudkeep/reference.config index da0156d7..39ff942e 100644 --- a/configs/cloudkeep/reference.config +++ b/configs/cloudkeep/reference.config @@ -34,6 +34,12 @@ payload=testdata payload_content_type=application/octet-stream payload_content_encoding=base64 +[cloudkeep-verifications] +resource_ref= +resource_type=image +resource_action=vm_attach +impersonation_allowed=False + [cloudkeep-orders] name=secretname algorithm=aes