cloud-mu 3.1.3 → 3.1.4

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.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +10 -2
  3. data/bin/mu-adopt +5 -1
  4. data/bin/mu-load-config.rb +2 -3
  5. data/bin/mu-run-tests +112 -27
  6. data/cloud-mu.gemspec +20 -20
  7. data/cookbooks/mu-tools/libraries/helper.rb +2 -1
  8. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  9. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  10. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  11. data/extras/image-generators/Google/centos6.yaml +1 -0
  12. data/extras/image-generators/Google/centos7.yaml +1 -1
  13. data/modules/mommacat.ru +5 -15
  14. data/modules/mu.rb +10 -14
  15. data/modules/mu/adoption.rb +20 -14
  16. data/modules/mu/cleanup.rb +13 -9
  17. data/modules/mu/cloud.rb +26 -26
  18. data/modules/mu/clouds/aws.rb +100 -59
  19. data/modules/mu/clouds/aws/alarm.rb +4 -2
  20. data/modules/mu/clouds/aws/bucket.rb +25 -21
  21. data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
  22. data/modules/mu/clouds/aws/collection.rb +21 -20
  23. data/modules/mu/clouds/aws/container_cluster.rb +47 -26
  24. data/modules/mu/clouds/aws/database.rb +57 -68
  25. data/modules/mu/clouds/aws/dnszone.rb +14 -14
  26. data/modules/mu/clouds/aws/endpoint.rb +20 -16
  27. data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
  28. data/modules/mu/clouds/aws/folder.rb +7 -7
  29. data/modules/mu/clouds/aws/function.rb +15 -12
  30. data/modules/mu/clouds/aws/group.rb +14 -10
  31. data/modules/mu/clouds/aws/habitat.rb +16 -13
  32. data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
  33. data/modules/mu/clouds/aws/log.rb +13 -10
  34. data/modules/mu/clouds/aws/msg_queue.rb +15 -8
  35. data/modules/mu/clouds/aws/nosqldb.rb +18 -11
  36. data/modules/mu/clouds/aws/notifier.rb +11 -6
  37. data/modules/mu/clouds/aws/role.rb +87 -70
  38. data/modules/mu/clouds/aws/search_domain.rb +30 -19
  39. data/modules/mu/clouds/aws/server.rb +102 -72
  40. data/modules/mu/clouds/aws/server_pool.rb +47 -28
  41. data/modules/mu/clouds/aws/storage_pool.rb +5 -6
  42. data/modules/mu/clouds/aws/user.rb +13 -10
  43. data/modules/mu/clouds/aws/vpc.rb +135 -121
  44. data/modules/mu/clouds/azure.rb +16 -9
  45. data/modules/mu/clouds/azure/container_cluster.rb +2 -3
  46. data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
  47. data/modules/mu/clouds/azure/habitat.rb +8 -6
  48. data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
  49. data/modules/mu/clouds/azure/role.rb +8 -10
  50. data/modules/mu/clouds/azure/server.rb +65 -25
  51. data/modules/mu/clouds/azure/user.rb +5 -7
  52. data/modules/mu/clouds/azure/vpc.rb +12 -15
  53. data/modules/mu/clouds/cloudformation.rb +8 -7
  54. data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
  55. data/modules/mu/clouds/google.rb +39 -24
  56. data/modules/mu/clouds/google/bucket.rb +9 -11
  57. data/modules/mu/clouds/google/container_cluster.rb +27 -42
  58. data/modules/mu/clouds/google/database.rb +6 -9
  59. data/modules/mu/clouds/google/firewall_rule.rb +11 -10
  60. data/modules/mu/clouds/google/folder.rb +16 -9
  61. data/modules/mu/clouds/google/function.rb +127 -161
  62. data/modules/mu/clouds/google/group.rb +21 -18
  63. data/modules/mu/clouds/google/habitat.rb +18 -15
  64. data/modules/mu/clouds/google/loadbalancer.rb +14 -16
  65. data/modules/mu/clouds/google/role.rb +48 -31
  66. data/modules/mu/clouds/google/server.rb +105 -105
  67. data/modules/mu/clouds/google/server_pool.rb +12 -31
  68. data/modules/mu/clouds/google/user.rb +67 -13
  69. data/modules/mu/clouds/google/vpc.rb +58 -65
  70. data/modules/mu/config.rb +89 -1738
  71. data/modules/mu/config/bucket.rb +3 -3
  72. data/modules/mu/config/collection.rb +3 -3
  73. data/modules/mu/config/container_cluster.rb +2 -2
  74. data/modules/mu/config/dnszone.rb +5 -5
  75. data/modules/mu/config/doc_helpers.rb +517 -0
  76. data/modules/mu/config/endpoint.rb +3 -3
  77. data/modules/mu/config/firewall_rule.rb +118 -3
  78. data/modules/mu/config/folder.rb +3 -3
  79. data/modules/mu/config/function.rb +2 -2
  80. data/modules/mu/config/group.rb +3 -3
  81. data/modules/mu/config/habitat.rb +3 -3
  82. data/modules/mu/config/loadbalancer.rb +3 -3
  83. data/modules/mu/config/log.rb +3 -3
  84. data/modules/mu/config/msg_queue.rb +3 -3
  85. data/modules/mu/config/nosqldb.rb +3 -3
  86. data/modules/mu/config/notifier.rb +2 -2
  87. data/modules/mu/config/ref.rb +333 -0
  88. data/modules/mu/config/role.rb +3 -3
  89. data/modules/mu/config/schema_helpers.rb +508 -0
  90. data/modules/mu/config/search_domain.rb +3 -3
  91. data/modules/mu/config/server.rb +86 -58
  92. data/modules/mu/config/server_pool.rb +2 -2
  93. data/modules/mu/config/tail.rb +189 -0
  94. data/modules/mu/config/user.rb +3 -3
  95. data/modules/mu/config/vpc.rb +44 -4
  96. data/modules/mu/defaults/Google.yaml +2 -2
  97. data/modules/mu/deploy.rb +13 -10
  98. data/modules/mu/groomer.rb +1 -1
  99. data/modules/mu/groomers/ansible.rb +69 -24
  100. data/modules/mu/groomers/chef.rb +52 -44
  101. data/modules/mu/logger.rb +17 -14
  102. data/modules/mu/master.rb +317 -2
  103. data/modules/mu/master/chef.rb +3 -4
  104. data/modules/mu/master/ldap.rb +3 -3
  105. data/modules/mu/master/ssl.rb +12 -2
  106. data/modules/mu/mommacat.rb +85 -1766
  107. data/modules/mu/mommacat/daemon.rb +394 -0
  108. data/modules/mu/mommacat/naming.rb +366 -0
  109. data/modules/mu/mommacat/storage.rb +689 -0
  110. data/modules/tests/bucket.yml +4 -0
  111. data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
  112. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  113. data/modules/tests/regrooms/bucket.yml +19 -0
  114. metadata +112 -102
