foreman_azure_rm 1.3.1 → 2.0.0.pre1

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
- SHA1:
3
- metadata.gz: c1c4e6dbdc0dbe85c19fed181beb16d91aac9909
4
- data.tar.gz: 84a125c8cccf9e472805d98b7841b1008d7f095d
2
+ SHA256:
3
+ metadata.gz: 8cdbc28091795bf21377b298699209cc2a0d06365858d117b9468a466fb0ffe2
4
+ data.tar.gz: 938f88f1ac6e6f9d9101ce57d2bf187e5c1196fd4abf68c667ae38db5c3270e2
5
5
  SHA512:
6
- metadata.gz: db1923e2cc13efd600fe2fc3192556491043e656b9a92e3920f4368c0c1d37b53dbdb9f501f89b93dcae541a14c6aac1f95409ad1238bb06ac7f08b4d13caf5b
7
- data.tar.gz: 7efdedb724d265fba4664acab40846fd10fee503cd5d52f3d499568ef89763fc3696dc840370796e6923763836651a883c7242059915cb7bcbf4d6c74f40b0cc
6
+ metadata.gz: c4def716d7fa2719d629c0bb9029a60e079e5578c16a33c9baa624462e3da7cdf634fa8f64070fef86bd4b615f9bccafedb427f073facad2a3e5f021bb74eedc
7
+ data.tar.gz: e2dbb0b84df8d5d7a62fa87486b858c5ee11cd28dcdf072ada26cbd77036942837f92f699e7738f40378cc839d0fde9cfc113d53c846b5af84af17dec14f78f4
data/README.md CHANGED
@@ -1,23 +1,51 @@
1
- # Foreman Azure
1
+ # Foreman AzureRM Plugin
2
2
 
3
3
  ## Description
