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
Fixes #27952 - Values lost on Host and profiles edit page #43
Conversation
28acd05
to
a0d6615
Compare
@apuntamb as checked the edit following are still not showing. Are they expected so far as it is or values should be there ?
|
|
@apuntamb |
premium_os_disk: opts[:premium_os_disk], | ||
) | ||
vm = AzureRMCompute.new(azure_vm: raw_vm ,sdk: sdk) | ||
vm.resource_group = opts[:resource_group] |
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 works well in case of Compute Profile. However, it fails for normal host creation since there it is expecting [:azure_vm][:resource_group]
. Playing around with this, I could understand that keeping the above hierarchy for rg would fail for host edit and keeping just [:resource_group] would fail for profile. Can we do something here where it can handle both the scenarios?
If still it errors out, how about removing the Resource Group
field from profiles page?
@ShimShtein thoughts?
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.
Thank you @apuntamb. Added few inline comments.
@ShimShtein,
I think it would be good to handle resource_group
inside custom class i.e AzureRMCompute.
But I would like to know your suggestions on the same.
premium_os_disk: opts[:premium_os_disk], | ||
) | ||
vm = AzureRMCompute.new(azure_vm: raw_vm ,sdk: sdk) | ||
vm.resource_group = opts[:resource_group] |
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.
resource_group
is required while vm creation so instead of assigning resource_group here, would it be possible to pass it as an argument while initializing?
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.
@kgaikwad do you mean while initializing the above custom/wrapper class, something like:
AzureRMCompute.new(azure_vm: raw_vm ,sdk: sdk, resource_group: opts[:resource_group])
?
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.
Yeah
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.
It still fails for create_vm. In _base partial, it still expects f.object.azure_vm.resource_group
for host creation (create_vm) while it expects f.object.resource_group
for compute profiles (new_vm).
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.
Why it is expecting f.object.azure_vm.resource_group
for host creation in _base partial not f.object.resource_group
?
By any chance, would it be possible to override resource_group's get method & handle it accordingly?
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.
To achieve this you have to tweak behaviour inside get method for resource_group
in your custom class i.e. either @azure_vm.resource_group or resource_group whichever having value.
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.
Yeah, I had to override resource_group's getter and handle the scenarios. Updating the changes.
sshkey.key_data | ||
end | ||
|
||
def premium_os_disk |
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.
Same like platform
, can't you set value for premium_os_disk using @azure_vm.storage_profile.os_disk.managed_disk?
Would it be possible to fetch storage_account_type
value from managed_disk
?
a0d6615
to
0fbab32
Compare
@apuntamb, |
Sure thing :) |
0fbab32
to
ab73dc4
Compare
@vijay8451 Can you please try now. I have updated the PR. This should work for both Host edit page and Compute Profiles edit page. However, Network Interfaces tab values might not still work. |
app/models/concerns/foreman_azure_rm/vm_extensions/managed_vm.rb
Outdated
Show resolved
Hide resolved
@@ -22,6 +33,39 @@ def vm_size | |||
@azure_vm.hardware_profile.vm_size | |||
end | |||
|
|||
def platform |
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 we either separate azure-specific fields like platform
to a concern, or at least put a comment that this property is a convenience for us, and not part of foreman's interface?
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.
Makes sense. I'll add comment here.
@@ -155,7 +180,9 @@ def vm_sizes(region) | |||
end | |||
|
|||
def vm_instance_defaults | |||
ActiveSupport::HashWithIndifferentAccess.new | |||
super.merge( |
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.
deep_merge
suits better - if there are some properties defined on interfaces in super
, we still want them. Regular merge
will replace the whole interfaces
member.
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.
done.
@apuntamb I'll start once code refactor part complete :) |
{ :include_blank => _('Please first select an image and an Azure region')}, | ||
<%= selectable_f f, :network, [],#options_for_select(compute_resource.subnets("eastus")), | ||
{ :include_blank => _('Please first select an image and an Azure region'), | ||
:selected => nil#f.object.network |
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 f.object.network is constructed after the vm is created. So, doesn't work for #new_vm
method. This f comes from the new_interface
method which returns nothing but the azure's (sdk's) NetworkInterface.new
. How should we display the value for this on edit page or Profile?
50ab426
to
f9095d2
Compare
As per the commit |
72e07b8
to
cbd94f8
Compare
@apuntamb test results Works: Not works: Create Image: Compute Profile:
|
cbd94f8
to
7921d91
Compare
@vijay8451 Thanks for the thorough testing! |
Able to see now .
Works fine when click on
Okay, If i understood correctly , so we have a plan to move from
I tired to latest dev setup and found :
Works for me now . |
@vijay8451 I have pushed a commit that fixes the associate vm and network interface problem for compute profile. |
@apuntamb sounds good to me . |
a90da40
to
f9e94c8
Compare
lib/foreman_azure_rm/engine.rb
Outdated
@@ -4,13 +4,14 @@ class Engine < ::Rails::Engine | |||
|
|||
#autoloading all files inside lib dir | |||
config.autoload_paths += Dir["#{config.root}/lib"] | |||
config.autoload_paths += Dir["#{config.root}/lib/foreman_azure_rm"] |
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.
You don't need this directive, If it is present class ::Foo
could be resolved to file lib/foreman_azure_rm/foo.rb
. I don't think this is what we want.
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.
removed.
attrs[:privip_alloc] = (attrs[:name] == 'false') ? false : true | ||
pip_alloc = case attrs[:pubip_alloc] | ||
private_ip = (attrs[:private_ip] == 'false') ? false : true | ||
pip_alloc = case attrs[:public_ip] |
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 we call it pub_ip
? pip
can be both public and private.
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.
done.
sdk.vnets.select { |vnet| vnet.location == stripped_region } | ||
end | ||
def virtual_networks | ||
sdk.vnets.select { |vnet| vnet.location == region } |
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.
Since the region is constant, I think it's worth memoizing the result:
sdk.vnets.select { |vnet| vnet.location == region } | |
@virtual_networks ||= sdk.vnets.select { |vnet| vnet.location == region } |
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.
done.
def new_vm(attr = {}) | ||
AzureRMCompute.new(sdk: sdk) | ||
def new_vm(args = {}) | ||
if args.empty? || args[:image_id].nil? |
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.
Instead of adding if..else
, could you please add return statement with if
condition. Something like:
return AzureRMCompute.new(sdk: sdk) if args.empty? || args[:image_id].nil?
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.
done.
ifaces << new_interface(iface_attrs) | ||
end | ||
end | ||
vm = AzureRMCompute.new(azure_vm: raw_vm ,sdk: sdk, resource_group: opts[:resource_group], nics: ifaces) |
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.
Here, no need of assignment. In Ruby, methods always return the evaluated result of the last line of the expression unless an explicit return comes before it.
vm = AzureRMCompute.new(azure_vm: raw_vm ,sdk: sdk, resource_group: opts[:resource_group], nics: ifaces) | |
AzureRMCompute.new(azure_vm: raw_vm ,sdk: sdk, resource_group: opts[:resource_group], nics: ifaces) |
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.
done.
@@ -35,7 +35,7 @@ def define_managed_storage_profile(vm_name, vhd_path, publisher, offer, sku, ver | |||
os_disk.managed_disk = managed_disk_params | |||
storage_profile.os_disk = os_disk | |||
|
|||
# Currently eliminating data disk creation since capability does not exist. | |||
# ToDo disk creation for volume capability |
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.
# ToDo disk creation for volume capability | |
# TODO - disk creation for volume capability |
Could you please create an upstream issue under Compute resources - Azure
category for better tracking instead of having it here?
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.
will create a tracker.
vm_params = initialize_vm(vm_hash) | ||
vm_params.network_profile = define_network_profile(vm_hash[:network_interface_card_ids]) | ||
|
||
actual_vm = sdk.create_or_update_vm(vm_hash[:resource_group], vm_hash[:name], vm_params) | ||
logger.debug "Virtual Machine #{vm_hash[:name]} Created Successfully." |
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.
Please move this logger statement inside azure_rm.rb after this line.
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.
done.
logger.debug "Virtual Machine #{vm_hash[:name]} Created Successfully." | ||
response | ||
actual_vm |
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.
Instead of lines(194..196), simply return -
sdk.create_or_update_vm(vm_hash[:resource_group], vm_hash[:name], vm_params)
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.
done.
return AzureRMCompute.new(sdk: sdk) if args.empty? || args[:image_id].nil? | ||
opts = vm_instance_defaults.merge(args.to_h).deep_symbolize_keys | ||
# convert rails nested_attributes into a plain hash | ||
[:interfaces].each do |collection| |
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.
Do we still need this generic code, or can we simplify it to:
nested_args = opts.delete(:interfaces_attributes)
opts[collection] = nested_attributes_for(:interfaces, nested_args) if nested_args
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.
done.
42e6d4a
to
460e88a
Compare
460e88a
to
68d56f0
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.
ACK from me.
@vijay8451, can you please give it a run? If you're OK with it, we can merge it
Below are not working : Compute Profile:
Below comes during profile edit: VM Power on/off/Edit/Delete action always end with below screen: |
@vijay8451 Following is my Compute Profiles Edit page. I can see Network Interfaces tab, Password and Image both are set after save. |
@vijay8451 Ohkk I see that network interfaces for profiles is not loading. |
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.
@apuntamb, added few inline comments not major.
nic_conf.private_ipallocation_method = priv_ip_alloc | ||
nic_conf.subnet = subnets(args[:azure_vm][:location]).select{ |subnet| subnet.id == attrs[:network] }.first | ||
nic_conf.subnet = subnets.select{ |subnet| subnet.id == attrs[:network] }.first | ||
nic_conf.public_ipaddress = pip.present? ? pip : nil |
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.
nic_conf.public_ipaddress = pip.present? ? pip : nil | |
nic_conf.public_ipaddress = pip |
pip
will be nil
if pub_ip_alloc
not present, right? so to add condition here doesn't make any sense.
when 'Static' | ||
NetworkModels::IPAllocationMethod::Static | ||
when 'Dynamic' | ||
NetworkModels::IPAllocationMethod::Dynamic | ||
when 'None' | ||
nil | ||
end | ||
priv_ip_alloc = if attrs[:priv_ip_alloc] | ||
priv_ip_alloc = if private_ip |
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 this priv_ip_alloc
assignment is not dependent on pub_ip_alloc
, could you please move this block above before pub_ip_alloc
assignment to make it better readable?
Currently it looks like -
private_ip value then pub_ip_alloc
assignment -> priv_ip_alloc
assignment -> again a condition based on pub_ip_alloc.
@@ -120,7 +119,7 @@ def create_nics(args = {}) | |||
nics | |||
end | |||
|
|||
def create_managed_virtual_machine(vm_hash) | |||
def initialize_vm(vm_hash) | |||
custom_data = vm_hash[:custom_data] |
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 can see that custom_data
used only once in this method, do we really need to declare this custom_data
?
why not to use vm_hash[:custom_data]
directly wherever required.
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 this should be a part of this PR. I would like to address functionality issues here, and refactor the code later on, while we are not under delivery pressure.
@@ -120,7 +119,7 @@ def create_nics(args = {}) | |||
nics | |||
end | |||
|
|||
def create_managed_virtual_machine(vm_hash) | |||
def initialize_vm(vm_hash) | |||
custom_data = vm_hash[:custom_data] | |||
msg = "Creating Virtual Machine #{vm_hash[:name]} in Resource Group #{vm_hash[:resource_group]}." | |||
logger.debug msg |
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.
At line-128,
if vm_hash[:availability_set_id]
sub_resource = MsRestAzure::SubResource.new
sub_resource.id = vm_hash[:availability_set_id]
vm.availability_set = sub_resource
end
looks much better, right?
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.
Again, it's cosmetics in the original code, let's leave it to after delivery.
@@ -183,30 +182,34 @@ def create_managed_virtual_machine(vm_hash) | |||
vm.hardware_profile = ComputeModels::HardwareProfile.new.tap do |hw_profile| | |||
hw_profile.vm_size = vm_hash[:vm_size] | |||
end | |||
vm.network_profile = define_network_profile(vm_hash[:network_interface_card_ids]) | |||
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.
Instead of hard-coding ssh_key path at two places, could you initialize a variable with given path.
Then use that variable at these places.
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 think there is only one place with hard-coded path right now.
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.
Line number 156 & 163.
if args[:azure_vm][:script_command].present? || args[:azure_vm][:script_uris].present? | ||
def create_vm_extension(region, args = {}) | ||
if args[:script_command].present? || args[:script_uris].present? | ||
args[:script_uris] = args[:script_uris].to_s unless args[:script_uris].present? |
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.
args[:script_uris] = args[:script_uris].to_s unless args[:script_uris].present? | |
args[:script_uris] ||= args[:script_uris].to_s |
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 will fail if the value is nil
(it would be nil.to_s
)
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.
In that case, current statement will also fail, right?
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.
@ShimShtein It will not fail as nil.to_s
will give us ""
.
public_ip_address || private_ip_address | ||
end | ||
|
||
def public_ip_address | ||
interfaces.each do |nic| | ||
nic.ip_configurations.each do |configuration| | ||
next unless configuration.primary |
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.
Why not to return nil
after this when configuration.public_ipaddress
is not present.
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 returning nil here if the public ip is not present: line 86
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 know that you have returned nil in case public_ipaddress is not present.
What I meant to say was that instead of having if.. else
loop why not to mention something like -
return nil if configuration.public_ipaddress.blank?
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.
done.
def vm_nics(vm) | ||
ifaces = [] | ||
vm.network_profile.network_interfaces.each do |nic| | ||
nic_rg = nic.id.split('/')[4] |
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.
nic_rg = nic.id.split('/')[4] | |
nic_rg = ((splits_nic_id = nic.id.split('/'))[4] | |
nic_name = splits_nic_id[-1] |
stripped_region = region.gsub(/\s+/, '').downcase | ||
vnets = virtual_networks(stripped_region) | ||
def subnets | ||
vnets = virtual_networks | ||
subnets = [] | ||
vnets.each do |vnet| | ||
subnets.concat(sdk.subnets(vnet.resource_group, vnet.name)) | ||
end | ||
subnets | ||
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.
Currently method available_subnets
internally calls to subnets
then why not to it alias_method of subnets
?
alias_method :available_subnets, :subnets
rescue RuntimeError => e | ||
Foreman::Logging.exception('Unhandled Azure RM error', e) | ||
destroy_vm vm.id if vm | ||
raise e | ||
end | ||
|
||
def destroy_vm(uuid) | ||
#vm.azure_vm because that's the azure object and vm is the wrapper | ||
vm = find_vm_by_uuid(uuid) | ||
vm_name = vm.name |
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.
Why not to use vm.name
directly as used only once? Similar case for nic_ids
.
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.
# causes compute profiles issue | ||
# NetworkModels::NetworkInterface.new | ||
def new_interface(attrs = {}) | ||
args = { :network => "", :public_ip => "", :private_ip => false }.merge(attrs.to_h) |
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.
args = { :network => "", :public_ip => "", :private_ip => false }.merge(attrs.to_h) | |
args = { :network => "", :public_ip => "", :private_ip => false, 'persisted?' => false }.merge(attrs.to_h) |
@apuntamb, this will make fields_for
generate new interface template in compute profiles.
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.
@ShimShtein This worked like a charm.
@@ -120,7 +119,7 @@ def create_nics(args = {}) | |||
nics | |||
end | |||
|
|||
def create_managed_virtual_machine(vm_hash) | |||
def initialize_vm(vm_hash) | |||
custom_data = vm_hash[:custom_data] |
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 this should be a part of this PR. I would like to address functionality issues here, and refactor the code later on, while we are not under delivery pressure.
@@ -120,7 +119,7 @@ def create_nics(args = {}) | |||
nics | |||
end | |||
|
|||
def create_managed_virtual_machine(vm_hash) | |||
def initialize_vm(vm_hash) | |||
custom_data = vm_hash[:custom_data] | |||
msg = "Creating Virtual Machine #{vm_hash[:name]} in Resource Group #{vm_hash[:resource_group]}." | |||
logger.debug msg |
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.
Again, it's cosmetics in the original code, let's leave it to after delivery.
@@ -183,30 +182,34 @@ def create_managed_virtual_machine(vm_hash) | |||
vm.hardware_profile = ComputeModels::HardwareProfile.new.tap do |hw_profile| | |||
hw_profile.vm_size = vm_hash[:vm_size] | |||
end | |||
vm.network_profile = define_network_profile(vm_hash[:network_interface_card_ids]) | |||
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.
I think there is only one place with hard-coded path right now.
if args[:azure_vm][:script_command].present? || args[:azure_vm][:script_uris].present? | ||
def create_vm_extension(region, args = {}) | ||
if args[:script_command].present? || args[:script_uris].present? | ||
args[:script_uris] = args[:script_uris].to_s unless args[:script_uris].present? |
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 will fail if the value is nil
(it would be nil.to_s
)
@ShimShtein, |
791a389
to
da2a585
Compare
@apuntamb @ShimShtein @kgaikwad
LGTM 👍 ... ACK from QE |
Merged. 🎉 Thanks a lot! |
As first iteration round, it fixes the existing properties to be displayed upon edit action for the form.
This PR is dependent on #42 for compute profile edit page.
Meanwhile @vijay8451 , if you can review this at your end and let me know if there are still issues. :)