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.
- checksums.yaml +4 -4
- data/Dockerfile +10 -2
- data/bin/mu-adopt +5 -1
- data/bin/mu-load-config.rb +2 -3
- data/bin/mu-run-tests +112 -27
- data/cloud-mu.gemspec +20 -20
- data/cookbooks/mu-tools/libraries/helper.rb +2 -1
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +5 -15
- data/modules/mu.rb +10 -14
- data/modules/mu/adoption.rb +20 -14
- data/modules/mu/cleanup.rb +13 -9
- data/modules/mu/cloud.rb +26 -26
- data/modules/mu/clouds/aws.rb +100 -59
- data/modules/mu/clouds/aws/alarm.rb +4 -2
- data/modules/mu/clouds/aws/bucket.rb +25 -21
- data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
- data/modules/mu/clouds/aws/collection.rb +21 -20
- data/modules/mu/clouds/aws/container_cluster.rb +47 -26
- data/modules/mu/clouds/aws/database.rb +57 -68
- data/modules/mu/clouds/aws/dnszone.rb +14 -14
- data/modules/mu/clouds/aws/endpoint.rb +20 -16
- data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
- data/modules/mu/clouds/aws/folder.rb +7 -7
- data/modules/mu/clouds/aws/function.rb +15 -12
- data/modules/mu/clouds/aws/group.rb +14 -10
- data/modules/mu/clouds/aws/habitat.rb +16 -13
- data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
- data/modules/mu/clouds/aws/log.rb +13 -10
- data/modules/mu/clouds/aws/msg_queue.rb +15 -8
- data/modules/mu/clouds/aws/nosqldb.rb +18 -11
- data/modules/mu/clouds/aws/notifier.rb +11 -6
- data/modules/mu/clouds/aws/role.rb +87 -70
- data/modules/mu/clouds/aws/search_domain.rb +30 -19
- data/modules/mu/clouds/aws/server.rb +102 -72
- data/modules/mu/clouds/aws/server_pool.rb +47 -28
- data/modules/mu/clouds/aws/storage_pool.rb +5 -6
- data/modules/mu/clouds/aws/user.rb +13 -10
- data/modules/mu/clouds/aws/vpc.rb +135 -121
- data/modules/mu/clouds/azure.rb +16 -9
- data/modules/mu/clouds/azure/container_cluster.rb +2 -3
- data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
- data/modules/mu/clouds/azure/habitat.rb +8 -6
- data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
- data/modules/mu/clouds/azure/role.rb +8 -10
- data/modules/mu/clouds/azure/server.rb +65 -25
- data/modules/mu/clouds/azure/user.rb +5 -7
- data/modules/mu/clouds/azure/vpc.rb +12 -15
- data/modules/mu/clouds/cloudformation.rb +8 -7
- data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
- data/modules/mu/clouds/google.rb +39 -24
- data/modules/mu/clouds/google/bucket.rb +9 -11
- data/modules/mu/clouds/google/container_cluster.rb +27 -42
- data/modules/mu/clouds/google/database.rb +6 -9
- data/modules/mu/clouds/google/firewall_rule.rb +11 -10
- data/modules/mu/clouds/google/folder.rb +16 -9
- data/modules/mu/clouds/google/function.rb +127 -161
- data/modules/mu/clouds/google/group.rb +21 -18
- data/modules/mu/clouds/google/habitat.rb +18 -15
- data/modules/mu/clouds/google/loadbalancer.rb +14 -16
- data/modules/mu/clouds/google/role.rb +48 -31
- data/modules/mu/clouds/google/server.rb +105 -105
- data/modules/mu/clouds/google/server_pool.rb +12 -31
- data/modules/mu/clouds/google/user.rb +67 -13
- data/modules/mu/clouds/google/vpc.rb +58 -65
- data/modules/mu/config.rb +89 -1738
- data/modules/mu/config/bucket.rb +3 -3
- data/modules/mu/config/collection.rb +3 -3
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/dnszone.rb +5 -5
- data/modules/mu/config/doc_helpers.rb +517 -0
- data/modules/mu/config/endpoint.rb +3 -3
- data/modules/mu/config/firewall_rule.rb +118 -3
- data/modules/mu/config/folder.rb +3 -3
- data/modules/mu/config/function.rb +2 -2
- data/modules/mu/config/group.rb +3 -3
- data/modules/mu/config/habitat.rb +3 -3
- data/modules/mu/config/loadbalancer.rb +3 -3
- data/modules/mu/config/log.rb +3 -3
- data/modules/mu/config/msg_queue.rb +3 -3
- data/modules/mu/config/nosqldb.rb +3 -3
- data/modules/mu/config/notifier.rb +2 -2
- data/modules/mu/config/ref.rb +333 -0
- data/modules/mu/config/role.rb +3 -3
- data/modules/mu/config/schema_helpers.rb +508 -0
- data/modules/mu/config/search_domain.rb +3 -3
- data/modules/mu/config/server.rb +86 -58
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/tail.rb +189 -0
- data/modules/mu/config/user.rb +3 -3
- data/modules/mu/config/vpc.rb +44 -4
- data/modules/mu/defaults/Google.yaml +2 -2
- data/modules/mu/deploy.rb +13 -10
- data/modules/mu/groomer.rb +1 -1
- data/modules/mu/groomers/ansible.rb +69 -24
- data/modules/mu/groomers/chef.rb +52 -44
- data/modules/mu/logger.rb +17 -14
- data/modules/mu/master.rb +317 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -2
- data/modules/mu/mommacat.rb +85 -1766
- data/modules/mu/mommacat/daemon.rb +394 -0
- data/modules/mu/mommacat/naming.rb +366 -0
- data/modules/mu/mommacat/storage.rb +689 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- metadata +112 -102
data/modules/mu/clouds/azure.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
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! { |
|
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
|
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
|
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
|
-
|
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
|
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(
|
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
|
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(
|
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
|
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(
|
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(
|
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
|
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(
|
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
|
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,
|
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
|
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(
|
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
|
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,
|
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 { |
|
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
|
69
|
-
def assignTo(
|
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
|
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].
|
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
|
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(
|
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
|
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,
|
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
|
-
|
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
|
-
|
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'] = "
|
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
|
-
|
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
|
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,
|
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
|
-
|
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.
|
628
|
-
|
629
|
-
|
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
|
-
|
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
|
815
|
+
rescue StandardError => e
|
776
816
|
MU.log e.message, MU::ERR
|
777
817
|
vm_obj.plan = nil
|
778
818
|
end
|