-
Notifications
You must be signed in to change notification settings - Fork 896
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
Conversation
@@ -11,7 +11,7 @@ def src_configured_systems | |||
end | |||
|
|||
def self.request_task_class_from(_attribs) | |||
ManageIQ::Providers::Lenovo::PhysicalInfraManager::ProvisionTask | |||
PhysicalServerProvisionTask |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
5f59c21
to
6099ec5
Compare
6099ec5
to
7207b35
Compare
There was a problem hiding this 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
7207b35
to
b39b21d
Compare
app/models/physical_server.rb
Outdated
@@ -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 |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this 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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 👍
app/models/physical_server.rb
Outdated
@@ -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 |
There was a problem hiding this comment.
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>
b39b21d
to
f25de09
Compare
Checked commit xlab-si@f25de09 with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0 spec/factories/miq_request.rb
spec/models/physical_server_provision_task/state_machine_spec.rb
|
There was a problem hiding this 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')) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
Physical server provisioning with internal state machine
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:
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