foreman_azure_rm 2.0.0.pre1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cdbc28091795bf21377b298699209cc2a0d06365858d117b9468a466fb0ffe2
4
- data.tar.gz: 938f88f1ac6e6f9d9101ce57d2bf187e5c1196fd4abf68c667ae38db5c3270e2
3
+ metadata.gz: 3a507325a26003d06dcc112040e5915d39306b9681ec21253e618da875846e56
4
+ data.tar.gz: 771298a3fc115f85b24d90198ba53a5a093e85661d4aa4da958c6a01ea437b3e
5
5
  SHA512:
6
- metadata.gz: c4def716d7fa2719d629c0bb9029a60e079e5578c16a33c9baa624462e3da7cdf634fa8f64070fef86bd4b615f9bccafedb427f073facad2a3e5f021bb74eedc
7
- data.tar.gz: e2dbb0b84df8d5d7a62fa87486b858c5ee11cd28dcdf072ada26cbd77036942837f92f699e7738f40378cc839d0fde9cfc113d53c846b5af84af17dec14f78f4
6
+ metadata.gz: f29267ea139f9e9fb18697dc828d33ea30c0d5fcd433b21be427ec93912d5113b4278fbfd6ffb9282d2ad05f5d3142047b11e4b912afdb3bb5e454019599c968
7
+ data.tar.gz: 5603751a843f247708743e8e639b27575080ac2c709c2efbd77c591805d14713c8c3a5995610c9162f6b6c7c2d23a6f7f015204dab0641e34079c0a49a9ae69c
@@ -3,6 +3,15 @@ module ForemanAzureRM
3
3
  module ComputeResourcesControllerExtensions
4
4
  include Api::Version2
5
5
  include Foreman::Controller::Parameters::ComputeResource
6
+ extend ::Apipie::DSL::Concern
7
+ update_api(:create, :update) do
8
+ param :compute_resource, Hash do
9
+ # Not adding :tenant as already specified in core.
10
+ param :app_ident, String, :desc => N_("Client ID for AzureRM")
11
+ param :secret_key, String, :desc => N_("Client Secret for AzureRM")
12
+ param :sub_id, String, :desc => N_("Subscription ID for AzureRM")
13
+ end
14
+ end
6
15
 
7
16
  def available_resource_groups
8
17
  compute_resource = ComputeResource.find_by_id(params[:id])
@@ -1,11 +1,12 @@
1
1
  module ForemanAzureRM
2
2
  module Concerns
3
3
  module HostsControllerExtensions
4
+ extend ActiveSupport::Concern
4
5
 
5
6
  def sizes
6
- if (azure_rm_resource = Image.unscoped.find_by_uuid(params[:image_id])).present?
7
- resource = azure_rm_resource.compute_resource
8
- render :json => resource.vm_sizes(params[:region_string]).map { |size| size.name }
7
+ azure_rm_resource = ComputeResource.unscoped.find_by_id(params[:compute_resource_id])
8
+ if azure_rm_resource.present?
9
+ render :json => azure_rm_resource.vm_sizes.map { |size| size.name }
9
10
  else
10
11
  no_sizes = _('The region you selected has no sizes associated with it')
11
12
  render :json => "[\"#{no_sizes}\"]"
@@ -13,10 +14,9 @@ module ForemanAzureRM
13
14
  end
14
15
 
15
16
  def subnets
16
- azure_rm_image = Image.unscoped.find_by_uuid(params[:image_id])
17
- if azure_rm_image.present?
18
- azure_rm_resource = azure_rm_image.compute_resource
19
- subnets = azure_rm_resource.subnets(params[:region])
17
+ azure_rm_resource = ComputeResource.unscoped.find_by_id(params[:compute_resource_id])
18
+ if azure_rm_resource.present?
19
+ subnets = azure_rm_resource.subnets
20
20
  if subnets.present?
21
21
  render :json => subnets
22
22
  else
@@ -35,7 +35,7 @@ module ForemanAzureRM
35
35
  os_disk.managed_disk = managed_disk_params
36
36
  storage_profile.os_disk = os_disk
37
37
 
38
- # Currently eliminating data disk creation since capability does not exist.
38
+ # TODO - disk creation for volume capability
39
39
 
40
40
  if vhd_path.nil?
41
41
  # We are using a marketplace image
@@ -72,45 +72,44 @@ module ForemanAzureRM
72
72
  network_profile
73
73
  end
74
74
 
75
- def create_nics(args = {})
75
+ def create_nics(region, args = {})
76
76
  nics = []
77
- formatted_region = args[:azure_vm][:location].gsub(/\s+/, '').downcase
78
77
  args[:interfaces_attributes].each do |nic, attrs|
79
- attrs[:pubip_alloc] = attrs[:bridge]
80
- attrs[:privip_alloc] = (attrs[:name] == 'false') ? false : true
81
- pip_alloc = case attrs[:pubip_alloc]
82
- when 'Static'
83
- NetworkModels::IPAllocationMethod::Static
84
- when 'Dynamic'
85
- NetworkModels::IPAllocationMethod::Dynamic
86
- when 'None'
87
- nil
88
- end
89
- priv_ip_alloc = if attrs[:priv_ip_alloc]
90
- NetworkModels::IPAllocationMethod::Static
91
- else
92
- NetworkModels::IPAllocationMethod::Dynamic
93
- end
94
- if pip_alloc.present?
78
+ private_ip = (attrs[:private_ip] == 'false') ? false : true
79
+ priv_ip_alloc = if private_ip
80
+ NetworkModels::IPAllocationMethod::Static
81
+ else
82
+ NetworkModels::IPAllocationMethod::Dynamic
83
+ end
84
+ pub_ip_alloc = case attrs[:public_ip]
85
+ when 'Static'
86
+ NetworkModels::IPAllocationMethod::Static
87
+ when 'Dynamic'
88
+ NetworkModels::IPAllocationMethod::Dynamic
89
+ when 'None'
90
+ nil
91
+ end
92
+ if pub_ip_alloc.present?
95
93
  public_ip_params = NetworkModels::PublicIPAddress.new.tap do |ip|
