diff options
Diffstat (limited to 'trove/instance/models.py')
-rw-r--r-- | trove/instance/models.py | 172 |
1 files changed, 114 insertions, 58 deletions
diff --git a/trove/instance/models.py b/trove/instance/models.py index 5cc53ec5..0621c2cc 100644 --- a/trove/instance/models.py +++ b/trove/instance/models.py @@ -1282,11 +1282,6 @@ class Instance(BuiltInstance): Raises exception if a configuration assign cannot currently be performed """ - # check if the instance already has a configuration assigned - if self.db_info.configuration_id: - raise exception.ConfigurationAlreadyAttached( - instance_id=self.id, - configuration_id=self.db_info.configuration_id) # check if the instance is not ACTIVE or has tasks status = None @@ -1299,23 +1294,118 @@ class Instance(BuiltInstance): raise exception.InvalidInstanceState(instance_id=self.id, status=status) - def unassign_configuration(self): - LOG.debug("Unassigning the configuration from the instance %s.", - self.id) + def attach_configuration(self, configuration_id): + LOG.debug("Attaching configuration to instance: %s", self.id) + if not self.db_info.configuration_id: + self._validate_can_perform_assign() + LOG.debug("Attaching configuration: %s", configuration_id) + config = Configuration.find(self.context, configuration_id, + self.db_info.datastore_version_id) + self.update_configuration(config) + else: + raise exception.ConfigurationAlreadyAttached( + instance_id=self.id, + configuration_id=self.db_info.configuration_id) + + def update_configuration(self, configuration): + self.save_configuration(configuration) + return self.apply_configuration(configuration) + + def save_configuration(self, configuration): + """Save configuration changes on the guest. + Update Trove records if successful. + This method does not update runtime values. It sets the instance task + to RESTART_REQUIRED. + """ + + LOG.debug("Saving configuration on instance: %s", self.id) + overrides = configuration.get_configuration_overrides() + + # Always put the instance into RESTART_REQUIRED state after + # configuration update. The sate may be released only once (and if) + # the configuration is successfully applied. + # This ensures that the instance will always be in a consistent state + # even if the apply never executes or fails. + LOG.debug("Persisting new configuration on the guest.") + self.guest.update_overrides(overrides) + LOG.debug("Configuration has been persisted on the guest.") + + # Configuration has now been persisted on the instance an can be safely + # detached. Update our records to reflect this change irrespective of + # results of any further operations. + self.update_db(task_status=InstanceTasks.RESTART_REQUIRED, + configuration_id=configuration.configuration_id) + + def apply_configuration(self, configuration): + """Apply runtime configuration changes and release the + RESTART_REQUIRED task. + Apply changes only if ALL values can be applied at once. + Return True if the configuration has changed. + """ + + LOG.debug("Applying configuration on instance: %s", self.id) + overrides = configuration.get_configuration_overrides() + + if not configuration.does_configuration_need_restart(): + LOG.debug("Applying runtime configuration changes.") + self.guest.apply_overrides(overrides) + LOG.debug("Configuration has been applied.") + self.update_db(task_status=InstanceTasks.NONE) + + return True + + LOG.debug( + "Configuration changes include non-dynamic settings and " + "will require restart to take effect.") + + return False + + def detach_configuration(self): + LOG.debug("Detaching configuration from instance: %s", self.id) if self.configuration and self.configuration.id: - LOG.debug("Unassigning the configuration id %s.", - self.configuration.id) + self._validate_can_perform_assign() + LOG.debug("Detaching configuration: %s", self.configuration.id) + self.remove_configuration() + else: + LOG.debug("No configuration found on instance.") + + def remove_configuration(self): + configuration_id = self.delete_configuration() + return self.reset_configuration(configuration_id) + + def delete_configuration(self): + """Remove configuration changes from the guest. + Update Trove records if successful. + This method does not update runtime values. It sets the instance task + to RESTART_REQUIRED. + Return ID of the removed configuration group. + """ + LOG.debug("Deleting configuration from instance: %s", self.id) + configuration_id = self.configuration.id + + LOG.debug("Removing configuration from the guest.") + self.guest.update_overrides({}, remove=True) + LOG.debug("Configuration has been removed from the guest.") + + self.update_db(task_status=InstanceTasks.RESTART_REQUIRED, + configuration_id=None) - self.guest.update_overrides({}, remove=True) + return configuration_id - # Dynamically reset the configuration values back to their default - # values from the configuration template. - # Reset the values only if the default is available for all of - # them and restart is not required by any. - # Mark the instance with a 'RESTART_REQUIRED' status otherwise. + def reset_configuration(self, configuration_id): + """Dynamically reset the configuration values back to their default + values from the configuration template and release the + RESTART_REQUIRED task. + Reset the values only if the default is available for all of + them and restart is not required by any. + Return True if the configuration has changed. + """ + + LOG.debug("Resetting configuration on instance: %s", self.id) + if configuration_id: flavor = self.get_flavor() default_config = self._render_config_dict(flavor) - current_config = Configuration(self.context, self.configuration.id) + current_config = Configuration(self.context, configuration_id) current_overrides = current_config.get_configuration_overrides() # Check the configuration template has defaults for all modified # values. @@ -1323,56 +1413,22 @@ class Instance(BuiltInstance): for key in current_overrides.keys()) if (not current_config.does_configuration_need_restart() and has_defaults_for_all): + LOG.debug("Applying runtime configuration changes.") self.guest.apply_overrides( {k: v for k, v in default_config.items() if k in current_overrides}) + LOG.debug("Configuration has been applied.") + self.update_db(task_status=InstanceTasks.NONE) + + return True else: LOG.debug( "Could not revert all configuration changes dynamically. " "A restart will be required.") - self.update_db(task_status=InstanceTasks.RESTART_REQUIRED) else: - LOG.debug("No configuration found on instance. Skipping.") - - def assign_configuration(self, configuration_id): - self._validate_can_perform_assign() - - try: - configuration = Configuration.load(self.context, configuration_id) - except exception.ModelNotFoundError: - raise exception.NotFound( - message='Configuration group id: %s could not be found.' - % configuration_id) - - config_ds_v = configuration.datastore_version_id - inst_ds_v = self.db_info.datastore_version_id - if (config_ds_v != inst_ds_v): - raise exception.ConfigurationDatastoreNotMatchInstance( - config_datastore_version=config_ds_v, - instance_datastore_version=inst_ds_v) - - config = Configuration(self.context, configuration.id) - LOG.debug("Config is %s.", config) - - self.update_overrides(config) - self.update_db(configuration_id=configuration.id) + LOG.debug("There are no values to reset.") - def update_overrides(self, config): - LOG.debug("Updating or removing overrides for instance %s.", self.id) - - overrides = config.get_configuration_overrides() - self.guest.update_overrides(overrides) - - # Apply the new configuration values dynamically to the running - # datastore service. - # Apply overrides only if ALL values can be applied at once or mark - # the instance with a 'RESTART_REQUIRED' status. - if not config.does_configuration_need_restart(): - self.guest.apply_overrides(overrides) - else: - LOG.debug("Configuration overrides has non-dynamic settings and " - "will require restart to take effect.") - self.update_db(task_status=InstanceTasks.RESTART_REQUIRED) + return False def _render_config_dict(self, flavor): config = template.SingleInstanceConfigTemplate( |