@@ -101,11 +101,11 @@ module MU
101
101
  def initialize(*args)
102
102
  if args.first.is_a?(String)
103
103
  @raw = args.first
104
- junk, junk, @subscription, junk, @resource_group, junk, @provider, @resource_type, @name = @raw.split(/\//)
104
+ _junk, _junk2, @subscription, _junk3, @resource_group, _junk4, @provider, @resource_type, @name = @raw.split(/\//)
105
105
  if @subscription.nil? or @resource_group.nil? or @provider.nil? or @resource_type.nil? or @name.nil?
106
106
  # Not everything has a resource group
107
107
  if @raw.match(/^\/subscriptions\/#{Regexp.quote(@subscription)}\/providers/)
108
- junk, junk, @subscription, junk, @provider, @resource_type, @name = @raw.split(/\//)
108
+ _junk, _junk2, @subscription, _junk3, @provider, @resource_type, @name = @raw.split(/\//)
109
109
  if @subscription.nil? or @provider.nil? or @resource_type.nil? or @name.nil?
110
110
  raise MuError, "Failed to parse Azure resource id string #{@raw} (got subscription: #{@subscription}, provider: #{@provider}, resource_type: #{@resource_type}, name: #{@name}"
111
111
  end
@@ -266,7 +266,7 @@ module MU
266
266
 
267
267
  begin
268
268
  sdk_response = MU::Cloud::Azure.subs(credentials: credentials).subscriptions().list_locations(subscription)
269
- rescue Exception => e
269
+ rescue StandardError => e
270
270
  MU.log e.inspect, MU::ERR, details: e.backtrace
271
271
  #pp "Error Getting the list of regions from Azure" #TODO: SWITCH THIS TO MU LOG
272
272
  if @@regions and @@regions.size > 0
@@ -378,7 +378,7 @@ module MU
378
378
  rg_obj = MU::Cloud::Azure.resources(:ResourceGroup).new
379
379
  rg_obj.location = region
380
380
  rg_obj.tags = MU::MommaCat.listStandardTags
381
- rg_obj.tags.reject! { |k, v| v.nil? }
381
+ rg_obj.tags.reject! { |_k, v| v.nil? }
382
382
 
383
383
  MU::Cloud::Azure.resources(credentials: credentials).resource_groups.list.each { |rg|
384
384
  if rg.name == name and rg.location == region and rg.tags == rg_obj.tags
@@ -519,7 +519,7 @@ module MU
519
519
  end
520
520
  return @@metadata
521
521
 
522
- rescue Timeout::Error => e
522
+ rescue Timeout::Error
523
523
  # MU.log "Timeout querying Azure Metadata"
524
524
  return nil
525
525
  rescue
@@ -906,7 +906,6 @@ module MU
906
906
  # END SDK STUBS
907
907
 
908
908
  # BEGIN SDK CLIENT
909
- private
910
909
 
911
910
  @@authorization_api = {}
912
911
  @@subscriptions_api = {}
@@ -967,7 +966,7 @@ module MU
967
966
  begin
968
967
  modelpath = "::Azure::#{api}::Mgmt::#{profile}::#{@subclass}"
969
968
  @api = Object.const_get(modelpath).new(@cred_obj)
970
- rescue NameError => e
969
+ rescue NameError
971
970
  raise MuError, "Unable to locate a profile #{profile} of Azure API #{api}. I tried:\n#{stdpath}\n#{modelpath}"
972
971
  end
973
972
  end
@@ -1017,6 +1016,7 @@ module MU
1017
1016
  # @param arguments [Array]
1018
1017
  def method_missing(method_sym, *arguments)
1019
1018
  MU.log "Calling #{@parentname}.#{@myname}.#{method_sym.to_s}", MU::DEBUG, details: arguments
1019
+ retries = 0
1020
1020
  begin
1021
1021
  if !arguments.nil? and arguments.size == 1
1022
1022
  retval = @myobject.method(method_sym).call(arguments[0])
@@ -1025,9 +1025,16 @@ module MU
1025
1025
  else
1026
1026
  retval = @myobject.method(method_sym).call
1027
1027
  end
1028
- rescue ::Net::ReadTimeout, ::Faraday::TimeoutError => e
1028
+ rescue ::Net::ReadTimeout, ::Faraday::TimeoutError, ::Faraday::ConnectionFailed => e
1029
1029
  sleep 5
1030
- retry
1030
+ if retries < 12
1031
+ MU.log e.message+" calling #{@parentname}.#{@myname}.#{method_sym.to_s}(#{arguments.map { |a| a.to_s }.join(", ")})", MU::DEBUG, details: caller
1032
+ retries += 1
1033
+ retry
1034
+ else
1035
+ MU.log e.message+" calling #{@parentname}.#{@myname}.#{method_sym.to_s}(#{arguments.map { |a| a.to_s }.join(", ")})", MU::ERR, details: caller
1036
+ raise e
1037
+ end
1031
1038
  rescue ::MsRestAzure::AzureOperationError, ::MsRest::HttpOperationError => e
1032
1039
  MU.log "Error calling #{@parent.api.class.name}.#{@myname}.#{method_sym.to_s}", MU::DEBUG, details: arguments
1033
1040
  begin
@@ -119,7 +119,6 @@ module MU
119
119
 
120
120
  # Register a description of this cluster instance with this deployment's metadata.
121
121
  def notify
122
- base = {}
123
122
  base = MU.structToHash(cloud_desc)
124
123
  base["cloud_id"] = @cloud_id.name
125
124
  base.merge!(@config.to_h)
@@ -146,9 +145,9 @@ module MU
146
145
  end
147
146
 
148
147
  # Cloud-specific configuration properties.
149
- # @param config [MU::Config]: The calling MU::Config object
148
+ # @param _config [MU::Config]: The calling MU::Config object
150
149
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
151
- def self.schema(config)
150
+ def self.schema(_config)
152
151
  toplevel_required = []
153
152
  schema = {
154
153
  "flavor" => {
@@ -53,7 +53,7 @@ module MU
53
53
  oldrules[rule.name] = rule
54
54
  end
55
55
  }
56
- used_priorities = oldrules.values.map { |r| r.priority }
56
+ # used_priorities = oldrules.values.map { |r| r.priority }
57
57
 
58
58
  newrules_semaphore = Mutex.new
59
59
  num_rules = 0
@@ -136,12 +136,12 @@ module MU
136
136
  }
137
137
  end
138
138
 
139
- resolved_lbs = []
140
- if lbs
141
- lbs.each { |lb|
139
+ # resolved_lbs = []
140
+ # if lbs
141
+ # lbs.each { |lb|
142
142
  # TODO awaiting LoadBalancer implementation
143
- }
144
- end
143
+ # }
144
+ # end
145
145
 
146
146
  if egress
147
147
  rule_obj.direction = MU::Cloud::Azure.network(:SecurityRuleDirection)::Outbound
@@ -295,7 +295,7 @@ module MU
295
295
  resp = MU::Cloud::Azure.network(credentials: args[:credentials]).network_security_groups.get(rg, id_str)
296
296
  next if resp.nil?
297
297
  found[Id.new(resp.id)] = resp
298
- rescue MU::Cloud::Azure::APIError => e
298
+ rescue MU::Cloud::Azure::APIError
299
299
  # this is fine, we're doing a blind search after all
300
300
  end
301
301
  }
@@ -336,16 +336,16 @@ module MU
336
336
  # Reverse-map our cloud description into a runnable config hash.
337
337
  # We assume that any values we have in +@config+ are placeholders, and
338
338
  # calculate our own accordingly based on what's live in the cloud.
339
- def toKitten(rootparent: nil, billing: nil)
339
+ def toKitten(**args)
340
340
  bok = {}
341
341
 
342
342
  bok
343
343
  end
344
344
 
345
345
  # Cloud-specific configuration properties.
346
- # @param config [MU::Config]: The calling MU::Config object
346
+ # @param _config [MU::Config]: The calling MU::Config object
347
347
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
348
- def self.schema(config = nil)
348
+ def self.schema(_config = nil)
349
349
  toplevel_required = []
350
350
  hosts_schema = MU::Config::CIDR_PRIMITIVE
351
351
  hosts_schema["pattern"] = "^(\\d+\\.\\d+\\.\\d+\\.\\d+\/[0-9]{1,2}|\\*)$"
@@ -59,8 +59,10 @@ module MU
59
59
  def groom
60
60
  end
61
61
 
62
+ @cached_cloud_desc = nil
62
63
  # Return the cloud descriptor for the Habitat
63
- def cloud_desc
64
+ def cloud_desc(use_cache: true)
65
+ return @cached_cloud_desc if @cached_cloud_desc and use_cache
64
66
  @cached_cloud_desc ||= MU::Cloud::Azure::Habitat.find(cloud_id: @cloud_id).values.first
65
67
  # @habitat_id ||= @cached_cloud_desc.parent.id if @cached_cloud_desc
66
68
  @cached_cloud_desc
@@ -131,7 +133,7 @@ module MU
131
133
  # Reverse-map our cloud description into a runnable config hash.
132
134
  # We assume that any values we have in +@config+ are placeholders, and
133
135
  # calculate our own accordingly based on what's live in the cloud.
134
- def toKitten(rootparent: nil, billing: nil)
136
+ def toKitten(**args)
135
137
  bok = {
136
138
  "cloud" => "Azure",
137
139
  "credentials" => @config['credentials']
@@ -141,9 +143,9 @@ module MU
141
143
  end
142
144
 
143
145
  # Cloud-specific configuration properties.
144
- # @param config [MU::Config]: The calling MU::Config object
146
+ # @param _config [MU::Config]: The calling MU::Config object
145
147
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
146
- def self.schema(config)
148
+ def self.schema(_config)
147
149
  toplevel_required = []
148
150
  schema = {
149
151
  }
@@ -152,9 +154,9 @@ module MU
152
154
 
153
155
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::habitats}, bare and unvalidated.
154
156
  # @param habitat [Hash]: The resource to process and validate
155
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
157
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
156
158
  # @return [Boolean]: True if validation succeeded, False otherwise
157
- def self.validateConfig(habitat, configurator)
159
+ def self.validateConfig(habitat, _configurator)
158
160
  ok = true
159
161
  habitat['region'] ||= MU::Cloud::Azure.myRegion(habitat['credentials'])
160
162
 
@@ -74,9 +74,9 @@ module MU
74
74
  end
75
75
 
76
76
  # Cloud-specific configuration properties.
77
- # @param config [MU::Config]: The calling MU::Config object
77
+ # @param _config [MU::Config]: The calling MU::Config object
78
78
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
79
- def self.schema(config)
79
+ def self.schema(_config)
80
80
  toplevel_required = []
81
81
  schema = {
82
82
  # "named_ports" => {
@@ -102,9 +102,9 @@ module MU
102
102
 
103
103
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::loadbalancers}, bare and unvalidated.
104
104
  # @param lb [Hash]: The resource to process and validate
105
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
105
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
106
106
  # @return [Boolean]: True if validation succeeded, False otherwise
107
- def self.validateConfig(lb, configurator)
107
+ def self.validateConfig(lb, _configurator)
108
108
  ok = true
109
109
  lb['region'] ||= MU::Cloud::Azure.myRegion(lb['credentials'])
110
110
 
@@ -144,7 +144,7 @@ module MU
144
144
  found[Id.new(lb.id)] = lb
145
145
  }
146
146
  else
147
- MU::Cloud::Azure.network(credentials: args[:credentials]).load_balancers.list_all.each { |net|
147
+ MU::Cloud::Azure.network(credentials: args[:credentials]).load_balancers.list_all.each { |lb|
148
148
  found[Id.new(lb.id)] = lb
149
149
  }
150
150
  end
@@ -65,8 +65,8 @@ module MU
65
65
  end
66
66
 
67
67
  # Assign this role object to a given principal (create a RoleAssignment)
68
- # @param principal [MU::Cloud::Azure::Id]
69
- def assignTo(principal)
68
+ # @param principal_id [MU::Cloud::Azure::Id]
69
+ def assignTo(principal_id)
70
70
  MU::Cloud::Azure::Role.assignTo(principal_id, role_id: @cloud_id)
71
71
  end
72
72
 
@@ -145,7 +145,7 @@ module MU
145
145
  begin
146
146
  resp = MU::Cloud::Azure.authorization(credentials: args[:credentials]).role_definitions.get(scope, id_str)
147
147
  found[Id.new(resp.id)] = resp
148
- rescue MsRestAzure::AzureOperationError => e
148
+ rescue MsRestAzure::AzureOperationError
149
149
  # this is fine, we're doing a blind search after all
150
150
  end
151
151
  else
@@ -155,7 +155,7 @@ module MU
155
155
  end
156
156
  }
157
157
  if args[:role_name]
158
- @@role_list_cache[scope].each_pair { |key, role|
158
+ @@role_list_cache[scope].values.each { |role|
159
159
  begin
160
160
  if role.role_name == args[:role_name]
161
161
  found[Id.new(role.id)] = role
@@ -183,9 +183,9 @@ module MU
183
183
  end
184
184
 
185
185
  # Cloud-specific configuration properties.
186
- # @param config [MU::Config]: The calling MU::Config object
186
+ # @param _config [MU::Config]: The calling MU::Config object
187
187
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
188
- def self.schema(config)
188
+ def self.schema(_config)
189
189
  toplevel_required = []
190
190
  schema = {
191
191
  }
@@ -194,17 +194,15 @@ module MU
194
194
 
195
195
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::roles}, bare and unvalidated.
196
196
  # @param role [Hash]: The resource to process and validate
197
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
197
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
198
198
  # @return [Boolean]: True if validation succeeded, False otherwise
199
- def self.validateConfig(role, configurator)
199
+ def self.validateConfig(role, _configurator)
200
200
  ok = true
201
201
  role['region'] ||= MU::Cloud::Azure.myRegion(role['credentials'])
202
202
 
203
203
  ok
204
204
  end
205
205
 
206
- private
207
-
208
206
  end
209
207
  end
210
208
  end
@@ -139,7 +139,7 @@ module MU
139
139
  # Figure out what's needed to SSH into this server.
140
140
  # @return [Array<String>]: nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name, alternate_names
141
141
  def getSSHConfig
142
- node, config, deploydata = describe(cloud_id: @cloud_id)
142
+ describe(cloud_id: @cloud_id)
143
143
  # XXX add some awesome alternate names from metadata and make sure they end
144
144
  # up in MU::MommaCat's ssh config wangling
145
145
  ssh_keydir = Etc.getpwuid(Process.uid).dir+"/.ssh"
@@ -153,7 +153,7 @@ module MU
153
153
  MU.log "NAT was missing cloud descriptor when called in #{@mu_name}'s getSSHConfig", MU::ERR
154
154
  return nil
155
155
  end
156
- foo, bar, baz, nat_ssh_host, nat_ssh_user, nat_ssh_key = @nat.getSSHConfig
156
+ _foo, _bar, _baz, nat_ssh_host, nat_ssh_user, nat_ssh_key = @nat.getSSHConfig
157
157
  if nat_ssh_user.nil? and !nat_ssh_host.nil?
158
158
  MU.log "#{@config["name"]} (#{MU.deploy_id}) is configured to use #{@config['vpc']} NAT #{nat_ssh_host}, but username isn't specified. Guessing root.", MU::ERR, details: caller
159
159
  nat_ssh_user = "root"
@@ -163,7 +163,7 @@ module MU
163
163
 
164
164
  if @config['ssh_user'].nil?
165
165
  if windows?
166
- @config['ssh_user'] = "Administrator"
166
+ @config['ssh_user'] = "muadmin"
167
167
  else
168
168
  @config['ssh_user'] = "root"
169
169
  end
@@ -188,7 +188,7 @@ module MU
188
188
  @named = true
189
189
  end
190
190
 
191
- nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
191
+ _nat_ssh_key, _nat_ssh_user, nat_ssh_host, _canonical_ip, _ssh_user, _ssh_key_name = getSSHConfig
192
192
  if !nat_ssh_host and !MU::Cloud::Azure::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
193
193
  # XXX check if canonical_ip is in the private ranges
194
194
  # raise MuError, "#{node} has no NAT host configured, and I have no other route to it"
@@ -236,7 +236,7 @@ module MU
236
236
  resp = MU::Cloud::Azure.compute(credentials: args[:credentials]).virtual_machines.get(rg, id_str)
237
237
  next if resp.nil?
238
238
  found[Id.new(resp.id)] = resp
239
- rescue MU::Cloud::Azure::APIError => e
239
+ rescue MU::Cloud::Azure::APIError
240
240
  # this is fine, we're doing a blind search after all
241
241
  end
242
242
  }
@@ -267,7 +267,7 @@ module MU
267
267
 
268
268
  MU::MommaCat.lock(@cloud_id.to_s+"-groom")
269
269
 
270
- node, config, deploydata = describe(cloud_id: @cloud_id)
270
+ node, _config, deploydata = describe(cloud_id: @cloud_id)
271
271
 
272
272
  if node.nil? or node.empty?
273
273
  raise MuError, "MU::Cloud::Azure::Server.groom was called without a mu_name"
@@ -357,7 +357,7 @@ module MU
357
357
  # bastion hosts that may be in the path, see getSSHConfig if that's what
358
358
  # you need.
359
359
  def canonicalIP
360
- mu_name, config, deploydata = describe(cloud_id: @cloud_id)
360
+ describe(cloud_id: @cloud_id)
361
361
 
362
362
  if !cloud_desc
363
363
  raise MuError, "Couldn't retrieve cloud descriptor for server #{self}"
@@ -451,6 +451,34 @@ module MU
451
451
  }
452
452
  }
453
453
  }
454
+ },
455
+ "windows_admin_username" => {
456
+ "type" => "string",
457
+ "default" => "muadmin",
458
+ },
459
+ "ssh_user" => {
460
+ "default_if" => [
461
+ {
462
+ "key_is" => "platform",
463
+ "value_is" => "windows",
464
+ "set" => "muadmin"
465
+ },
466
+ {
467
+ "key_is" => "platform",
468
+ "value_is" => "win2k12",
469
+ "set" => "muadmin"
470
+ },
471
+ {
472
+ "key_is" => "platform",
473
+ "value_is" => "win2k12r2",
474
+ "set" => "muadmin"
475
+ },
476
+ {
477
+ "key_is" => "platform",
478
+ "value_is" => "win2k16",
479
+ "set" => "muadmin"
480
+ }
481
+ ]
454
482
  }