96
- ip.location = formatted_region
97
- ip.public_ipallocation_method = pip_alloc
94
+ ip.location = region
95
+ ip.public_ipallocation_method = pub_ip_alloc
98
96
  end
99
- pip = sdk.create_or_update_pip(args[:azure_vm][:resource_group],
100
- "#{args[:azure_vm][:vm_name]}-pip#{nic}",
97
+
98
+ pip = sdk.create_or_update_pip(args[:resource_group],
99
+ "#{args[:vm_name]}-pip#{nic}",
101
100
  public_ip_params)
102
101
  end
103
102
  new_nic = sdk.create_or_update_nic(
104
- args[:azure_vm][:resource_group],
105
- "#{args[:azure_vm][:vm_name]}-nic#{nic}",
103
+ args[:resource_group],
104
+ "#{args[:vm_name]}-nic#{nic}",
106
105
  NetworkModels::NetworkInterface.new.tap do |interface|
107
- interface.location = formatted_region
106
+ interface.location = region
108
107
  interface.ip_configurations = [
109
108
  NetworkModels::NetworkInterfaceIPConfiguration.new.tap do |nic_conf|
110
- nic_conf.name = "#{args[:azure_vm][:vm_name]}-nic#{nic}"
109
+ nic_conf.name = "#{args[:vm_name]}-nic#{nic}"
111
110
  nic_conf.private_ipallocation_method = priv_ip_alloc
112
- nic_conf.subnet = subnets(args[:azure_vm][:location]).select{ |subnet| subnet.id == attrs[:network] }.first
113
- nic_conf.public_ipaddress = pip.present? ? pip : nil
111
+ nic_conf.subnet = subnets.select{ |subnet| subnet.id == attrs[:network] }.first
112
+ nic_conf.public_ipaddress = pip
114
113
  end
115
114
  ]
116
115
  end
@@ -120,7 +119,7 @@ module ForemanAzureRM
120
119
  nics
121
120
  end
122
121
 
123
- def create_managed_virtual_machine(vm_hash)
122
+ def initialize_vm(vm_hash)
124
123
  custom_data = vm_hash[:custom_data]
125
124
  msg = "Creating Virtual Machine #{vm_hash[:name]} in Resource Group #{vm_hash[:resource_group]}."
126
125
  logger.debug msg
@@ -183,30 +182,34 @@ module ForemanAzureRM
183
182
  vm.hardware_profile = ComputeModels::HardwareProfile.new.tap do |hw_profile|
184
183
  hw_profile.vm_size = vm_hash[:vm_size]
185
184
  end
186
- vm.network_profile = define_network_profile(vm_hash[:network_interface_card_ids])
187
185
  end
188
186
 
189
- response = sdk.create_or_update_vm(vm_hash[:resource_group], vm_hash[:name], vm_create_params)
190
- logger.debug "Virtual Machine #{vm_hash[:name]} Created Successfully."
191
- response
187
+ vm_create_params
188
+ end
189
+
190
+ def create_managed_virtual_machine(vm_hash)
191
+ vm_params = initialize_vm(vm_hash)
192
+ vm_params.network_profile = define_network_profile(vm_hash[:network_interface_card_ids])
193
+ sdk.create_or_update_vm(vm_hash[:resource_group], vm_hash[:name], vm_params)
192
194
  end
193
195
 
194
- def create_vm_extension(args = {})
195
- if args[:azure_vm][:script_command].present? || args[:azure_vm][:script_uris].present?
196
+ def create_vm_extension(region, args = {})
197
+ if args[:script_command].present? || args[:script_uris].present?
198
+ args[:script_uris] ||= args[:script_uris].to_s
196
199
  extension = ComputeModels::VirtualMachineExtension.new
197
- if args[:azure_vm][:platform] == 'Linux'
200
+ if args[:platform] == 'Linux'
198
201
  extension.publisher = 'Microsoft.Azure.Extensions'
199
202
  extension.virtual_machine_extension_type = 'CustomScript'
200
203
  extension.type_handler_version = '2.0'
201
204
  end
202
205
  extension.auto_upgrade_minor_version = true
203
- extension.location = args[:azure_vm][:location].gsub(/\s+/, '').downcase
206
+ extension.location = region
204
207
  extension.settings = {
205
- 'commandToExecute' => args[:azure_vm][:script_command],
206
- 'fileUris' => args[:azure_vm][:script_uris].split(',')
208
+ 'commandToExecute' => args[:script_command],
209
+ 'fileUris' => args[:script_uris].split(',')
207
210
  }
208
- sdk.create_or_update_vm_extensions(args[:azure_vm][:resource_group],
209
- args[:azure_vm][:vm_name],
211
+ sdk.create_or_update_vm_extensions(args[:resource_group],
212
+ args[:vm_name],
210
213
  'ForemanCustomScript',
211
214
  extension)
212
215
  end
@@ -1,6 +1,6 @@
1
1
  # This Model contains code modified as per azure-sdk
2
2
  # and removed dependencies from fog-azure-rm.
3
- #
3
+
4
4
  require 'base64'
5
5
 
6
6
  module ForemanAzureRM
@@ -9,13 +9,10 @@ module ForemanAzureRM
9
9
  include VMExtensions::ManagedVM
10
10
  alias_attribute :sub_id, :user
11
11
  alias_attribute :secret_key, :password
12
- alias_attribute :app_ident, :url
12
+ alias_attribute :region, :url
13
13
  alias_attribute :tenant, :uuid
14
14
 
15
- validates :user, :presence => true
16
- validates :password, :presence => true
17
- validates :url, :presence => true
18
- validates :uuid, :presence => true
15
+ validates :user, :password, :url, :uuid, :app_ident, :presence => true
19
16
 
20
17
  has_one :key_pair, :foreign_key => :compute_resource_id, :dependent => :destroy
21
18
 
@@ -23,6 +20,7 @@ module ForemanAzureRM
23
20
 
24
21
  class VMContainer
25
22
  attr_accessor :virtualmachines
23
+ delegate :each, to: :virtualmachines
26
24
 
27
25
  def initialize
28
26
  @virtualmachines = []
@@ -33,6 +31,14 @@ module ForemanAzureRM
33
31
  end
34
32
  end
35
33
 
34
+ def app_ident
35
+ attrs[:app_ident]
36
+ end
37
+
38
+ def app_ident=(name)
39
+ attrs[:app_ident] = name
40
+ end
41
+
36
42
  def sdk
37
43
  @sdk ||= ForemanAzureRM::AzureSDKAdapter.new(tenant, app_ident, secret_key, sub_id)
38
44
  end
@@ -45,7 +51,7 @@ module ForemanAzureRM
45
51
  ComputeResource.model_name
46
52
  end
47
53
 
48
- def provider_friendly_name
54
+ def self.provider_friendly_name
49
55
  'Azure Resource Manager'
50
56
  end
51
57
 
@@ -55,33 +61,18 @@ module ForemanAzureRM
55
61
 
56
62
  def regions
57
63
  [
58
- 'West Europe',
59
- 'Central US',
60
- 'South Central US',
61
- 'North Central US',
62
- 'West Central US',
63
- 'East US',
64
- 'East US 2',
65
- 'West US',
66
- 'West US 2'
64
+ ['West Europe', 'westeurope'],
65
+ ['Central US', 'centralus'],
66
+ ['South Central US', 'southcentralus'],
67
+ ['North Central US', 'northcentralus'],
68
+ ['West Central US', 'westcentralus'],
69
+ ['East US', 'eastus'],
70
+ ['East US 2', 'eastus2'],
71
+ ['West US', 'westus'],
72
+ ['West US 2', 'westus2']
67
73
  ]
68
74
  end
69
75
 
70
- def storage_accts(region = nil)
71
- stripped_region = region.gsub(/\s+/, '').downcase
72
- acct_names = []
73
- if region.nil?
74
- sdk.get_storage_accts.each do |acct|
75
- acct_names << acct.name
76
- end
77
- else
78
- (sdk.get_storage_accts.select { |acct| acct.region == stripped_region }).each do |acct|
79
- acct_names << acct.name
80
- end
81
- end
82
- acct_names
83
- end
84
-
85
76
  def resource_groups
86
77
  sdk.rgs
87
78
  end
@@ -93,25 +84,39 @@ module ForemanAzureRM
93
84
  super(options)
94
85
  end
95
86
 
96
- def new_vm(attr = {})
97
- AzureRMCompute.new(sdk: sdk)
98
- end
99
-
100
- def stop
101
- power_off
102
- deallocate
87
+ def new_vm(args = {})
88
+ return AzureRMCompute.new(sdk: sdk) if args.empty? || args[:image_id].nil?
89
+ opts = vm_instance_defaults.merge(args.to_h).deep_symbolize_keys
90
+ # convert rails nested_attributes into a plain hash
91
+ nested_args = opts.delete(:interfaces_attributes)
92
+ opts[:interfaces] = nested_attributes_for(:interfaces, nested_args) if nested_args
93
+
94
+ opts.reject! { |k, v| v.nil? }
95
+
96
+ raw_vm = initialize_vm(location: region,
97
+ resource_group: opts[:resource_group],
98
+ vm_size: opts[:vm_size],
99
+ username: opts[:username],
100
+ password: opts[:password],
101
+ platform: opts[:platform],
102
+ ssh_key_data: opts[:ssh_key_data],
103
+ os_disk_caching: opts[:os_disk_caching],
104
+ vhd_path: opts[:image_id],
105
+ premium_os_disk: opts[:premium_os_disk]
106
+ )
107
+ if opts[:interfaces].present?
108
+ ifaces = []
109
+ opts[:interfaces].each_with_index do |iface_attrs, i|
110
+ ifaces << new_interface(iface_attrs)
111
+ end
112
+ end
113
+ AzureRMCompute.new(azure_vm: raw_vm ,sdk: sdk, resource_group: opts[:resource_group], nics: ifaces)
103
114
  end
104
115
 
105
116
  def provided_attributes
106
117
  super.merge({ :ip => :provisioning_ip_address })
107
118
  end
108
119
 
109
- def host_interfaces_attrs(host)
110
- host.interfaces.select(&:physical?).each.with_index.reduce({}) do |hash, (nic, index)|
111
- hash.merge(index.to_s => nic.compute_attributes.merge(ip: nic.ip, ip6: nic.ip6))
112
- end
113
- end
114
-
115
120
  def available_vnets(attr = {})
116
121
  virtual_networks
117
122
  end
@@ -120,22 +125,12 @@ module ForemanAzureRM
120
125
  subnets
121
126
  end
122
127
 
123
- def available_subnets
124
- subnets
125
- end
126
-
127
- def virtual_networks(region = nil)
128
- if region.nil?
129
- sdk.vnets
130
- else
131
- stripped_region = region.gsub(/\s+/, '').downcase
132
- sdk.vnets.select { |vnet| vnet.location == stripped_region }
133
- end
128
+ def virtual_networks
129
+ @virtual_networks ||= sdk.vnets.select { |vnet| vnet.location == region }
134
130
  end
135
131
 
136
- def subnets(region = nil)
137
- stripped_region = region.gsub(/\s+/, '').downcase
138
- vnets = virtual_networks(stripped_region)
132
+ def subnets
133
+ vnets = virtual_networks
139
134
  subnets = []
140
135
  vnets.each do |vnet|
141
136
  subnets.concat(sdk.subnets(vnet.resource_group, vnet.name))
@@ -143,28 +138,46 @@ module ForemanAzureRM
143
138
  subnets
144
139
  end
145
140
 
146
- def new_interface(attr = {})
147
- # WIP
148
- # calls nic_cards method in adapter
149
- # causes compute profiles issue
150
- # NetworkModels::NetworkInterface.new
141
+ alias_method :available_subnets, :subnets
142
+
143
+ def new_interface(attrs = {})
144
+ args = { :network => "", :public_ip => "", :private_ip => false, 'persisted?' => false }.merge(attrs.to_h)
145
+ OpenStruct.new(args)
146
+ end
147
+
148
+ def editable_network_interfaces?
149
+ true
151
150
  end
152
151
 
153
- def vm_sizes(region)
152
+ def vm_sizes
154
153
  sdk.list_vm_sizes(region)
155
154
  end
156
155
 
156
+ def associated_host(vm)
157
+ associate_by("ip", [vm.public_ip_address, vm.private_ip_address])
158
+ end
159
+
157
160
  def vm_instance_defaults
158
- ActiveSupport::HashWithIndifferentAccess.new
161
+ super.deep_merge(
162
+ interfaces: [new_interface]
163
+ )
164
+ end
165
+
166
+ def vm_nics(vm)
167
+ ifaces = []
168
+ vm.network_profile.network_interfaces.each do |nic|
169
+ nic_rg = (split_nic_id = nic.id.split('/'))[4]
170
+ nic_name = split_nic_id[-1]
171
+ ifaces << sdk.vm_nic(nic_rg, nic_name)
172
+ end
173
+ ifaces
159
174
  end
160
175
 
161
- def vms
176
+ def vms(attrs = {})
162
177
  container = VMContainer.new
163
- # Load all vms
164
- resource_groups.each do |rg|
165
- sdk.list_vms(rg).each do |vm|
166
- container.virtualmachines << AzureRMCompute.new(azure_vm: vm, sdk:sdk)
167
- end
178
+ # Load all vms of the region
179
+ sdk.list_vms(region).each do |vm|
180
+ container.virtualmachines << AzureRMCompute.new(azure_vm: vm, sdk:sdk, nics: vm_nics(vm))
168
181
  end
169
182
  container
170
183
  end
@@ -188,44 +201,46 @@ module ForemanAzureRM
188
201
  end
189
202
 
190
203
  def create_vm(args = {})
191
- args[:azure_vm][:vm_name] = args[:name].split('.')[0]
192
- nics = create_nics(args)
193
- if args[:azure_vm][:password].present? && !args[:azure_vm][:ssh_key_data].present?
194
- sudoers_cmd = "$echo #{args[:azure_vm][:password]} | sudo -S echo '\"#{args[:azure_vm][:username]}\" ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/waagent"
195
- if args[:azure_vm][:script_command].present?
196
- # to run the script_cmd given through form
197
- # as username
198
- args[:azure_vm][:script_command] = sudoers_cmd + " ; su - \"#{args[:azure_vm][:username]}\" -c \"#{args[:azure_vm][:script_command]}\""
204
+ args = args.to_h.deep_symbolize_keys
205
+ args[:vm_name] = args[:name].split('.')[0]
206
+ nics = create_nics(region, args)
207
+ if args[:password].present? && !args[:ssh_key_data].present?
208
+ sudoers_cmd = "$echo #{args[:password]} | sudo -S echo '\"#{args[:username]}\" ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/waagent"
209
+ if args[:script_command].present?
210
+ # to run the script_cmd given through form as username
211
+ args[:script_command] = sudoers_cmd + " ; su - \"#{args[:username]}\" -c \"#{args[:script_command]}\""
199
212
  else
200
- args[:azure_vm][:script_command] = sudoers_cmd
213
+ args[:script_command] = sudoers_cmd
201
214
  end
202
215
  disable_password_auth = false
203
- elsif args[:azure_vm][:ssh_key_data].present? && !args[:azure_vm][:password].present?
216
+ elsif args[:ssh_key_data].present? && !args[:password].present?
204
217
  disable_password_auth = true
205
218
  else
206
219
  disable_password_auth = false
207
220
  end
221
+
208
222
  vm = create_managed_virtual_machine(
209
- name: args[:azure_vm][:vm_name],
210
- location: args[:azure_vm][:location],
211
- resource_group: args[:azure_vm][:resource_group],
212
- vm_size: args[:azure_vm][:vm_size],
213
- username: args[:azure_vm][:username],
214
- password: args[:azure_vm][:password],
215
- ssh_key_data: args[:azure_vm][:ssh_key_data],
223
+ name: args[:vm_name],
224
+ location: region,
225
+ resource_group: args[:resource_group],
226
+ vm_size: args[:vm_size],
227
+ username: args[:username],
228
+ password: args[:password],
229
+ ssh_key_data: args[:ssh_key_data],
216
230
  disable_password_authentication: disable_password_auth,
217
231
  network_interface_card_ids: nics.map(&:id),
218
- platform: args[:azure_vm][:platform],
232
+ platform: args[:platform],
219
233
  vhd_path: args[:image_id],
220
- os_disk_caching: args[:azure_vm][:os_disk_caching],
221
- premium_os_disk: args[:azure_vm][:premium_os_disk],
234
+ os_disk_caching: args[:os_disk_caching],
235
+ premium_os_disk: args[:premium_os_disk],
222
236
  custom_data: args[:user_data],
223
- script_command: args[:azure_vm][:script_command],
224
- script_uris: args[:azure_vm][:script_uris],
237
+ script_command: args[:script_command],
238
+ script_uris: args[:script_uris],
225
239
  )
226
- create_vm_extension(args)
240
+ logger.debug "Virtual Machine #{args[:vm_name]} Created Successfully."
241
+ create_vm_extension(region, args)
227
242
  # return the vm object using azure_vm
228
- return_vm = AzureRMCompute.new(azure_vm: vm, sdk: sdk)
243
+ AzureRMCompute.new(azure_vm: vm, sdk: sdk, resource_group: args[:resource_group], nics: vm_nics(vm))
229
244
  rescue RuntimeError => e
230
245
  Foreman::Logging.exception('Unhandled Azure RM error', e)
231
246
  destroy_vm vm.id if vm
@@ -233,15 +248,13 @@ module ForemanAzureRM
233
248
  end
234
249
 
235
250
  def destroy_vm(uuid)
236
- #vm.azure_vm because that's the azure object and vm is the wrapper
237
251
  vm = find_vm_by_uuid(uuid)
238
- vm_name = vm.name
239
- rg_name = vm.azure_vm.resource_group
252
+ rg_name = vm.resource_group
240
253
  os_disk = vm.azure_vm.storage_profile.os_disk
241
254
  data_disks = vm.azure_vm.storage_profile.data_disks
242
255
  nic_ids = vm.network_interface_card_ids
243
256
 
244
- sdk.delete_vm(rg_name, vm_name)
257
+ sdk.delete_vm(rg_name, vm.name)
245
258
 
246
259
  nic_ids.each do |nic_id|
247
260
  nic = sdk.vm_nic(rg_name, nic_id.split('/')[-1])
@@ -2,12 +2,29 @@ module ForemanAzureRM
2
2
  class AzureRMCompute
3
3
  attr_accessor :sdk
4
4
  attr_accessor :azure_vm
5
+ attr_accessor :resource_group
6
+ attr_accessor :nics
7
+ attr_accessor :image_id
5
8
 
6
9
  delegate :name, to: :azure_vm, allow_nil: true
7
10
 
8
- def initialize(azure_vm: ComputeModels::VirtualMachine.new, sdk: sdk)
11
+ def initialize(azure_vm: ComputeModels::VirtualMachine.new,
12
+ sdk: sdk,
13
+ resource_group: azure_vm.resource_group,
14
+ nics: [])
15
+
9
16
  @azure_vm = azure_vm
10
17
  @sdk = sdk
18
+ @resource_group ||= resource_group
19
+ @nics ||= nics
20
+ @azure_vm.hardware_profile ||= ComputeModels::HardwareProfile.new
21
+ @azure_vm.os_profile ||= ComputeModels::OSProfile.new
22
+ @azure_vm.os_profile.linux_configuration ||= ComputeModels::LinuxConfiguration.new
23
+ @azure_vm.os_profile.linux_configuration.ssh ||= ComputeModels::SshConfiguration.new
24
+ @azure_vm.os_profile.linux_configuration.ssh.public_keys ||= [ComputeModels::SshPublicKey.new]
25
+ @azure_vm.storage_profile ||= ComputeModels::StorageProfile.new
26
+ @azure_vm.storage_profile.os_disk ||= ComputeModels::OSDisk.new
27
+ @azure_vm.storage_profile.os_disk.managed_disk ||= ComputeModels::ManagedDiskParameters.new
11
28
  end
12
29
 
13
30
  def id
@@ -18,10 +35,6 @@ module ForemanAzureRM
18
35
  !!identity && !!id
19
36
  end
20
37
 
21
- def vm_size
22
- @azure_vm.hardware_profile.vm_size
23
- end
24
-
25
38
  def wait_for(_timeout = 0, _interval = 0, &block)
26
39
  instance_eval(&block)
27
40
  return true
@@ -35,46 +48,60 @@ module ForemanAzureRM
35
48
  vm_status
36
49
  end
37
50
 
51
+ def start
52
+ sdk.start_vm(@azure_vm.resource_group, name)
53
+ true
54
+ end
55
+
56
+ def stop
57
+ sdk.stop_vm(@azure_vm.resource_group, name)
58
+ true
59
+ end
60
+
38
61
  def vm_status
39
62
  sdk.check_vm_status(@azure_vm.resource_group, name)
40
63
  end
41
64
 
42
65
  def network_interface_card_ids
66
+ return nil unless @azure_vm.network_profile
43
67
  nics = @azure_vm.network_profile.network_interfaces
44
68
  nics.map(&:id)
45
69
  end
46
70
 
47
71
  def provisioning_ip_address
72
+ public_ip_address || private_ip_address
73
+ end
74
+
75
+ def public_ip_address
48
76
  interfaces.each do |nic|
49
77
  nic.ip_configurations.each do |configuration|
50
78
  next unless configuration.primary
51
- if configuration.public_ipaddress.present?
52
- ip_id = configuration.public_ipaddress.id
53
- ip_rg = ip_id.split('/')[4]
54
- ip_name = ip_id.split('/')[-1]
55
- public_ip = sdk.public_ip(ip_rg, ip_name)
56
- return public_ip.ip_address
57
- else
58
- return configuration.private_ipaddress
59
- end
79
+ return nil if configuration.public_ipaddress.blank?
80
+ ip_id = configuration.public_ipaddress.id
81
+ ip_rg = ip_id.split('/')[4]
82
+ ip_name = ip_id.split('/')[-1]
83
+ public_ip = sdk.public_ip(ip_rg, ip_name)
84
+ return public_ip.ip_address
60
85
  end
61
- end
86
+ end
62
87
  end
63
88
 
64
- def interfaces
65
- interfaces = []
66
- unless network_interface_card_ids.nil?
67
- network_interface_card_ids.each do |nic_id|
68
- nic_rg = nic_id.split('/')[4]
69
- nic_name = nic_id.split('/')[-1]
70
- interfaces << sdk.vm_nic(nic_rg, nic_name)
89
+ def private_ip_address
90
+ interfaces.each do |nic|
91
+ nic.ip_configurations.each do |configuration|
92
+ next unless configuration.primary
93
+ if configuration.private_ipaddress.present?
94
+ return private_ip_address = configuration.private_ipaddress
95
+ end
71
96
  end
72
97
  end
73
- interfaces
74
98
  end
75
99
 
76
- def interfaces=(setifaces)
77
- @azure_vm.network_profile.network_interfaces = setifaces
100
+ def interfaces
101
+ nics
102
+ end
103
+
104
+ def interfaces_attributes=(attrs)
78
105
  end
79
106
 
80
107
  def ip_addresses
@@ -89,7 +116,45 @@ module ForemanAzureRM
89
116
  @azure_vm.name = setuuid
90
117
  end
91
118
 
92
- def image_id
119
+ # Following properties are for AzureRM
120
+ # These are not part of Foreman's interface
121
+
122
+ def vm_size
123
+ @azure_vm.hardware_profile.vm_size
124
+ end
125
+
126
+ def platform
127
+ @azure_vm.storage_profile.os_disk.os_type
128
+ end
129
+
130
+ def username
131
+ @azure_vm.os_profile.admin_username
132
+ end
133
+
134
+ def password
135
+ @azure_vm.os_profile.admin_password
136
+ end
137
+
138
+ def ssh_key_data
139
+ # since you can only give one additional
140
+ # sshkey through foreman's UI
141
+ sshkey = @azure_vm.os_profile.linux_configuration.ssh.public_keys[1]
142
+ return unless sshkey.present?
143
+ sshkey.key_data
144
+ end
145
+
146
+ def premium_os_disk
147
+ @azure_vm.storage_profile.os_disk.managed_disk.storage_account_type
148
+ end
149
+
150
+ def os_disk_caching
151
+ @azure_vm.storage_profile.os_disk.caching
152
+ end
153
+
154
+ def script_command
155
+ end
156
+
157
+ def script_uris
93
158
  end
94
159
  end
95
160
  end
@@ -1 +1 @@
1
- attributes :user, :uuid
1
+ attributes :tenant, :app_ident, :sub_id, :secret_key, :region
@@ -1,8 +1,10 @@
1
- <%= text_f f, :url, :label => _('Client ID'), :required => true %>
1
+ <%= text_f f, :app_ident, :label => _('Client ID'), :required => true %>
2
2
  <%= password_f f, :password, :label => _('Client Secret'), :keep_value => true, :required => true %>
3
3
  <%= text_f f, :user, :label => _('Subscription ID'), :required => true %>
4
4
  <%= text_f f, :uuid, :label => _('Tenant ID'), :required => true %>
5
5
 
6
+ <%= selectable_f(f, :url, f.object.regions, {}, {:label => _('Azure Region'), :required => true }) %>
7
+
6
8
  <div class="col-md-offset-2">
7
9
  <%= test_connection_button_f(f, true) %>
8
10
  </div>
@@ -2,16 +2,17 @@
2
2
  os ||= nil
3
3
  images = possible_images(compute_resource, arch, os)
4
4
  resource_groups = compute_resource.resource_groups
5
+ compute_resource_id = compute_resource.id
5
6
  %>
6
7
 
7
- <script>
8
+ <script >
8
9
  function azure_rm_region_callback() {
9
10
  azure_rm_get_size_from_region();
10
11
  azure_rm_subnets_from_region();
11
12
  }
12
13
 
13
14
  function azure_rm_get_size_from_region() {
14
- var region = $('#azure_rm_region').val();
15
+ var compute_resource = <%=compute_resource_id%>;
15
16
  var size_spinner = $('#azure_rm_size_spinner');
16
17
  var sizes = $('#azure_rm_size');
17
18
  var imageId = $('#azure_rm_image_id').val();
@@ -22,7 +23,7 @@
22
23
  }
23
24
  size_spinner.removeClass('hide');
24
25
  $.ajax({
25
- data: {"region_string": region, "image_id": imageId},
26
+ data: {"image_id": imageId, "compute_resource_id": compute_resource},
26
27
  type: 'get',
27
28
  url: '/azure_rm/sizes',
28
29
  complete: function () {
@@ -50,14 +51,14 @@
50
51
  function azure_rm_subnets_from_region() {
51
52
  var imageId = $('#azure_rm_image_id').val();
52
53
  var subnets = $('#azure_rm_subnet');
53
- var region = $('#azure_rm_region').val();
54
+ var compute_resource = <%=compute_resource_id%>;
54
55
  if (typeof tfm == 'undefined') { // earlier than 1.13
55
56
  foreman.tools.showSpinner();
56
57
  } else {
57
58
  tfm.tools.showSpinner();
58
59
  }
59
60
  $.ajax({
60
- data: {"image_id": imageId, "region": region},
61
+ data: {"image_id": imageId, "compute_resource_id": compute_resource},
61
62
  type: 'get',
62
63
  url: '/azure_rm/subnets',
63
64
  complete: function () {
@@ -84,109 +85,102 @@
84
85
  }
85
86
  </script>
86
87
 
87
- <% #This view has been modified and wraps the properties of azure_vm
88
- # using fields_for rails method.
88
+ <% # This view has been modified and refers to the properties wrapper class %>
89
+
90
+ <%= selectable_f f, :resource_group, resource_groups,
91
+ { :include_blank => true },
92
+ {
93
+ :disabled => resource_groups.empty?,
94
+ :label => _('Resource Group'),
95
+ :required => true,
96
+ :id => 'azure_rm_rg',
97
+ :help_inline => spinner_button_f(f, _('Reload Images, Sizes, vNets'),
98
+ 'azure_rm_region_callback();',
99
+ {
100
+ :id => 'load_subnets_btn',
101
+ :spinner_id => 'load_subnets_indicator',
102
+ :class => 'btn-success',
103
+ :spinner_class => 'spinner-inverse'
104
+ })
105
+ }
89
106
  %>
90
107
 
91
- <%= f.fields_for :azure_vm do |vm_f| %>
108
+ <%= selectable_f f, :vm_size, compute_resource.vm_sizes.map { |size| size.name },
109
+ {},
110
+ {
111
+ :label => _('VM Size'),
112
+ :required => true,
113
+ :id => 'azure_rm_size'
114
+ }
115
+ %>
92
116
 
93
- <%= selectable_f vm_f, :location, compute_resource.regions,
94
- { :include_blank => _('Please select an Azure region') },
117
+ <%= selectable_f f, :platform, %w(Linux Windows),
118
+ {},
95
119
  {
96
- :label => _('Azure Region'),
97
- :required => true,
98
- :id => 'azure_rm_region',
99
- :label_size => "col-md-2",
100
- :onchange => 'azure_rm_region_callback();',
101
- :help_inline => spinner_button_f(f, _('Reload Images, Sizes, vNets'),
102
- 'azure_rm_region_callback();',
103
- {
104
- :id => 'load_subnets_btn',
105
- :spinner_id => 'load_subnets_indicator',
106
- :class => 'btn-success',
107
- :spinner_class => 'spinner-inverse'
108
- })
120
+ :label => _('Platform'),
121
+ :required => true
109
122
  }
110
- %>
123
+ %>
111
124
 
112
- <%= selectable_f vm_f, :resource_group, resource_groups,
113
- { :include_blank => true },
114
- {
115
- :disabled => resource_groups.empty?,
116
- :label => _('Resource Group'),
117
- :required => true,
118
- :id => 'azure_rm_rg'
119
- }
120
- %>
125
+ <%= text_f f, :username,
126
+ {
127
+ :label => _('Username'),
128
+ :required => true
129
+ }
130
+ %>
121
131
 
122
- <%= selectable_f vm_f, :vm_size, [],
123
- { :include_blank => _('Please first select an Azure region') },
124
- {
125
- :label => _('VM Size'),
126
- :required => true,
127
- :id => 'azure_rm_size'
128
- }
129
- %>
132
+ <%= password_f f, :password,
133
+ {
134
+ :label => _('Password'),
135
+ :required => true,
136
+ :placeholder => "********",
137
+ :value => f.object.password
130
138
 
131
- <%= selectable_f vm_f, :platform, %w(Linux Windows),
132
- {},
133
- {
134
- :label => _('Platform'),
135
- :required => true
136
- }
137
- %>
139
+ }
140
+ %>
138
141
 
139
- <%= text_f vm_f, :username,
140
- {
141
- :label => _('Username'),
142
- :required => true
143
- }
144
- %>
142
+ <%= textarea_f f, :ssh_key_data,
143
+ {
144
+ :label => _('SSH Key')
145
+ }
146
+ %>
145
147
 
146
- <%= password_f vm_f, :password,
147
- {
148
- :label => _('Password'),
149
- :required => true,
150
- :placeholder => "********"
151
- }
152
- %>
148
+ <%= checkbox_f f, :premium_os_disk,
149
+ { :checked => f.object.premium_os_disk == "Premium_LRS",
150
+ :label => _('Premium OS Disk'),
151
+ :label_size => "col-md-2"
152
+ },
153
+ 'true',
154
+ 'false'
155
+ %>
153
156
 
154
- <%= textarea_f vm_f, :ssh_key_data,
157
+ <%= selectable_f f, :os_disk_caching, %w(None ReadOnly ReadWrite),
158
+ {},
155
159
  {
156
- :label => _('SSH Key')
160
+ :label => _('OS Disk Caching'),
161
+ :required => true,
162
+ :class => "col-md-2"
157
163
  }
158
- %>
164
+ %>
159
165
 
160
- <%= checkbox_f vm_f, :premium_os_disk,
161
- {
162
- :label => _('Premium OS Disk'), :label_size => "col-md-2"
163
- },
164
- 'true',
165
- 'false'
166
- %>
166
+ <%= text_f f, :script_command,
167
+ {
168
+ :label => _('Custom Script Command'),
169
+ :help_inline => _("To perform commands as root, prefix it with 'sudo'.")
170
+ }
171
+ %>
167
172
 
168
- <%= selectable_f vm_f, :os_disk_caching, %w(None ReadOnly ReadWrite),
169
- {},
170
- {
171
- :label => _('OS Disk Caching'),
172
- :required => true,
173
- :class => "col-md-2"
174
- }
175
- %>
173
+ <%= text_f f, :script_uris,
174
+ {
175
+ :label => _('Comma seperated file URIs')
176
+ }
177
+ %>
176
178
 
177
- <%= text_f vm_f, :script_command,
178
- {
179
- :label => _('Custom Script Command'),
180
- :help_inline => _("To perform commands as root, prefix it with 'sudo'.")
181
- }
182
- %>
179
+ <% checked = params[:host] && params[:host][:compute_attributes] && params[:host][:compute_attributes][:start] || '1'
180
+ %>
183
181
 
184
- <%= text_f vm_f, :script_uris,
185
- {
186
- :label => _('Comma seperated file URIs')
187
- }
188
- %>
189
- <% end %>
182
+ <%= checkbox_f f, :start, { :checked => (checked == '1'), :help_inline => _("Power ON this machine upon creation"), :label => _('Start'), :label_size => "col-md-2" } if new_vm && controller_name != "compute_attributes"
183
+ %>
190
184
 
191
185
  <div id="image_selection">
192
186
  <%= select_f f, :image_id, images, :uuid, :name,
@@ -1,5 +1,8 @@
1
- <%= selectable_f f, :network, [],
2
- { :include_blank => _('Please first select an image and an Azure region')},
1
+ <% nat = compute_resource.subnets.collect { |s| [ "#{s.id.split('/')[8]}-#{s.name} #{s.address_prefix}", s.id ] } %>
2
+
3
+ <%= selectable_f f, :network, options_for_select(nat,
4
+ :selected => f.object.network),
5
+ { :include_blank => _('Select') },
3
6
  {
4
7
  :label => _('Azure Subnet'),
5
8
  :required => true,
@@ -8,16 +11,21 @@
8
11
  }
9
12
  %>
10
13
 
11
- <%= selectable_f f, :bridge, ['None', 'Dynamic', 'Static'],
14
+ <%= selectable_f f, :public_ip, options_for_select(['None', 'Dynamic', 'Static'],
15
+ :selected => f.object.public_ip),
12
16
  {},
13
17
  {
14
- :label => _("Public IP"),
15
- :label_size => "col-md-2"
18
+ :label => _("Public IP"),
19
+ :label_size => "col-md-2"
16
20
  }
17
21
  %>
18
22
 
19
- <%= checkbox_f f, :name,
20
- { :label => _("Static Private IP"), :label_size => "col-md-2" },
21
- 'true',
22
- 'false'
23
- %>
23
+ <%= checkbox_f f, :private_ip,
24
+ {
25
+ :label => _("Static Private IP"),
26
+ :label_size => "col-md-2"
27
+ },
28
+ 'true',
29
+ 'false'
30
+
31
+ %>
@@ -6,14 +6,14 @@
6
6
  <th><%= _('Resource Group') %></th>
7
7
  <th><%= _('Region') %></th>
8
8
  <th><%= _('State') %></th>
9
- <th></th>
9
+ <th><%= _('Actions') %></th>
10
10
  </tr>
11
11
  </thead>
12
12
  <% @vms.each do |vm| %>
13
13
  <tr>
14
14
  <td><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => :authorizer) %></td>
15
15
  <td><%= vm.vm_size %></td>
16
- <td><%= vm.azure_vm.resource_group %></td>
16
+ <td><%= vm.resource_group %></td>
17
17
  <td><%= vm.azure_vm.location %></td>
18
18
  <td> <span <%= vm_power_class(vm.ready?) %>> <%= vm_state(vm) %> </span> </td>
19
19
  <td>
@@ -2,5 +2,5 @@
2
2
  :help_inline => _("The user that will be used to SSH into the VM for completion")
3
3
  %>
4
4
  <%= password_f f, :password, :help_inline => _("Password to authenticate with - used for SSH finish step.") %>
5
- <%= image_field(f, :label => _("Managed Image ID or Marketplace URN")) %>
5
+ <%= image_field(f, :label => _("Marketplace Image URN"), :help_inline => _("Marketplace URN (e.g. OpenLogic:CentOS:7.5:latest)")) %>
6
6
  <%= checkbox_f f, :user_data, :help_inline => _("Does this image support user data input?") %>
@@ -1,5 +1,17 @@
1
1
  require 'foreman_azure_rm/engine.rb'
2
+ require 'azure_mgmt_resources'
3
+ require 'azure_mgmt_network'
4
+ require 'azure_mgmt_storage'
5
+ require 'azure_mgmt_compute'
2
6
 
3
7
  module ForemanAzureRM
8
+ Storage = Azure::Storage::Profiles::Latest::Mgmt
9
+ Network = Azure::Network::Profiles::Latest::Mgmt
10
+ Compute = Azure::Compute::Profiles::Latest::Mgmt
11
+ Resources = Azure::Resources::Profiles::Latest::Mgmt
4
12
 
13
+ StorageModels = Storage::Models
14
+ NetworkModels = Network::Models
15
+ ComputeModels = Compute::Models
16
+ ResourceModels = Resources::Models
5
17
  end
@@ -1,14 +1,4 @@
1
1
  module ForemanAzureRM
2
- Storage = Azure::Storage::Profiles::Latest::Mgmt
3
- Network = Azure::Network::Profiles::Latest::Mgmt
4
- Compute = Azure::Compute::Profiles::Latest::Mgmt
5
- Resources = Azure::Resources::Profiles::Latest::Mgmt
6
-
7
- StorageModels = Storage::Models
8
- NetworkModels = Network::Models
9
- ComputeModels = Compute::Models
10
- ResourceModels = Resources::Models
11
-
12
2
  class AzureSDKAdapter
13
3
  def initialize(tenant, app_ident, secret_key, sub_id)
14
4
  @tenant = tenant
@@ -56,8 +46,8 @@ module ForemanAzureRM
56
46
  network_client.virtual_networks.list_all
57
47
  end
58
48
 
59
- def subnets(resource_group, vnet_name)
60
- network_client.subnets.list(resource_group, vnet_name)
49
+ def subnets(rg_name, vnet_name)
50
+ network_client.subnets.list(rg_name, vnet_name)
61
51
  end
62
52
 
63
53
  def public_ip(rg_name, pip_name)
@@ -68,14 +58,19 @@ module ForemanAzureRM
68
58
  network_client.network_interfaces.get(rg_name, nic_name)
69
59
  end
70
60
 
61
+ def get_vm_extension(rg_name, vm_name, vm_extension_name)
62
+ compute_client.virtual_machine_extensions.get(rg_name, vm_name, vm_extension_name)
63
+ end
64
+
71
65
  def list_vm_sizes(region)
66
+ return [] unless region.present?
72
67
  stripped_region = region.gsub(/\s+/, '').downcase
73
68
  compute_client.virtual_machine_sizes.list(stripped_region).value()
74
69
  end
75
70
 
76
- def list_vms(rg_name)
71
+ def list_vms(region)
77
72
  # List all VMs in a resource group
78
- virtual_machines = compute_client.virtual_machines.list(rg_name)
73
+ virtual_machines = compute_client.virtual_machines.list_by_location(region)
79
74
  end
80
75
 
81
76
  def get_vm(rg_name, vm_name)
@@ -137,5 +132,14 @@ module ForemanAzureRM
137
132
  end
138
133
  vm_status
139
134
  end
135
+
136
+ def start_vm(rg_name, vm_name)
137
+ compute_client.virtual_machines.start(rg_name, vm_name)
138
+ end
139
+
140
+ def stop_vm(rg_name, vm_name)
141
+ compute_client.virtual_machines.power_off(rg_name, vm_name)
142
+ compute_client.virtual_machines.deallocate(rg_name, vm_name)
143
+ end
140
144
  end
141
145
  end
@@ -4,13 +4,19 @@ module ForemanAzureRM
4
4
 
5
5
  #autoloading all files inside lib dir
6
6
  config.autoload_paths += Dir["#{config.root}/lib"]
7
- config.autoload_paths += Dir["#{config.root}/app/models/concerns"]
7
+ config.autoload_paths += Dir["#{config.root}/app/models/concerns/foreman_azure_rm/vm_extensions/"]
8
8
 
9
9
  initializer 'foreman_azure_rm.register_plugin', :before => :finisher_hook do
10
10
  Foreman::Plugin.register :foreman_azure_rm do
11
11
  requires_foreman '>= 1.17'
12
12
  compute_resource ForemanAzureRM::AzureRM
13
- parameter_filter ComputeResource, :azure_vm, :tenant, :app_ident, :secret_key, :sub_id
13
+ parameter_filter ComputeResource, :azure_vm, :tenant, :app_ident, :secret_key, :sub_id, :region
14
+ end
15
+ end
16
+
17
+ initializer "foreman_azure_rm.add_rabl_view_path" do
18
+ Rabl.configure do |config|
19
+ config.view_paths << ForemanAzureRM::Engine.root.join('app', 'views')
14
20
  end
15
21
  end
16
22
 
@@ -1,3 +1,3 @@
1
1
  module ForemanAzureRM
2
- VERSION = '2.0.0.pre1'.freeze
2
+ VERSION = '2.0.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_azure_rm
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre1
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aditi Puntambekar
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-08-21 00:00:00.000000000 Z
13
+ date: 2019-10-31 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: deface
@@ -169,9 +169,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
169
169
  version: '0'
170
170
  required_rubygems_version: !ruby/object:Gem::Requirement
171
171
  requirements:
172
- - - ">"
172
+ - - ">="
173
173
  - !ruby/object:Gem::Version
174
- version: 1.3.1
174
+ version: '0'
175
175
  requirements: []
176
176
  rubyforge_project:
177
177
  rubygems_version: 2.7.6