cloud-mu 3.1.3 → 3.1.4

Sign up to get free protection for your applications and to get access to all the features.
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