455
483
  }
456
484
  [toplevel_required, schema]
@@ -479,6 +507,7 @@ module MU
479
507
  mem = foreign_types[size]["memory"]
480
508
  ecu = foreign_types[size]["ecu"]
481
509
  types.keys.sort.reverse.each { |type|
510
+ next if type.match(/_Promo$/i)
482
511
  features = types[type]
483
512
  next if ecu == "Variable" and ecu != features["ecu"]
484
513
  next if features["vcpu"] != vcpu
@@ -495,7 +524,6 @@ module MU
495
524
 
496
525
  if !foundmatch
497
526
  MU.log "Invalid size '#{size}' for Azure Compute instance in #{region}. Supported types:", MU::ERR, details: types.keys.sort.join(", ")
498
- exit
499
527
  return nil
500
528
  end
501
529
  end
@@ -512,6 +540,10 @@ exit
512
540
 
513
541
  server['region'] ||= MU::Cloud::Azure.myRegion(server['credentials'])
514
542
  server['ssh_user'] ||= "muadmin"
543
+ if server['windows_admin_username'] == "Administrator"
544
+ MU.log "Azure does not permit admin user to be 'Administrator'", MU::ERR
545
+ ok = false
546
+ end
515
547
 
516
548
  server['size'] = validateInstanceType(server["size"], server["region"])
517
549
  ok = false if server['size'].nil?
@@ -527,17 +559,17 @@ exit
527
559
  end
528
560
 
529
561
  image_desc = MU::Cloud::Azure::Server.fetchImage(server['image_id'].to_s, credentials: server['credentials'], region: server['region'])
530
- if image_desc.plan
531
- terms = MU::Cloud::Azure.marketplace(credentials: @credentials).marketplace_agreements.get(image_desc.plan.publisher, image_desc.plan.product, image_desc.plan.name)
532
- if !terms.accepted
533
- MU.log "Deploying #{server['name']} will automatically agree to the licensing terms for #{terms.product}", MU::NOTICE, details: terms.license_text_link
534
- end
535
- end
536
562
 
537
563
  if !image_desc
538
564
  MU.log "Failed to locate an Azure VM image for #{server['name']} from #{server['image_id']} in #{server['region']}", MU::ERR
539
565
  ok = false
540
566
  else
567
+ if image_desc.plan
568
+ terms = MU::Cloud::Azure.marketplace(credentials: @credentials).marketplace_agreements.get(image_desc.plan.publisher, image_desc.plan.product, image_desc.plan.name)
569
+ if !terms.accepted
570
+ MU.log "Deploying #{server['name']} will automatically agree to the licensing terms for #{terms.product}", MU::NOTICE, details: terms.license_text_link
571
+ end
572
+ end
541
573
  server['image_id'] = image_desc.id
542
574
  end
543
575
 
@@ -624,17 +656,22 @@ exit
624
656
  skus = MU::Cloud::Azure.compute(credentials: credentials).virtual_machine_images.list_skus(region, publisher, offer).map { |s| s.name }
625
657
 
626
658
  if !skus.include?(sku)
627
- skus.sort { |a, b| MU.version_sort(a, b) }.reverse.each { |s|
628
- if s.match(/^#{Regexp.quote(sku)}/)
629
- sku = s
630
- break
631
- end
632
- }
659
+ skus.reject! { |s| !s.match(/^#{Regexp.quote(sku)}/) }
660
+ skus.sort! { |a, b| MU.version_sort(a, b) }.reverse!
661
+ sku = skus.first
633
662
  end
634
663
 
635
- versions = MU::Cloud::Azure.compute(credentials: credentials).virtual_machine_images.list(region, publisher, offer, sku).map { |v| v.name }
664
+ version = nil
665
+ begin
666
+ versions = MU::Cloud::Azure.compute(credentials: credentials).virtual_machine_images.list(region, publisher, offer, sku).map { |v| v.name }
667
+ if versions.nil? or versions.empty?
668
+ skus.delete(sku)
669
+ sku = skus.first
670
+ end
671
+ end while skus.size > 0 and (versions.nil? or versions.empty?)
672
+
636
673
  if versions.nil? or versions.empty?
637
- MU.log "Azure API returned empty machine image version list for publisher #{publisher} offer #{offer} sku #{sku}", MU::ERR
674
+ MU.log "Azure API returned empty machine image version list for publisher #{publisher} offer #{offer} sku #{sku}", MU::ERR, details: skus
638
675
  return nil
639
676
  end
640
677
 
@@ -724,12 +761,15 @@ exit
724
761
  hw_obj.vm_size = @config['size']
725
762
 
726
763
  os_obj = MU::Cloud::Azure.compute(:OSProfile).new
727
- os_obj.admin_username = @config['ssh_user']
728
- os_obj.computer_name = @mu_name
729
764
  if windows?
730
765
  win_obj = MU::Cloud::Azure.compute(:WindowsConfiguration).new
731
766
  os_obj.windows_configuration = win_obj
767
+ os_obj.admin_username = @config['windows_admin_username']
768
+ os_obj.admin_password = MU.generateWindowsPassword
769
+ os_obj.computer_name = @deploy.getResourceName(@config["name"], max_length: 15, disallowed_chars: /[~!@#$%^&*()=+_\[\]{}\\\|;:\.'",<>\/\?]/)
732
770
  else
771
+ os_obj.admin_username = @config['ssh_user']
772
+ os_obj.computer_name = @mu_name
733
773
  key_obj = MU::Cloud::Azure.compute(:SshPublicKey).new
734
774
  key_obj.key_data = @deploy.ssh_public_key
735
775
  key_obj.path = "/home/#{@config['ssh_user']}/.ssh/authorized_keys"
@@ -772,7 +812,7 @@ exit
772
812
  begin
773
813
  # XXX this doesn't actually work as documented
774
814
  MU::Cloud::Azure.marketplace(credentials: @credentials).marketplace_agreements.sign(image_desc.plan.publisher, image_desc.plan.product, image_desc.plan.name)
775
- rescue Exception => e
815
+ rescue StandardError => e
776
816
  MU.log e.message, MU::ERR
777
817
  vm_obj.plan = nil
778
818
  end