4
- Plugin to add [Microsoft Azure Resource Manager](http://azure.com/) as a compute resource for [The Foreman](http://theforeman.org/)
4
+ ```foreman_azure_rm``` adds [Microsoft Azure Resource Manager](http://azure.com/) as a compute resource for The Foreman
5
+
6
+ * Website: [TheForeman.org](http://theforeman.org)
7
+ * Support: [Foreman support](http://theforeman.org/support.html)
5
8
 
6
9
  ## Features
7
- * Managed disks support
8
10
  * Support for most typical IaaS operations
9
11
  * VM creation
10
- * Multiple NICs
11
- * Multiple data disks, premium or not
12
+ * Provisions using Finish and User data templates from Foreman
13
+ * Supports cloud-config provisioning
14
+ * Currently supports single NIC
15
+ * Currently supports single default OS Disk
16
+ * Currently supports only provisioning of Linux platforms
17
+ * Provisioning using [Public Images](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage)
12
18
  * Static or dynamic addresses on a per NIC basis
13
19
  * Limited extension support
14
20
  * Microsoft's custom script extension
15
21
  * Puppet Lab's Puppet agent extension for Windows
22
+
23
+ ## Configuration
24
+ Go to **Infrastructure > Compute Resources** and click on "New Compute Resource".
25
+
26
+ Choose the **AzureRM provider**, and fill in all the fields. You need a Subscription ID, Tenant ID, Client ID and a Client Secret which you can generate from your [Microsoft Azure subscription](https://docs.bmc.com/docs/cloudlifecyclemanagement/46/setting-up-a-tenant-id-client-id-and-client-secret-for-azure-resource-manager-provisioning-669202145.html#SettingupaTenantID,ClientID,andClientSecretforAzureResourceManagerprovisioning-SetupTenantIDPrereqPrerequisites)
27
+
28
+ That's it. You're now ready to create and manage Azure resources in your new AzureRM compute resource. You should see something like this in the Compute Resource page:
29
+
30
+
31
+ ![](https://i.imgur.com/9J7tPJa.png)
32
+
33
+
34
+ ![](https://i.imgur.com/eFHucdb.png)
35
+
36
+
37
+ ![](https://i.imgur.com/RTBlMeE.png)
38
+
16
39
 
17
40
  ## Planned Features
41
+ * Multiple NICs support
42
+ * Support to add multiple data disks (standard or premium)
43
+ * Provision using custom images
44
+ * Provision using shared image galleries
18
45
  * Improved extension support
19
46
 
20
47
  ## Known Limitations
21
- * Most Azure marketplace images (likely all of them) disallow direct root login, which means SSH provisioning
22
- with The Foreman has limited functionality. A workaround is to provide a dummy user data template and do all
23
- post-provisioning with the custom script extension
48
+ * Unable to provision using Windows Images
49
+
50
+ ## Links
51
+ * [Issue tracker](https://projects.theforeman.org/projects/azurerm)
@@ -5,9 +5,9 @@ module ForemanAzureRM
5
5
  def sizes
6
6
  if (azure_rm_resource = Image.unscoped.find_by_uuid(params[:image_id])).present?
7
7
  resource = azure_rm_resource.compute_resource
8
- render :json => resource.vm_sizes(params[:location_string]).map { |size| size.name }
8
+ render :json => resource.vm_sizes(params[:region_string]).map { |size| size.name }
9
9
  else
10
- no_sizes = _('The location you selected has no sizes associated with it')
10
+ no_sizes = _('The region you selected has no sizes associated with it')
11
11
  render :json => "[\"#{no_sizes}\"]"
12
12
  end
13
13
  end
@@ -16,11 +16,11 @@ module ForemanAzureRM
16
16
  azure_rm_image = Image.unscoped.find_by_uuid(params[:image_id])
17
17
  if azure_rm_image.present?
18
18
  azure_rm_resource = azure_rm_image.compute_resource
19
- subnets = azure_rm_resource.subnets(params[:location])
19
+ subnets = azure_rm_resource.subnets(params[:region])
20
20
  if subnets.present?
21
- render :json => azure_rm_resource.subnets(params[:location])
21
+ render :json => subnets
22
22
  else
23
- no_subnets = _('The selected location has no subnets')
23
+ no_subnets = _('The selected region has no subnets')
24
24
  render :json => "[\"#{no_subnets}\"]"
25
25
  end
26
26
  else
@@ -30,4 +30,4 @@ module ForemanAzureRM
30
30
  end
31
31
  end
32
32
  end
33
- end
33
+ end
@@ -0,0 +1,216 @@
1
+ # This concern has the methods to be called inside azure_rm.rb
2
+ module ForemanAzureRM
3
+ module VMExtensions
4
+ module ManagedVM
5
+ extend ActiveSupport::Concern
6
+
7
+ def define_managed_storage_profile(vm_name, vhd_path, publisher, offer, sku, version,
8
+ os_disk_caching, platform, premium_os_disk)
9
+ storage_profile = ComputeModels::StorageProfile.new
10
+ os_disk = ComputeModels::OSDisk.new
11
+ managed_disk_params = ComputeModels::ManagedDiskParameters.new
12
+
13
+ # Create OS disk
14
+ os_disk.name = "#{vm_name}-osdisk"
15
+ os_disk.os_type = platform
16
+ os_disk.create_option = ComputeModels::DiskCreateOptionTypes::FromImage
17
+ os_disk.caching = if os_disk_caching.present?
18
+ case os_disk_caching
19
+ when 'None'
20
+ ComputeModels::CachingTypes::None
21
+ when 'ReadOnly'
22
+ ComputeModels::CachingTypes::ReadOnly
23
+ when 'ReadWrite'
24
+ ComputeModels::CachingTypes::ReadWrite
25
+ else
26
+ # ARM best practices stipulate RW caching on the OS disk
27
+ ComputeModels::CachingTypes::ReadWrite
28
+ end
29
+ end
30
+ managed_disk_params.storage_account_type = if premium_os_disk == 'true'
31
+ ComputeModels::StorageAccountTypes::PremiumLRS
32
+ else
33
+ ComputeModels::StorageAccountTypes::StandardLRS
34
+ end
35
+ os_disk.managed_disk = managed_disk_params
36
+ storage_profile.os_disk = os_disk
37
+
38
+ # Currently eliminating data disk creation since capability does not exist.
39
+
40
+ if vhd_path.nil?
41
+ # We are using a marketplace image
42
+ storage_profile.image_reference = image_reference(publisher, offer,
43
+ sku, version)
44
+ else
45
+ # We are using a custom managed image
46
+ image_ref = ComputeModels::ImageReference.new
47
+ image_ref.id = vhd_path
48
+ storage_profile.image_reference = image_ref
49
+ end
50
+ storage_profile
51
+ end
52
+
53
+ def image_reference(publisher, offer, sku, version)
54
+ image_reference = ComputeModels::ImageReference.new
55
+ image_reference.publisher = publisher
56
+ image_reference.offer = offer
57
+ image_reference.sku = sku
58
+ image_reference.version = version
59
+ image_reference
60
+ end
61
+
62
+ def define_network_profile(network_interface_card_ids)
63
+ network_interface_cards = []
64
+ network_interface_card_ids.each_with_index do |id, index|
65
+ nic = ComputeModels::NetworkInterfaceReference.new
66
+ nic.id = id
67
+ nic.primary = true
68
+ network_interface_cards << nic
69
+ end
70
+ network_profile = ComputeModels::NetworkProfile.new
71
+ network_profile.network_interfaces = network_interface_cards
72
+ network_profile
73
+ end
74
+
75
+ def create_nics(args = {})
76
+ nics = []
77
+ formatted_region = args[:azure_vm][:location].gsub(/\s+/, '').downcase
78
+ 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?
95
+ public_ip_params = NetworkModels::PublicIPAddress.new.tap do |ip|
96
+ ip.location = formatted_region
97
+ ip.public_ipallocation_method = pip_alloc
98
+ end
99
+ pip = sdk.create_or_update_pip(args[:azure_vm][:resource_group],
100
+ "#{args[:azure_vm][:vm_name]}-pip#{nic}",
101
+ public_ip_params)
102
+ end
103
+ new_nic = sdk.create_or_update_nic(
104
+ args[:azure_vm][:resource_group],
105
+ "#{args[:azure_vm][:vm_name]}-nic#{nic}",
106
+ NetworkModels::NetworkInterface.new.tap do |interface|
107
+ interface.location = formatted_region
108
+ interface.ip_configurations = [
109
+ NetworkModels::NetworkInterfaceIPConfiguration.new.tap do |nic_conf|
110
+ nic_conf.name = "#{args[:azure_vm][:vm_name]}-nic#{nic}"
111
+ 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
114
+ end
115
+ ]
116
+ end
117
+ )
118
+ nics << new_nic
119
+ end
120
+ nics
121
+ end
122
+
123
+ def create_managed_virtual_machine(vm_hash)
124
+ custom_data = vm_hash[:custom_data]
125
+ msg = "Creating Virtual Machine #{vm_hash[:name]} in Resource Group #{vm_hash[:resource_group]}."
126
+ logger.debug msg
127
+ vm_create_params = ComputeModels::VirtualMachine.new.tap do |vm|
128
+ vm.location = vm_hash[:location]
129
+ unless vm_hash[:availability_set_id].nil?
130
+ sub_resource = MsRestAzure::SubResource.new
131
+ sub_resource.id = vm_hash[:availability_set_id]
132
+ vm.availability_set = sub_resource
133
+ end
134
+ # If image UUID begins with / it is a custom managed image
135
+ # Otherwise it is a marketplace URN
136
+ unless vm_hash[:vhd_path].start_with?('/')
137
+ urn = vm_hash[:vhd_path].split(':')
138
+ vm_hash[:publisher] = urn[0]
139
+ vm_hash[:offer] = urn[1]
140
+ vm_hash[:sku] = urn[2]
141
+ vm_hash[:version] = urn[3]
142
+ vm_hash[:vhd_path] = nil
143
+ end
144
+
145
+ vm.os_profile = ComputeModels::OSProfile.new.tap do |os_profile|
146
+ os_profile.computer_name = vm_hash[:name]
147
+ os_profile.admin_username = vm_hash[:username]
148
+ os_profile.admin_password = vm_hash[:password]
149
+
150
+ # Adding the ssh-key support for authentication
151
+ os_profile.linux_configuration = ComputeModels::LinuxConfiguration.new.tap do |linux|
152
+ linux.disable_password_authentication = vm_hash[:disable_password_authentication]
153
+ linux.ssh = ComputeModels::SshConfiguration.new.tap do |ssh_config|
154
+ ssh_config.public_keys = [
155
+ ComputeModels::SshPublicKey.new.tap do |foreman_key|
156
+ foreman_key.key_data = key_pair.public
157
+ foreman_key.path = "/home/#{vm_hash[:username]}/.ssh/authorized_keys"
158
+ end
159
+ ]
160
+ if vm_hash[:ssh_key_data].present?
161
+ key_data = vm_hash[:ssh_key_data]
162
+ pub_key = ComputeModels::SshPublicKey.new
163
+ pub_key.key_data = key_data
164
+ pub_key.path = "/home/#{vm_hash[:username]}/.ssh/authorized_keys"
165
+ ssh_config.public_keys << pub_key
166
+ end
167
+ end
168
+ end
169
+ # added custom_data here so that azure's vm gets this
170
+ os_profile.custom_data = Base64.strict_encode64(custom_data) unless vm_hash[:custom_data].nil?
171
+ end
172
+ vm.storage_profile = define_managed_storage_profile(
173
+ vm_hash[:name],
174
+ vm_hash[:vhd_path],
175
+ vm_hash[:publisher],
176
+ vm_hash[:offer],
177
+ vm_hash[:sku],
178
+ vm_hash[:version],
179
+ vm_hash[:os_disk_caching],
180
+ vm_hash[:platform],
181
+ vm_hash[:premium_os_disk],
182
+ )
183
+ vm.hardware_profile = ComputeModels::HardwareProfile.new.tap do |hw_profile|
184
+ hw_profile.vm_size = vm_hash[:vm_size]
185
+ end
186
+ vm.network_profile = define_network_profile(vm_hash[:network_interface_card_ids])
187
+ end
188
+
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
192
+ end
193
+
194
+ def create_vm_extension(args = {})
195
+ if args[:azure_vm][:script_command].present? || args[:azure_vm][:script_uris].present?
196
+ extension = ComputeModels::VirtualMachineExtension.new
197
+ if args[:azure_vm][:platform] == 'Linux'
198
+ extension.publisher = 'Microsoft.Azure.Extensions'
199
+ extension.virtual_machine_extension_type = 'CustomScript'
200
+ extension.type_handler_version = '2.0'
201
+ end
202
+ extension.auto_upgrade_minor_version = true
203
+ extension.location = args[:azure_vm][:location].gsub(/\s+/, '').downcase
204
+ extension.settings = {
205
+ 'commandToExecute' => args[:azure_vm][:script_command],
206
+ 'fileUris' => args[:azure_vm][:script_uris].split(',')
207
+ }
208
+ sdk.create_or_update_vm_extensions(args[:azure_vm][:resource_group],
209
+ args[:azure_vm][:vm_name],
210
+ 'ForemanCustomScript',
211
+ extension)
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
@@ -1,11 +1,25 @@
1
+ # This Model contains code modified as per azure-sdk
2
+ # and removed dependencies from fog-azure-rm.
3
+ #
4
+ require 'base64'
5
+
1
6
  module ForemanAzureRM
2
7
  class AzureRM < ComputeResource
8
+
9
+ include VMExtensions::ManagedVM
3
10
  alias_attribute :sub_id, :user
4
11
  alias_attribute :secret_key, :password
5
12
  alias_attribute :app_ident, :url
6
13
  alias_attribute :tenant, :uuid
7
14
 
8
- before_create :test_connection
15
+ validates :user, :presence => true
16
+ validates :password, :presence => true
17
+ validates :url, :presence => true
18
+ validates :uuid, :presence => true
19
+
20
+ has_one :key_pair, :foreign_key => :compute_resource_id, :dependent => :destroy
21
+
22
+ before_create :test_connection, :setup_key_pair
9
23
 
10
24
  class VMContainer
11
25
  attr_accessor :virtualmachines
@@ -19,6 +33,10 @@ module ForemanAzureRM
19
33
  end
20
34
  end
21
35
 
36
+ def sdk
37
+ @sdk ||= ForemanAzureRM::AzureSDKAdapter.new(tenant, app_ident, secret_key, sub_id)
38
+ end
39
+
22
40
  def to_label
23
41
  "#{name} (#{provider_friendly_name})"
24
42
  end
@@ -35,8 +53,9 @@ module ForemanAzureRM
35
53
  [:image]
36
54
  end
37
55
 
38
- def locations
56
+ def regions
39
57
  [
58
+ 'West Europe',
40
59
  'Central US',
41
60
  'South Central US',
42
61
  'North Central US',
@@ -48,34 +67,41 @@ module ForemanAzureRM
48
67
  ]
49
68
  end
50
69
 
51
- def resource_groups
52
- rgs = rg_client.list_resource_groups
53
- rg_names = []
54
- rgs.each do |rg|
55
- rg_names << rg.name
56
- end
57
- rg_names
58
- end
59
-
60
- def available_resource_groups
61
- rg_client.list_resource_groups
62
- end
63
-
64
- def storage_accts(location = nil)
65
- stripped_location = location.gsub(/\s+/, '').downcase
70
+ def storage_accts(region = nil)
71
+ stripped_region = region.gsub(/\s+/, '').downcase
66
72
  acct_names = []
67
- if location.nil?
68
- storage_client.list_storage_accounts.each do |acct|
73
+ if region.nil?
74
+ sdk.get_storage_accts.each do |acct|
69
75
  acct_names << acct.name
70
76
  end
71
77
  else
72
- (storage_client.list_storage_accounts.select { |acct| acct.location == stripped_location }).each do |acct|
78
+ (sdk.get_storage_accts.select { |acct| acct.region == stripped_region }).each do |acct|
73
79
  acct_names << acct.name
74
80
  end
75
81
  end
76
82
  acct_names
77
83
  end
78
84
 
85
+ def resource_groups
86
+ sdk.rgs
87
+ end
88
+
89
+ def test_connection(options = {})
90
+ sdk.rgs.each do |rg|
91
+ puts "#{rg}"
92
+ end
93
+ super(options)
94
+ end
95
+
96
+ def new_vm(attr = {})
97
+ AzureRMCompute.new(sdk: sdk)
98
+ end
99
+
100
+ def stop
101
+ power_off
102
+ deallocate
103
+ end
104
+
79
105
  def provided_attributes
80
106
  super.merge({ :ip => :provisioning_ip_address })
81
107
  end
@@ -98,226 +124,144 @@ module ForemanAzureRM
98
124
  subnets
99
125
  end
100
126
 
101
- # TODO Delete this
102
- def networks
103
- subnets
104
- end
105
-
106
- def virtual_networks(location = nil)
107
- if location.nil?
108
- azure_network_service.virtual_networks
127
+ def virtual_networks(region = nil)
128
+ if region.nil?
129
+ sdk.vnets
109
130
  else
110
- stripped_location = location.gsub(/\s+/, '').downcase
111
- azure_network_service.virtual_networks.select { |vnet| vnet.location == stripped_location }
131
+ stripped_region = region.gsub(/\s+/, '').downcase
132
+ sdk.vnets.select { |vnet| vnet.location == stripped_region }
112
133
  end
113
134
  end
114
135
 
115
- def subnets(location = nil)
116
- vnets = virtual_networks(location)
136
+ def subnets(region = nil)
137
+ stripped_region = region.gsub(/\s+/, '').downcase
138
+ vnets = virtual_networks(stripped_region)
117
139
  subnets = []
118
140
  vnets.each do |vnet|
119
- subnets.concat(azure_network_service.subnets(resource_group: vnet.resource_group,
120
- virtual_network_name: vnet.name).all)
141
+ subnets.concat(sdk.subnets(vnet.resource_group, vnet.name))
121
142
  end
122
143
  subnets
123
144
  end
124
145
 
125
- def test_connection(options = {})
126
- rg_client.resource_groups.each do |rg|
127
- puts "#{rg.name}"
128
- end
129
- super(options)
146
+ def new_interface(attr = {})
147
+ # WIP
148
+ # calls nic_cards method in adapter
149
+ # causes compute profiles issue
150
+ # NetworkModels::NetworkInterface.new
130
151
  end
131
152
 
132
- def new_interface(attr = {})
133
- azure_network_service.network_interfaces.new(attr)
153
+ def vm_sizes(region)
154
+ sdk.list_vm_sizes(region)
134
155
  end
135
156
 
136
- def new_volume(attr = {})
137
- client.managed_disks.new(attr)
157
+ def vm_instance_defaults
158
+ ActiveSupport::HashWithIndifferentAccess.new
138
159
  end
139
160
 
140
161
  def vms
141
162
  container = VMContainer.new
142
- rg_client.resource_groups.each do |rg|
143
- client.servers(resource_group: rg.name).each do |vm|
144
- container.virtualmachines << vm
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)
145
167
  end
146
168
  end
147
169
  container
148
170
  end
149
171
 
150
- def vm_sizes(location)
151
- client.list_available_sizes(location)
172
+ def setup_key_pair
173
+ require 'sshkey'
174
+ name = "foreman-#{id}#{Foreman.uuid}"
175
+ key = ::SSHKey.generate
176
+ build_key_pair :name => name, :secret => key.private_key, :public => key.ssh_public_key
152
177
  end
153
178
 
154
179
  def find_vm_by_uuid(uuid)
155
- # TODO: Find a better way to handle this than loading and sorting through
156
- # all VMs, which also requires that names be globally unique, instead of
157
- # unique within a resource group
158
180
  vm = vms.all.find { |vm| vm.name == uuid }
159
181
  raise ActiveRecord::RecordNotFound unless vm.present?
160
182
  vm
161
183
  end
162
184
 
163
- def create_nics(args = {})
164
- nics = []
165
- formatted_location = args[:location].gsub(/\s+/, '').downcase
166
- args[:interfaces_attributes].each do |nic, attrs|
167
- attrs[:pubip_alloc] = attrs[:bridge]
168
- attrs[:privip_alloc] = (attrs[:name] == 'false') ? false : true
169
- pip_alloc = case attrs[:pubip_alloc]
170
- when 'Static'
171
- Fog::ARM::Network::Models::IPAllocationMethod::Static
172
- when 'Dynamic'
173
- Fog::ARM::Network::Models::IPAllocationMethod::Dynamic
174
- when 'None'
175
- nil
176
- end
177
- priv_ip_alloc = if attrs[:priv_ip_alloc]
178
- Fog::ARM::Network::Models::IPAllocationMethod::Static
179
- else
180
- Fog::ARM::Network::Models::IPAllocationMethod::Dynamic
181
- end
182
- if pip_alloc.present?
183
- pip = azure_network_service.public_ips.create(
184
- name: "#{args[:vm_name]}-pip#{nic}",
185
- resource_group: args[:resource_group],
186
- location: formatted_location,
187
- public_ip_allocation_method: pip_alloc
188
- )
189
- end
190
- new_nic = azure_network_service.network_interfaces.create(
191
- name: "#{args[:vm_name]}-nic#{nic}",
192
- resource_group: args[:resource_group],
193
- location: formatted_location,
194
- subnet_id: attrs[:network],
195
- public_ip_address_id: pip.present? ? pip.id : nil,
196
- ip_configuration_name: 'ForemanIPConfiguration',
197
- private_ip_allocation_method: priv_ip_alloc
198
- )
199
- nics << new_nic
200
- end
201
- nics
185
+ # user data support
186
+ def user_data_supported?
187
+ true
202
188
  end
203
189
 
204
- # Preferred behavior is to utilize Fog but Fog Azure RM
205
- # does not currently support creating managed VMs
206
190
  def create_vm(args = {})
207
- args[:vm_name] = args[:name].split('.')[0]
208
- nics = create_nics(args)
209
- if args[:ssh_key_data].present?
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]}\""
199
+ else
200
+ args[:azure_vm][:script_command] = sudoers_cmd
201
+ end
202
+ disable_password_auth = false
203
+ elsif args[:azure_vm][:ssh_key_data].present? && !args[:azure_vm][:password].present?
210
204
  disable_password_auth = true
211
- ssh_key_path = "/home/#{args[:username]}/.ssh/authorized_keys"
212
205
  else
213
206
  disable_password_auth = false
214
- ssh_key_path = nil
215
207
  end
216
- vm = client.create_managed_virtual_machine(
217
- name: args[:vm_name],
218
- location: args[:location],
219
- resource_group: args[:resource_group],
220
- vm_size: args[:vm_size],
221
- username: args[:username],
222
- password: args[:password],
223
- ssh_key_data: args[:ssh_key_data],
224
- ssh_key_path: ssh_key_path,
225
- disable_password_authentication: disable_password_auth,
226
- network_interface_card_ids: nics.map(&:id),
227
- platform: args[:platform],
228
- vhd_path: args[:image_id],
229
- os_disk_caching: args[:os_disk_caching],
230
- data_disks: args[:volumes_attributes],
231
- os_disk_size: args[:os_disk_size],
232
- premium_os_disk: args[:premium_os_disk],
208
+ 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],
216
+ disable_password_authentication: disable_password_auth,
217
+ network_interface_card_ids: nics.map(&:id),
218
+ platform: args[:azure_vm][:platform],
219
+ 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],
222
+ custom_data: args[:user_data],
223
+ script_command: args[:azure_vm][:script_command],
224
+ script_uris: args[:azure_vm][:script_uris],
233
225
  )
234
- vm_hash = Fog::Compute::AzureRM::Server.parse(vm)
235
- vm_hash[:password] = args[:password]
236
- vm_hash[:platform] = args[:platform]
237
- vm_hash[:puppet_master] = args[:puppet_master]
238
- vm_hash[:script_command] = args[:script_command]
239
- vm_hash[:script_uris] = args[:script_uris]
240
- client.create_vm_extension(vm_hash)
241
- client.servers.new vm_hash
242
- # fog-azure-rm raises all ARM errors as RuntimeError
243
- rescue Fog::Errors::Error, RuntimeError => e
226
+ create_vm_extension(args)
227
+ # return the vm object using azure_vm
228
+ return_vm = AzureRMCompute.new(azure_vm: vm, sdk: sdk)
229
+ rescue RuntimeError => e
244
230
  Foreman::Logging.exception('Unhandled Azure RM error', e)
245
231
  destroy_vm vm.id if vm
246
232
  raise e
247
233
  end
248
234
 
249
235
  def destroy_vm(uuid)
236
+ #vm.azure_vm because that's the azure object and vm is the wrapper
250
237
  vm = find_vm_by_uuid(uuid)
251
- raw_model = client.get_virtual_machine(vm.resource_group, vm.name)
252
- os_disk_name = raw_model.storage_profile.os_disk.name
253
- data_disks = raw_model.storage_profile.data_disks
238
+ vm_name = vm.name
239
+ rg_name = vm.azure_vm.resource_group
240
+ os_disk = vm.azure_vm.storage_profile.os_disk
241
+ data_disks = vm.azure_vm.storage_profile.data_disks
254
242
  nic_ids = vm.network_interface_card_ids
255
- # In ARM things must be deleted in order
256
- vm.destroy
257
- nic_ids.each do |id|
258
- nic = azure_network_service.network_interfaces.get(id.split('/')[4],
259
- id.split('/')[-1])
260
- ip_id = nic.public_ip_address_id
261
- nic.destroy
262
- if ip_id.present?
263
- azure_network_service.public_ips.get(ip_id.split('/')[4],
264
- ip_id.split('/')[-1]).destroy
243
+
244
+ sdk.delete_vm(rg_name, vm_name)
245
+
246
+ nic_ids.each do |nic_id|
247
+ nic = sdk.vm_nic(rg_name, nic_id.split('/')[-1])
248
+ if nic.present?
249
+ public_ip = nic.ip_configurations.first.public_ipaddress
250
+ sdk.delete_nic(rg_name, nic_id.split('/')[-1])
251
+ if public_ip.present?
252
+ ip_id = public_ip.id
253
+ sdk.delete_pip(rg_name, ip_id.split('/')[-1])
254
+ end
265
255
  end
266
256
  end
267
- client.managed_disks.get(vm.resource_group, os_disk_name).destroy
268
- data_disks.each do |disk|
269
- client.managed_disks.get(vm.resource_group, disk.name).destroy
257
+ if os_disk.present?
258
+ sdk.delete_disk(rg_name, os_disk.name)
270
259
  end
271
260
 
261
+ true
272
262
  rescue ActiveRecord::RecordNotFound
273
- # If the VM does not exist, we don't really care.
263
+ logger.info "Could not find the selected vm."
274
264
  true
275
265
  end
276
-
277
- protected
278
-
279
- def client
280
- @client ||= Fog::Compute.new(
281
- :provider => 'AzureRM',
282
- :tenant_id => tenant,
283
- :client_id => app_ident,
284
- :client_secret => secret_key,
285
- :subscription_id => sub_id,
286
- :environment => 'AzureCloud'
287
- )
288
- end
289
-
290
- def rg_client
291
- # noinspection RubyArgCount
292
- @rg_client ||= Fog::Resources::AzureRM.new(
293
- tenant_id: tenant,
294
- client_id: app_ident,
295
- client_secret: secret_key,
296
- subscription_id: sub_id,
297
- :environment => 'AzureCloud'
298
- )
299
- end
300
-
301
- def storage_client
302
- @storage_client ||= Fog::Storage.new(
303
- :provider => 'AzureRM',
304
- :tenant_id => tenant,
305
- :client_id => app_ident,
306
- :client_secret => secret_key,
307
- :subscription_id => sub_id,
308
- :environment => 'AzureCloud'
309
- )
310
- end
311
-
312
- def azure_network_service
313
- # noinspection RubyArgCount
314
- @azure_network_service ||= Fog::Network::AzureRM.new(
315
- :tenant_id => tenant,
316
- :client_id => app_ident,
317
- :client_secret => secret_key,
318
- :subscription_id => sub_id,
319
- :environment => 'AzureCloud'
320
- )
321
- end
322
266
  end
323
- end
267
+ end