def get_update_model(self): update_model = super(SecurityListHelperCustom, self).get_update_model() existing_security_list = self.get_resource().data existing_ingress_security_rules = existing_security_list.ingress_security_rules existing_ingress_security_rules_dict = to_dict( existing_ingress_security_rules) existing_egress_security_rules = existing_security_list.egress_security_rules existing_egress_security_rules_dict = to_dict( existing_egress_security_rules) if self.module.params.get("purge_security_rules") is False: if existing_ingress_security_rules: update_model.ingress_security_rules = ( update_model.ingress_security_rules or []) update_model.ingress_security_rules = ( existing_ingress_security_rules + [ security_rule for security_rule in update_model. ingress_security_rules if not oci_common_utils. is_in_list(existing_ingress_security_rules_dict, to_dict(security_rule)) ]) if existing_egress_security_rules: update_model.egress_security_rules = ( update_model.egress_security_rules or []) update_model.egress_security_rules = existing_egress_security_rules + [ security_rule for security_rule in update_model.egress_security_rules if not oci_common_utils.is_in_list( existing_egress_security_rules_dict, to_dict(security_rule)) ] elif self.module.params.get("delete_security_rules") is True: if update_model.ingress_security_rules is None: update_model.ingress_security_rules = existing_ingress_security_rules else: existing_ingress_security_rules = existing_ingress_security_rules or [] update_model.ingress_security_rules = [ existing_security_rule for existing_security_rule in existing_ingress_security_rules if not any([ oci_common_utils.compare_dicts( to_dict(security_rule), to_dict(existing_security_rule)) for security_rule in update_model.ingress_security_rules ]) ] if update_model.egress_security_rules is None: update_model.egress_security_rules = existing_egress_security_rules else: existing_egress_security_rules = existing_egress_security_rules or [] update_model.egress_security_rules = [ existing_security_rule for existing_security_rule in existing_egress_security_rules if not any([ oci_common_utils.compare_dicts( to_dict(security_rule), to_dict(existing_security_rule)) for security_rule in update_model.egress_security_rules ]) ] return update_model
def get_update_model(self): update_model = super(RouteTableHelperCustom, self).get_update_model() existing_route_table = self.get_resource().data existing_route_rules = getattr(existing_route_table, "route_rules", []) or [] existing_route_rules_dict = to_dict(existing_route_rules) if self.module.params.get("purge_route_rules") is False: if existing_route_rules: update_model.route_rules = (getattr(update_model, "route_rules", []) or []) update_model.route_rules = existing_route_rules + [ route_rule for route_rule in update_model.route_rules if not oci_common_utils.is_in_list( existing_route_rules_dict, to_dict(route_rule)) ] elif self.module.params.get("delete_route_rules") is True: update_model.route_rules = getattr(update_model, "route_rules", []) or [] if not update_model.route_rules: update_model.route_rules = existing_route_rules else: existing_route_rules = existing_route_rules or [] update_model.route_rules = [ existing_route_rule for existing_route_rule in existing_route_rules if not any([ oci_common_utils.compare_dicts( to_dict(route_rule), to_dict(existing_route_rule)) for route_rule in update_model.route_rules ]) ] return update_model
def is_action_necessary(self, action, resource=None): # Handling idempotency for `scale` operation when both `capacity_type` & `capacity_value` are same as # existing capacity metadata. if ((action.lower() == self.ACTION_SCALE_ANALYTICS_INSTANCE) and self.module.params.get("capacity") and (resource.capacity.capacity_type == self.module.params.get("capacity").get("capacity_type") and resource.capacity.capacity_value == self.module.params.get("capacity").get("capacity_value"))): return False elif (action.lower() == self.ACTION_CHANGE_ANALYTICS_INSTANCE_NETWORK_ENDPOINT_DETAILS): action_details = oci_common_utils.convert_input_data_to_model_class( self.module.params, ChangeAnalyticsInstanceNetworkEndpointDetails) return not oci_common_utils.compare_dicts( to_dict(action_details.network_endpoint_details), to_dict(resource.network_endpoint_details), ) return super(AnalyticsInstanceActionsHelperCustom, self).is_action_necessary(action, resource)
def is_action_necessary(self, action, resource=None): if (action.upper() == self.CHANGE_INTEGRATION_INSTANCE_NETWORK_ENDPOINT_ACTION_KEY): # Let the API throw the validation error if not self.module.params.get("network_endpoint_details"): return True resource = resource or self.get_resource() return not oci_common_utils.compare_dicts( self.module.params.get("network_endpoint_details"), to_dict(getattr(resource, "network_endpoint_details", None)), ) return super(IntegrationInstanceActionsHelperCustom, self).is_action_necessary(action, resource)
def is_action_necessary(self, action, resource=None): resource = resource or self.get_resource().data if action == self.UPDATE_CLUSTER_ENDPOINT_CONFIG_KEY: action_details = oci_common_utils.convert_input_data_to_model_class( self.module.params, UpdateClusterEndpointConfigDetails ) return not oci_common_utils.compare_dicts( to_dict(action_details), to_dict(getattr(resource, "endpoint_config", None)), ) return super(ClusterActionsHelperCustom, self).is_action_necessary( action, resource )
def evaluate_response_for_load_balancer_detachment(response): if not response.data.load_balancers: return True user_load_balancer_detachment_details = to_dict( oci_common_utils.convert_input_data_to_model_class( self.module.params, DetachLoadBalancerDetails)) for existing_load_balancer_attachment in response.data.load_balancers: if (oci_common_utils.compare_dicts( user_load_balancer_detachment_details, to_dict(existing_load_balancer_attachment), ) and existing_load_balancer_attachment.lifecycle_state == self.LIFECYCLE_STATE_DETACHED): return True return False
def is_patch_necessary(self, existing_resource_dict): patch_model = self.get_patch_model() patch_model_dict = self.get_patch_model_dict_for_idempotence_check( patch_model) patch_is_necessary = not oci_common_utils.compare_dicts( patch_model_dict, existing_resource_dict) _debug("is patch necessary for {resource_type}: {patch_is_necessary}". format( resource_type=self.resource_type, patch_is_necessary=patch_is_necessary, )) return patch_is_necessary
def is_update_necessary(self, existing_resource_dict): update_model = self.get_update_model() update_model_dict = self.get_update_model_dict_for_idempotence_check( update_model) update_is_necessary = not oci_common_utils.compare_dicts( update_model_dict, existing_resource_dict["capabilities"]) _debug( "is update necessary for {resource_type}: {update_is_necessary}". format( resource_type=self.resource_type, update_is_necessary=update_is_necessary, )) return update_is_necessary
def is_detach_load_balancer_necessary(self, instance_pool): if not instance_pool.load_balancers: return False user_load_balancer_detachment_details = to_dict( oci_common_utils.convert_input_data_to_model_class( self.module.params, DetachLoadBalancerDetails)) for existing_load_balancer_attachment in instance_pool.load_balancers: if (existing_load_balancer_attachment.lifecycle_state in oci_common_utils.DEAD_STATES): continue if oci_common_utils.compare_dicts( user_load_balancer_detachment_details, to_dict(existing_load_balancer_attachment), ): return True return False
def is_update_necessary(self): current_resource_dict = to_dict(self.get_resource().data) update_model = self.get_update_model() update_model_dict = self.get_update_model_dict_for_idempotence_check( update_model) update_is_necessary = not oci_common_utils.compare_dicts( update_model_dict, current_resource_dict) _debug( "is update necessary for {resource_type}: {update_is_necessary}". format( resource_type=self.resource_type, update_is_necessary=update_is_necessary, )) return update_is_necessary
def get_resource(self): vanity_url_list = self.list_resources() for resource in vanity_url_list: resource_dict = to_dict(resource) vanity_url_key = self.module.params.get("vanity_url_key") if vanity_url_key and vanity_url_key == resource_dict.get("key"): return oci_common_utils.get_default_response_from_resource( resource) elif oci_common_utils.compare_dicts( source_dict=self.module.params, target_dict=resource_dict, ignore_attr_if_not_in_target=True, ): return oci_common_utils.get_default_response_from_resource( resource) return oci_common_utils.raise_does_not_exist_service_error()
def get_update_model(self): # right now this happens to be the same as exclude attributes # if the service eventually supports updating username / password # we should empty this list and leave exlude attributes, thus I am # keeping them as separate # this is a unique case for this API because it has fields on the Update model # that are not possible to update update_attributes_not_present_on_get_model_which_dont_support_update = [ "admin_password", "admin_username", ] existing_resource_dict = self.get_existing_resource_dict_for_update() params_to_pass_in_update_call = {} # MySQL UpdateDbSystem will throw an error if you specify any fields in the update request that the service # does not allow updating (which is most of the fields) # Thus, we only want to pass through values that are updated relative to the existing value on the resource # For example, if we pass subnet_id, even if it is set to the same value as resource.subnet_id the service will # throw an error, so we have custom logic to exclude it for key, input_value in six.iteritems(self.module.params): if (key in update_attributes_not_present_on_get_model_which_dont_support_update ): continue if input_value is not None and key in existing_resource_dict: existing_value = existing_resource_dict[key] values_are_equal = input_value == existing_value dicts_are_equivalent = (isinstance(input_value, dict) and isinstance(existing_value, dict) and oci_common_utils.compare_dicts( input_value, existing_value)) if values_are_equal or dicts_are_equivalent: _debug( "skipping updating field {field_name} because it already matches the value on the resource." .format(field_name=key)) continue params_to_pass_in_update_call[key] = input_value return oci_common_utils.convert_input_data_to_model_class( params_to_pass_in_update_call, self.get_update_model_class())
def get_resource(self): private_access_channels = self.list_resources() if private_access_channels: for channel in private_access_channels: resource_dict = to_dict(channel) private_access_channel_key = self.module.params.get( "private_access_channel_key") if (private_access_channel_key and private_access_channel_key == channel.key): return oci_common_utils.get_default_response_from_resource( resource=channel) elif oci_common_utils.compare_dicts( source_dict=self.module.params, target_dict=resource_dict, ignore_attr_if_not_in_target=True, ): return oci_common_utils.get_default_response_from_resource( resource=channel) return oci_common_utils.raise_does_not_exist_service_error()
def get_matching_resource(self): create_model = self.get_create_model() attributes_to_consider = ( [ parameter for parameter in self.NAME_PARAMETERS if self.module.params.get(parameter) ] if self._use_name_as_identifier() else self.get_attributes_to_consider_for_create_idempotency_check( create_model)) create_model_dict = self.get_create_model_dict_for_idempotence_check( create_model) # There are cases where method - `list_resources()` returns `Summary` model instead of `Get` model. In most of # the cases `Summary` model doesn't have all the parameters available in `Get` model. It is possible to get and # return `Get` model for all the resources obtained by calling `list_resources()` however doing that we would # have to deal with performance overhead of multiple REST calls. To avoid that first we would filter out # potential matches and then return 'Get' model for each match. prospective_matches = [] for resource in self.list_resources(): if not self._is_resource_active(resource): continue resource_dict = self.get_existing_resource_dict_for_idempotence_check( resource) # set `ignore_attr_if_not_in_target` to `True` to avoid false negatives. if oci_common_utils.compare_dicts( source_dict=create_model_dict, target_dict=resource_dict, attrs=attributes_to_consider, ignore_attr_if_not_in_target=True, ): prospective_matches.append(resource) for resource in prospective_matches: # some resources return a summary model instead of a full model in the list call. Returning the summary # model makes the return values inconsistent between the first and subsequent runs. So get and return # the get model (if exists). if self.is_summary_model(resource): resource = self.get_get_model_from_summary_model(resource) resource_dict = self.get_existing_resource_dict_for_idempotence_check( resource) _debug( "Comparing create model dict values {0} against an existing resource's " "values {1}".format( pretty_print_json(create_model_dict), pretty_print_json(resource_dict), )) if oci_common_utils.compare_dicts( source_dict=create_model_dict, target_dict=resource_dict, attrs=attributes_to_consider, ): _debug("Resource with same attributes found: {0}.".format( pretty_print_json(resource_dict))) return resource _debug( "No matching resource found. Attempting to create a new resource.") return None
def is_action_necessary(self, action, resource=None): existing_route_rules = to_dict(resource or self.get_resource().data) logger.debug("Existing rules: {0}".format(existing_route_rules)) if action == self.ADD_KEY: if not self.module.params.get("route_rules"): return False logger.debug("Original route rules to add: {0}".format( self.module.params.get("route_rules"))) action_details = oci_common_utils.convert_input_data_to_model_class( self.module.params, AddDrgRouteRulesDetails) route_rules = to_dict( getattr(action_details, "route_rules", []) or []) route_rules_to_add = [] for route_rule in route_rules: if not oci_common_utils.is_in_list(existing_route_rules, route_rule): route_rules_to_add.append(route_rule) logger.debug("Route rules to add: {0}".format(route_rules_to_add)) if route_rules_to_add: self.module.params["route_rules"] = route_rules_to_add return True return False elif action == self.UPDATE_KEY: if not self.module.params.get("route_rules"): return False logger.debug("Original route rules to update: {0}".format( self.module.params.get("route_rules"))) action_details = oci_common_utils.convert_input_data_to_model_class( self.module.params, UpdateDrgRouteRulesDetails) route_rules = to_dict( getattr(action_details, "route_rules", []) or []) route_rules_to_update = [] for route_rule in route_rules: existing_route_rule = None for existing_rule in existing_route_rules: if existing_rule.get("id") == route_rule.get("id"): existing_route_rule = existing_rule if not existing_route_rule: self.module.fail_json( msg="Could not find an existing rule with id: {0}". format(route_rule.get("id"))) if not oci_common_utils.compare_dicts(route_rule, existing_route_rule): route_rules_to_update.append(route_rule) logger.debug( "Route rules to update: {0}".format(route_rules_to_update)) if route_rules_to_update: self.module.params["route_rules"] = route_rules_to_update return True return False elif action == self.REMOVE_KEY: route_rule_ids = self.module.params.get("route_rule_ids") if not route_rule_ids: return False existing_route_rule_ids = [ existing_route_rule.get("id") for existing_route_rule in existing_route_rules ] logger.debug("Original route_rule_ids to remove: {0}".format( route_rule_ids)) route_rule_ids_to_remove = [] for route_rule_id in route_rule_ids: if route_rule_id in existing_route_rule_ids: route_rule_ids_to_remove.append(route_rule_id) logger.debug("route_rule_ids to remove: {0}".format( route_rule_ids_to_remove)) if route_rule_ids_to_remove: self.module.params["route_rule_ids"] = route_rule_ids_to_remove return True return False return super(DrgRouteRulesActionsHelperCustom, self).is_action_necessary(action, resource)
def is_action_necessary(self, action, resource=None): existing_statements = to_dict(resource or self.get_resource().data) logger.debug("Existing statements: {0}".format(existing_statements)) if action == self.ADD_DRG_ROUTE_DISTRIBUTION_STATEMENTS_KEY: if not self.module.params.get("statements"): return False logger.debug("Original statements to add: {0}".format( self.module.params.get("statements"))) action_details = oci_common_utils.convert_input_data_to_model_class( self.module.params, AddDrgRouteDistributionStatementsDetails) statements = to_dict( getattr(action_details, "statements", []) or []) statements_to_add = [] for statement in statements: if not oci_common_utils.is_in_list(existing_statements, statement): statements_to_add.append(statement) logger.debug("Statements to add: {0}".format(statements_to_add)) if statements_to_add: self.module.params["statements"] = statements_to_add return True return False elif action == self.UPDATE_DRG_ROUTE_DISTRIBUTION_STATEMENTS_KEY: if not self.module.params.get("statements"): return False logger.debug("Original statements to update: {0}".format( self.module.params.get("statements"))) action_details = oci_common_utils.convert_input_data_to_model_class( self.module.params, UpdateDrgRouteDistributionStatementsDetails) statements = to_dict( getattr(action_details, "statements", []) or []) statements_to_update = [] for statement in statements: existing_statement = None for existing_stmt in existing_statements: if existing_stmt.get("id") == statement.get("id"): existing_statement = existing_stmt if not existing_statement: self.module.fail_json( msg="Could not find an existing statement with id: {0}" .format(statement.get("id"))) if not oci_common_utils.compare_dicts(statement, existing_statement): statements_to_update.append(statement) logger.debug( "Statements to update: {0}".format(statements_to_update)) if statements_to_update: self.module.params["statements"] = statements_to_update return True return False elif action == self.REMOVE_DRG_ROUTE_DISTRIBUTION_STATEMENTS_KEY: statement_ids = self.module.params.get("statement_ids") if not statement_ids: return False existing_statement_ids = [ existing_statement.get("id") for existing_statement in existing_statements ] logger.debug( "Original statement_ids to remove: {0}".format(statement_ids)) statement_ids_to_remove = [] for statement_id in statement_ids: if statement_id in existing_statement_ids: statement_ids_to_remove.append(statement_id) logger.debug( "statement_ids to remove: {0}".format(statement_ids_to_remove)) if statement_ids_to_remove: self.module.params["statement_ids"] = statement_ids_to_remove return True return False return super(DrgRouteDistributionStatementsActionsHelperCustom, self).is_action_necessary(action, resource)