def delete_signatures(self):
        log('ModuleExecutor.delete_signatures()')

        result = self.fetcher.delete(resource='appfwsignatures',
                                     id=self.module.params['name'])
        log('delete result %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #2
0
    def get_existing_monitor_bindings(self):
        log('ModuleExecutor.get_existing_monitor_bindings()')
        result = self.fetcher.get('service_lbmonitor_binding', self.module.params['name'])

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
        elif 'service_lbmonitor_binding' in result['data']:
            return result['data']['service_lbmonitor_binding']
        else:
            return []
Пример #3
0
    def create_ssl_certkey(self):
        log('ModuleExecutor.create_ssl_certkey()')

        processed_data = copy.deepcopy(self.configured_ssl_certkey)

        # No domain check is flag for change operation
        if 'nodomaincheck' in processed_data:
            del processed_data['nodomaincheck']

        # Flag for the delete operation
        if 'deletefromdevice' in processed_data:
            del processed_data['deletefromdevice']

        post_data = {
            'sslcertkey': processed_data
        }

        result = self.fetcher.post(post_data=post_data, resource='sslcertkey')
        log('post data: %s' % post_data)
        log('result of post: %s' % result)
        if result['http_response_data']['status'] == 201:
            if result.get('nitro_errorcode') is not None:
                if result['nitro_errorcode'] != 0:
                    raise NitroException(
                        errorcode=result['nitro_errorcode'],
                        message=result.get('nitro_message'),
                        severity=result.get('nitro_severity'),
                    )
        elif 400 <= result['http_response_data']['status'] <= 599:
            raise NitroException(
                errorcode=result.get('nitro_errorcode'),
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
        else:
            msg = 'Did not get nitro errorcode and http status was not 201 or 4xx (%s)' % result['http_response_data']['status']
            self.module.fail_json(msg=msg, **self.module_result)
    def delete_cipher(self):
        log('ModuleExecutor.delete_cipher()')

        result = self.fetcher.delete(
            resource='sslcipher',
            id=self.module.params['ciphergroupname'],
        )
        log('delete result %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #5
0
    def service_exists(self):
        log('ModuleExecutor.service_exists()')
        result = self.fetcher.get('service', self.module.params['name'])

        log('get result %s' % result)
        if result['nitro_errorcode'] == 0:
            return True
        elif result['nitro_errorcode'] == 344:
            return False
        else:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #6
0
    def delete_dnsnsrec(self):
        log('ModuleExecutor.delete_dnsnsrec()')

        args = {'nameserver': self.configured_dnsnsrec.get('nameserver')}
        result = self.fetcher.delete(resource='dnsnsrec',
                                     id=self.module.params['domain'],
                                     args=args)
        log('delete result %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #7
0
    def ssl_certkey_exists(self):
        log('ModuleExecutor.ssl_certkey_exists()')
        result = self.fetcher.get('sslcertkey', self.module.params['certkey'])

        log('get result %s' % result)
        if result['nitro_errorcode'] in [258, 1540]:
            return False
        elif result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )

        # Fallthrough
        return True
Пример #8
0
    def dnsnsrec_identical(self):
        log('ModuleExecutor.dnsnsrec_identical()')
        result = self.fetcher.get('dnsnsrec')
        retrieved_dnsnsrecs = result['data'].get('dnsnsrec', [])

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )

        diff_list = []
        # Iterate over keys that already exist in the playbook
        for retrieved_record in retrieved_dnsnsrecs:

            # Skip irrelevant ciphers
            match = all((retrieved_record['domain'] ==
                         self.configured_dnsnsrec['domain'],
                         retrieved_record['nameserver'] ==
                         self.configured_dnsnsrec['nameserver']))
            if not match:
                continue

            for attribute in self.configured_dnsnsrec.keys():
                retrieved_value = retrieved_record.get(attribute)
                configured_value = self.configured_dnsnsrec.get(attribute)
                if retrieved_value != configured_value:
                    str_tuple = (
                        attribute,
                        type(configured_value),
                        configured_value,
                        type(retrieved_value),
                        retrieved_value,
                    )
                    diff_list.append(
                        'Attribute "%s" differs. Playbook parameter: (%s) %s. Retrieved NITRO object: (%s) %s'
                        % str_tuple)
                    log('Attribute "%s" differs. Playbook parameter: (%s) %s. Retrieved NITRO object: (%s) %s'
                        % str_tuple)
            self.module_result['diff_list'] = diff_list

        if diff_list != []:
            return False
        else:
            return True
Пример #9
0
    def _binding_list_item_create(self, binding):
        log('ModuleExecutor._binding_list_item_create()')

        put_data = {self.endpoint: binding}

        log('request put data: %s' % put_data)

        result = self.fetcher.put(put_data=put_data, resource=self.endpoint)

        log('result of put: %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
    def cipher_exists(self):
        log('ModuleExecutor.cipher_exists()')
        result = self.fetcher.get('sslcipher',
                                  self.module.params['ciphergroupname'])

        log('get result %s' % result)
        if result['nitro_errorcode'] == 258:
            return False
        elif result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )

        # Fallthrough
        return True
Пример #11
0
    def non_updateable_object_delete(self):
        log('ModuleExecutor.non_updateable_object_delete()')

        args = {}
        for key in self.module.params['workflow']['delete_id_attributes']:
            if key in self.configured_object:
                args[key] = self.configured_object[key]

        result = self.fetcher.delete(resource=self.endpoint,
                                     id=self.id,
                                     args=args)
        log('delete result %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #12
0
    def delete_systemfile(self):
        log('ModuleExecutor.delete_systemfile()')

        args = {
            'filename': self.configured_systemfile['filename'],
            'filelocation': self.configured_systemfile['filelocation'],
        }
        result = self.fetcher.delete(
            resource='systemfile',
            args=args,
        )
        log('delete result %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #13
0
    def binding_create(self):
        log('ModuleExecutor.binding_create()')

        attributes = self.module.params['resource']

        put_data = {self.endpoint: attributes}

        log('request put data: %s' % put_data)

        result = self.fetcher.put(put_data=put_data, resource=self.endpoint)

        log('result of put: %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #14
0
    def delete_binding(self):
        log('ModuleExecutor.delete_binding()')

        args = {
            'ciphername': self.configured_binding['ciphername']
        }
        result = self.fetcher.delete(
            resource='sslcipher_sslciphersuite_binding',
            id=self.module.params['ciphergroupname'],
            args=args
        )
        log('delete result %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #15
0
    def service_identical(self):
        log('ModuleExecutor.service_identical()')
        result = self.fetcher.get('service', self.module.params['name'])
        retrieved_object = result['data']['service'][0]

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )

        diff_list = []
        non_updateable_list = []
        for attribute in self.configured_service.keys():
            retrieved_value = retrieved_object.get(attribute)
            configured_value = self.configured_service.get(attribute)
            if retrieved_value != configured_value:
                str_tuple = (
                    attribute,
                    type(configured_value),
                    configured_value,
                    type(retrieved_value),
                    retrieved_value,
                )
                diff_list.append('Attribute "%s" differs. Playbook parameter: (%s) %s. Retrieved NITRO object: (%s) %s' % str_tuple)
                log('Attribute "%s" differs. Playbook parameter: (%s) %s. Retrieved NITRO object: (%s) %s' % str_tuple)
                entry = 'Attribute "%s" differs. Playbook parameter: "%s". Retrieved NITRO object: "%s"' % (attribute, configured_value, retrieved_value)
                self.prepared_list.append(entry)
                # Also append changed values to the non updateable list
                if attribute in self.attribute_config['service']['non_updateable_attributes']:
                    non_updateable_list.append(attribute)

        self.module_result['diff_list'] = diff_list
        if non_updateable_list != []:
            msg = 'Cannot change value for the following non updateable attributes %s' % non_updateable_list
            self.module.fail_json(msg=msg, **self.module_result)

        if diff_list != []:
            return False
        else:
            return True
Пример #16
0
    def binding_exists(self):
        log('ModuleExecutor.binding_exists()')
        result = self.fetcher.get('sslcipher_sslciphersuite_binding', self.module.params['ciphergroupname'])

        log('get result %s' % result)
        if result['nitro_errorcode'] == 258:
            return False
        elif result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
        # Sort though the bound ciphers for cipheraliasname match
        for binding in result['data'].get('sslcipher_sslciphersuite_binding', []):
            if binding['ciphername'] == self.configured_binding['ciphername']:
                return True

        # Fallthrough
        return False
Пример #17
0
    def object_by_args_exists(self):
        log('ModuleExecutor.object_exists()')

        resource_missing_errorcode = self.module.params['workflow'].get(
            'resource_missing_errorcode')
        log('resource missing errorcode %s' % resource_missing_errorcode)

        if resource_missing_errorcode is None:
            msg = 'object_by_args lifecycle requires resource_missing_errorcode workflow parameter'
            self.module.fail_json(msg=msg, **self.module_result)

        # We need to id the object through args
        # We use the delete ids for get as well
        args = {}
        for key in self.module.params['workflow'].get('delete_id_attributes',
                                                      []):
            if key in self.module.params['resource']:
                args[key] = self.module.params['resource'][key]

        result = self.fetcher.get(self.endpoint, args=args)

        log('get result %s' % result)
        if result['nitro_errorcode'] == 0:

            if self.endpoint not in result['data']:
                return False
            elif len(result['data'][self.endpoint]) > 1:
                raise Exception(
                    "Multiple objects retrieved. Should only be one.")
            else:
                self.retrieved_object = result['data'][self.endpoint][0]
                return True
        elif result['nitro_errorcode'] == resource_missing_errorcode:
            return False
        else:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #18
0
    def dnsnsrec_exists(self):
        log('ModuleExecutor.dnsnsrec_exists()')
        result = self.fetcher.get('dnsnsrec')

        log('get result %s' % result)
        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
        # Sort though the bound ciphers for cipheraliasname match
        for dnsnsrec in result['data'].get('dnsnsrec', []):
            match = all(
                (dnsnsrec['domain'] == self.configured_dnsnsrec['domain'],
                 dnsnsrec['nameserver'] ==
                 self.configured_dnsnsrec['nameserver']))
            if match:
                return True

        # Fallthrough
        return False
    def nspartition_exists(self):
        log('ModuleExecutor.nspartition_exists()')

        result = self.fetcher.get('nspartition', id=self.module.params['partitionname'])

        log('get result %s' % result)

        # nspartition does not exist
        if result['nitro_errorcode'] == 2755:
            return False
        elif result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
        # Fallthrough

        # Save retrieved nspartition contents for nspartition_identical()
        self.retrieved_nspartition = result['data']['nspartition'][0]

        return True
Пример #20
0
    def binding_identical(self):
        log('ModuleExecutor.binding_identical()')
        result = self.fetcher.get('sslcipher_sslciphersuite_binding', self.module.params['ciphergroupname'])
        retrieved_bindings = result['data']['sslcipher_sslciphersuite_binding']

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )

        diff_list = []
        # Iterate over keys that already exist in the playbook
        for retrieved_object in retrieved_bindings:

            # Skip irrelevant ciphers
            if retrieved_object['ciphername'] != self.configured_binding['ciphername']:
                continue

            for attribute in self.configured_binding.keys():
                retrieved_value = retrieved_object.get(attribute)
                configured_value = self.configured_binding.get(attribute)
                if retrieved_value != configured_value:
                    str_tuple = (
                        attribute,
                        type(configured_value),
                        configured_value,
                        type(retrieved_value),
                        retrieved_value,
                    )
                    diff_list.append('Attribute "%s" differs. Playbook parameter: (%s) %s. Retrieved NITRO object: (%s) %s' % str_tuple)
                    log('Attribute "%s" differs. Playbook parameter: (%s) %s. Retrieved NITRO object: (%s) %s' % str_tuple)
            self.module_result['diff_list'] = diff_list

        if diff_list != []:
            return False
        else:
            return True
Пример #21
0
    def non_updateable_object_exists(self):
        log('ModuleExecutor.non_updateable_object_exists()')

        resource_missing_errorcode = self.module.params['workflow'].get(
            'resource_missing_errorcode')
        log('resource missing errorcode %s' % resource_missing_errorcode)

        if resource_missing_errorcode is None:
            msg = 'object lifecycle requires resource_missing_errorcode workflow parameter'
            self.module.fail_json(msg=msg, **self.module_result)

        args = {}
        for key in self.module.params['workflow'].get('delete_id_attributes',
                                                      []):
            if key in self.configured_object:
                args[key] = self.configured_object[key]

        log('self.id %s' % self.id)
        result = self.fetcher.get(self.endpoint, id=self.id, args=args)
        log('get result %s' % result)

        if result['nitro_errorcode'] == 0:
            returned_list = result['data'][self.endpoint]
            if len(returned_list) > 1:
                msg = 'Found more than one existing objects'
                self.module.fail_json(msg=msg, **self.module_result)

            # Fallthrough
            self.retrieved_object = result['data'][self.endpoint][0]
            return True
        elif result['nitro_errorcode'] == resource_missing_errorcode:
            return False
        else:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
    def delete_nsip(self):
        log('ModuleExecutor.delete_nsip()')

        args = {}

        td = self.configured_nsip.get('td')
        if td is not None:
            args['td'] = td


        result = self.fetcher.delete(
            resource='nsip',
            id=self.module.params['ipaddress'],
            args=args,
        )
        log('delete result %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
    def _download_file(self, remote_path, local_path):
        log('ModuleExecutor._download_file()')
        log('remote_path %s' % remote_path)
        log('local_path %s' % local_path)
        args = {}
        args['filename'] = os.path.basename(remote_path)
        args['filelocation'] = os.path.dirname(remote_path)
        result = self.fetcher.get('systemfile', args=args)

        log('get result %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )

        bytes_received = codecs.encode(
            result['data']['systemfile'][0]['filecontent'])
        retrieved_filecontent = codecs.decode(base64.b64decode(bytes_received))
        with open(local_path, 'w') as fh:
            fh.write(retrieved_filecontent)
    def nsip_exists(self):
        log('ModuleExecutor.nsip_exists()')
        args = {}
        args['ipaddress'] = self.module.params['ipaddress']
        result = self.fetcher.get('nsip', args=args)

        log('get result %s' % result)

        # NSIP does not exist
        if result['nitro_errorcode'] == 258:
            return False
        elif result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
        # Fallthrough

        # Save retrieved file contents for nsip_identical()
        self.retrieved_nsip = result['data']['nsip'][0]

        return True
Пример #25
0
    def object_update(self):
        log('ModuleExecutor.object_update()')

        non_updateables_changed = list(
            frozenset(self.non_updateable_attributes)
            & frozenset(self.differing_attributes))
        if len(non_updateables_changed) > 0:
            log('Non updateables changed %s' % non_updateables_changed)
            if self.module.params['workflow']['allow_recreate']:
                self.object_delete()
                self.object_create()
            else:
                msg = (
                    'Not allowed to recreate object. Non updateable attributes changed %s'
                    % non_updateables_changed)
                self.module.fail_json(msg=msg, **self.module_result)
        else:
            attributes = self.module.params['resource']
            for attribute in self.non_updateable_attributes:
                if attribute in attributes:
                    del attributes[attribute]

            put_data = {self.endpoint: attributes}

            log('request put data: %s' % put_data)

            result = self.fetcher.put(put_data=put_data,
                                      resource=self.endpoint)

            log('result of put: %s' % result)

            if result['nitro_errorcode'] != 0:
                raise NitroException(
                    errorcode=result['nitro_errorcode'],
                    message=result.get('nitro_message'),
                    severity=result.get('nitro_severity'),
                )
Пример #26
0
    def binding_exists(self):
        log('ModuleExecutor.binding_exists()')

        result = self.fetcher.get(self.endpoint, self.id)

        log('get result %s' % result)

        if result['nitro_errorcode'] == 0:
            if self.endpoint not in result['data']:
                return False

            objects_returned = result['data'][self.endpoint]
            matching_objects = []

            # Compare the present id attributes
            for object in objects_returned:
                if self.binding_matches_id_attributes(object):
                    matching_objects.append(object)

            if len(matching_objects) == 0:
                return False
            elif len(matching_objects) == 1:
                self.retrieved_object = matching_objects[0]
                return True
            elif len(matching_objects) > 1:
                msg = 'Found multiple matching objects for binding'
                self.module.fail_json(msg=msg, **self.module_result)
        elif result['nitro_errorcode'] == self.module.params['workflow'][
                'bound_resource_missing_errorcode']:
            return False
        else:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #27
0
    def systemfile_exists(self):
        log('ModuleExecutor.systemfile_exists()')
        args = {}
        args['filename'] = self.module.params['filename']
        args['filelocation'] = self.module.params['filelocation']
        result = self.fetcher.get('systemfile', args=args)

        log('get result %s' % result)

        # File does not exist
        if result['nitro_errorcode'] == 3441:
            return False
        elif result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
        # Fallthrough

        # Save retrieved file contents for systemfile_identical()
        self.retrieved_systemfile = result['data']['systemfile'][0]

        return True
    def update_nspartition(self):
        log('ModuleExecutor.update_nspartition()')

        # Catching trying to change non updateable attributes is done in self.nspartition_identical()
        put_payload = copy.deepcopy(self.configured_nspartition)
        for attribute in self.attribute_config['nspartition']['non_updateable_attributes']:
            if attribute in put_payload:
                del put_payload[attribute]

        put_data = {
            'nspartition': put_payload
        }

        log('request put data: %s' % put_data)
        result = self.fetcher.put(put_data=put_data, resource='nspartition')

        log('result of put: %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
    def do_update_operation(self):
        log('ModuleExecutor.do_update_operation()')

        processed_data = {}
        processed_data['certkey'] = self.configured_ssl_certkey['certkey']

        for attribute in self.update_keys:
            if attribute in self.configured_ssl_certkey:
                processed_data[attribute] = self.configured_ssl_certkey[
                    attribute]

        put_data = {'sslcertkey': processed_data}

        result = self.fetcher.put(put_data=put_data, resource='sslcertkey')

        log('put data %s' % put_data)
        log('result of put %s' % result)

        if result['nitro_errorcode'] != 0:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )
Пример #30
0
    def bindings_list_identical(self):
        log('ModuleExecutor.bindings_list_identical()')

        configured_bindings = self.configured_object['bindings_list']

        self.key_attributes = copy.deepcopy(
            self.module.params['workflow']['binding_workflow']
            ['delete_id_attributes'])
        self.key_attributes.insert(
            0, self.module.params['workflow']['binding_workflow']
            ['primary_id_attribute'])

        # Sanity check that at least one item is defined in bindings_list
        if len(configured_bindings) == 0:
            msg = 'Bindings list must have at least one item.'
            self.module.fail_json(msg=msg, **self.module_result)
        # Fallthrough

        # Sanity check that all bindings have uniform resource attribute keys
        key_tuples = []
        for binding in configured_bindings:
            attribute_keys_present = list(
                frozenset(binding.keys()) & frozenset(self.key_attributes))
            key_tuple = tuple(sorted(attribute_keys_present))
            key_tuples.append(key_tuple)

        key_tuple_set = frozenset(key_tuples)
        log('key_tuple_set %s' % key_tuple_set)
        if len(key_tuple_set) > 1:
            key_tuples = list(key_tuple_set)
            msg = 'Bindings list key attributes are not uniform. Attribute key sets found %s' % key_tuples
            self.module.fail_json(msg=msg, **self.module_result)

        # Fallthrough

        # Sanity check that all primary ids are one and the same
        primary_id_key = self.module.params['workflow']['binding_workflow'][
            'primary_id_attribute']
        primary_ids_list = [
            item[primary_id_key] for item in configured_bindings
        ]
        primary_ids_set = frozenset(primary_ids_list)
        log('primary_ids_set %s' % primary_ids_set)
        if len(primary_ids_set) > 1:
            keys = list(primary_ids_set)
            msg = 'Need to have only one primary id value. Found: %s' % keys
            self.module.fail_json(msg=msg, **self.module_result)

        # Fallthrough

        # Get existing bindings
        self.id = list(primary_ids_set)[0]
        self.endpoint = self.module.params['workflow']['binding_workflow'][
            'endpoint']

        result = self.fetcher.get(self.endpoint, self.id)

        log('get result %s' % result)

        existing_bindings = []
        if result['nitro_errorcode'] == 0:
            if self.endpoint not in result['data']:
                existing_bindings = []
            else:
                existing_bindings = result['data'][self.endpoint]

        elif result['nitro_errorcode'] == self.module.params['workflow'][
                'binding_workflow']['bound_resource_missing_errorcode']:
            existing_bindings = []
        else:
            raise NitroException(
                errorcode=result['nitro_errorcode'],
                message=result.get('nitro_message'),
                severity=result.get('nitro_severity'),
            )

        # Construct the dictionaries keyed by tuple of key attributes
        # First attribute must be the primary id attribute
        self.key_attributes_present = []
        for item in self.key_attributes:
            if item in list(key_tuple_set)[0]:
                self.key_attributes_present.append(item)

        self.configured_bindings_dict = {}
        for binding in configured_bindings:
            binding_key = self._get_binding_key_tuple(binding)

            if binding_key in self.configured_bindings_dict:
                msg = 'Found duplicate key for configured bindings %s' % (
                    binding_key, )
                self.module.fail_json(msg=msg, **self.module_result)

            log('Configured binding id %s registered to dict' %
                (binding_key, ))
            self.configured_bindings_dict[binding_key] = binding

        self.existing_bindings_dict = {}

        for binding in existing_bindings:
            binding_key = self._get_binding_key_tuple(binding)

            if binding_key in self.existing_bindings_dict:
                msg = 'Found duplicate key for existing bindings %s' % (
                    binding_key, )
                self.module.fail_json(msg=msg, **self.module_result)

            log('Existing binding id %s registered to dict' % (binding_key, ))
            self.existing_bindings_dict[binding_key] = binding

        # Calculate to delete keys
        self.to_delete_keys = []
        for existing_key in self.existing_bindings_dict:
            if existing_key not in self.configured_bindings_dict:
                log('Existing binding key marked for delete %s' %
                    (existing_key, ))
                self.to_delete_keys.append(existing_key)

        # Calculate to update keys
        self.to_update_keys = []
        for existing_key in self.existing_bindings_dict:
            if existing_key in self.configured_bindings_dict:
                configured = self.configured_bindings_dict[existing_key]
                existing = self.existing_bindings_dict[existing_key]
                if not self._binding_list_item_identical_to_configured(
                        configured, existing):
                    log('Existing binding key marked for update %s' %
                        (existing_key, ))
                    self.to_update_keys.append(existing_key)

        # Calculate to create keys
        self.to_create_keys = []
        for configured_key in self.configured_bindings_dict:
            if configured_key not in self.existing_bindings_dict:
                log('Configured binding key marked for create %s' %
                    (configured_key, ))
                self.to_create_keys.append(configured_key)

        # Calculate all changes
        all_change_keys = self.to_create_keys + self.to_update_keys + self.to_delete_keys
        if len(all_change_keys) == 0:
            return True
        else:
            return False