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.
- 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
|