Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Physical server provisioning with internal state machine #18573

Merged
merged 1 commit into from
Apr 29, 2019

Conversation

miha-plesko
Copy link
Contributor

@miha-plesko miha-plesko commented Mar 19, 2019

We implement PhysicalServerProvisionRequest with one or more tasks - one per server to be provisioned. Each task is provider-specific (depending on PhysicalServer instance type). Tasks are implemented with internal state machine; each provider implements its own steps for provisioning like this:

:run_provision
:start_provisioning
     #
...  # provider-specific steps here
     #
:done_provisioning
:mark_as_completed
:finish

Please note that internal state machine gets triggered by external one to allow for more customization.

Related to
ManageIQ/manageiq-automation_engine#306
ManageIQ/manageiq-content#516

@miq-bot add_label enhancement
@miq-bot assign @agrare

app/models/physical_server.rb Outdated Show resolved Hide resolved
@@ -11,7 +11,7 @@ def src_configured_systems
end

def self.request_task_class_from(_attribs)
ManageIQ::Providers::Lenovo::PhysicalInfraManager::ProvisionTask
PhysicalServerProvisionTask
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this method need to be overridden in sub-classes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay so as discussed on a call a week ago we're now allowing Task override from within provider repo (see L19 below). Overriden Task should inherit from this PhysicalServerProvisionTask.

Here in Request, however, we cannot allow override because there is no way we can figure what provider does the Request belong to. But this is not a problem, because self.request_task_class is only used by Request to render Task description prefix, so IMO it's safe to leave it like this.

app/models/physical_server_provision_task.rb Outdated Show resolved Hide resolved
@miha-plesko miha-plesko changed the title [WIP] Physical server provisioning via StateMachine Physical server provisioning with internal state machine Apr 17, 2019
@miq-bot miq-bot removed the wip label Apr 17, 2019
@miha-plesko
Copy link
Contributor Author

Retrying add_label and assign:

@miq-bot add_label enhancement
@miq-bot assign @agrare

Copy link
Member

@agrare agrare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with this from a providers POV, I'll leave it up to @gmcculloug to ack the provision request changes

@@ -33,6 +33,7 @@ class PhysicalServer < ApplicationRecord

virtual_column :v_availability, :type => :string, :uses => :host
virtual_column :v_host_os, :type => :string, :uses => :host
virtual_delegate :ems_type, :to => "ext_management_system", :allow_nil => true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gmcculloug here's the virtual attribute definition that the external state machine depends on (for routing via messages).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stated above, I think this should be emstype.

end

def self.base_model
PhysicalServerProvisionTask
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the change @lfu @gmcculloug that introduces standalone task name instead shared one (was miq_provision_task, is physical_server_provision_task now). Not sure why I didn't do it in first place, sorry.

Copy link
Member

@gmcculloug gmcculloug left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to look into the emstype vs ems_type comments, otherwise this is looking good.

source = PhysicalServer.find_by(:id => source_id)
raise MiqException::MiqProvisionError, "Unable to find source PhysicalServer with id [#{source_id}]" if source.nil?
raise MiqException::MiqProvisionError, "Source PhysicalServer with id [#{source_id}] has no EMS, unable to provision" if source.ext_management_system.nil?
source
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, but when I see the pattern

var = set_var
raise ''
raise ''
return var

I want to use tap

PhysicalServer.find_by(:id => source_id).tap do |source|
  raise MiqException::MiqProvisionError, "Unable to find source PhysicalServer with id [#{source_id}]" if source.nil?
  raise MiqException::MiqProvisionError, "Source PhysicalServer with id [#{source_id}] has no EMS, unable to provision" if source.ext_management_system.nil?
end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @lfu demonstrated something similar on the content PR and I like it, not sure why I did it oldschool here again.

@@ -34,6 +34,7 @@ class << model_name
def self.ems_type
@ems_type ||= "physical_infra_manager".freeze
end
delegate :ems_type, :to => :class
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need this if your virtual_delegate uses emstype instead of ems_type.

With a fake provider added to the ext_manage_systems table you see:

irb(main):037:0> p
=> #<ManageIQ::Providers::Redfish::PhysicalInfraManager id: 50, name: "RedFish", created_on: "2019-04-26 22:08:06", updated_on: "2019-04-26 22:08:06", guid: "ffec646a-3145-4e63-8bbf-546c4525b344", zone_id: nil, type: "ManageIQ::Providers::Redfish::PhysicalInfraManager", api_version: nil, uid_ems: nil, host_default_vnc_port_start: nil, host_default_vnc_port_end: nil, provider_region: nil, last_refresh_error: nil, last_refresh_date: nil, provider_id: nil, realm: nil, tenant_id: 1, project: nil, parent_ems_id: nil, subscription: nil, last_metrics_error: nil, last_metrics_update_date: nil, last_metrics_success_date: nil, tenant_mapping_enabled: nil, enabled: true, options: nil, zone_before_pause_id: nil, last_inventory_date: nil>

irb(main):038:0> p.emstype
=> "redfish_ph_infra"

irb(main):039:0> p.class.ems_type
=> "redfish_ph_infra"

If this works you will also need to adjust the automate engine and content PRs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, works like a charm, updated, thanks 👍

@@ -33,6 +33,7 @@ class PhysicalServer < ApplicationRecord

virtual_column :v_availability, :type => :string, :uses => :host
virtual_column :v_host_os, :type => :string, :uses => :host
virtual_delegate :ems_type, :to => "ext_management_system", :allow_nil => true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stated above, I think this should be emstype.

We implement PhysicalServerProvisionRequest with one or more
tasks - one per server to be provisioned. Each task is provider-specific
(depending on PhysicalServer instance type). Tasks are implemented
with internal state machine; each provider implements its own steps
for provisioning like this:

```
:run_provision
:start_provisioning
     #
...  # provider-specific steps here
     #
:done_provisioning
:mark_as_completed
:finish
```

Please note that internal state machine gets triggered by external one
to allow for more customization.

With this commit we also add virtual attribute `ems_type` to
PhysicalServer model because external state machine needs it
for routing.

Signed-off-by: Miha Pleško <miha.plesko@xlab.si>
@miq-bot
Copy link
Member

miq-bot commented Apr 29, 2019

Checked commit xlab-si@f25de09 with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0
9 files checked, 3 offenses detected

spec/factories/miq_request.rb

spec/models/physical_server_provision_task/state_machine_spec.rb

Copy link
Member

@agrare agrare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you address that one thing in a follow-up @miha-plesko ?

end

def start_provisioning
update_and_notify_parent(:message => msg('start provisioning'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@miha-plesko why go through the trouble of updating the parent message if you're just going to raise immediately after? The way this is now you can't even do super in the child class to get the benefit of sharing the update_and_notify_parent calls across subclasses because it would just raise.

I'm going to merge as is because this case shouldn't ever happen

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agrare my thinking was to improve logs for unimplemented provider (e.g. Lenovo): first log says "start provisioning" then it explodes "NotImplemented" which kind of reads nicely as "start provisioning is not implemented".

However, I see your point - the piece of code is unusable as soon as one performs override from the provider. Followup here #18706, thanks for merging.

@agrare agrare merged commit f25de09 into ManageIQ:master Apr 29, 2019
agrare added a commit that referenced this pull request Apr 29, 2019
Physical server provisioning with internal state machine
@agrare agrare added this to the Sprint 110 Ending Apr 29, 2019 milestone Aug 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants