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
|
@@ -86,7 +86,6 @@ module MU
|
|
|
86
86
|
|
|
87
87
|
client = ::MsRest::ServiceClient.new(cred_obj)
|
|
88
88
|
cloud_desc.client_secret_url.match(/^(http.*?\.azure\.net)(\/.*)/)
|
|
89
|
-
base = Regexp.last_match[1]
|
|
90
89
|
path = Regexp.last_match[2]
|
|
91
90
|
#MU.log "Calling into #{base} #{path}"
|
|
92
91
|
promise = client.make_request_async(
|
|
@@ -97,7 +96,7 @@ module MU
|
|
|
97
96
|
|
|
98
97
|
# XXX this is async, need to stop and wait somehow
|
|
99
98
|
promise.then do | result|
|
|
100
|
-
|
|
99
|
+
result.response
|
|
101
100
|
# MU.log "RESPONSE", MU::WARN, details: resp
|
|
102
101
|
end
|
|
103
102
|
end
|
|
@@ -106,7 +105,6 @@ module MU
|
|
|
106
105
|
|
|
107
106
|
# Called automatically by {MU::Deploy#createResources}
|
|
108
107
|
def groom
|
|
109
|
-
rgroup_name = @deploy.deploy_id+"-"+@config['region'].upcase
|
|
110
108
|
if @config['roles']
|
|
111
109
|
@config['roles'].each { |role|
|
|
112
110
|
MU::Cloud::Azure::Role.assignTo(cloud_desc.principal_id, role_name: role, credentials: @config['credentials'])
|
|
@@ -191,9 +189,9 @@ module MU
|
|
|
191
189
|
end
|
|
192
190
|
|
|
193
191
|
# Cloud-specific configuration properties.
|
|
194
|
-
# @param
|
|
192
|
+
# @param _config [MU::Config]: The calling MU::Config object
|
|
195
193
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
|
196
|
-
def self.schema(
|
|
194
|
+
def self.schema(_config)
|
|
197
195
|
toplevel_required = []
|
|
198
196
|
schema = {
|
|
199
197
|
"region" => MU::Config.region_primitive,
|
|
@@ -221,9 +219,9 @@ module MU
|
|
|
221
219
|
|
|
222
220
|
# Cloud-specific pre-processing of {MU::Config::BasketofKittens::users}, bare and unvalidated.
|
|
223
221
|
# @param user [Hash]: The resource to process and validate
|
|
224
|
-
# @param
|
|
222
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
225
223
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
226
|
-
def self.validateConfig(user,
|
|
224
|
+
def self.validateConfig(user, _configurator)
|
|
227
225
|
ok = true
|
|
228
226
|
user['region'] ||= MU::Cloud::Azure.myRegion(user['credentials'])
|
|
229
227
|
|
|
@@ -53,7 +53,6 @@ module MU
|
|
|
53
53
|
def groom
|
|
54
54
|
|
|
55
55
|
if @config['peers']
|
|
56
|
-
count = 0
|
|
57
56
|
@config['peers'].each { |peer|
|
|
58
57
|
if peer['vpc']['name']
|
|
59
58
|
peer_obj = @deploy.findLitterMate(name: peer['vpc']['name'], type: "vpcs", habitat: peer['vpc']['project'])
|
|
@@ -113,17 +112,16 @@ module MU
|
|
|
113
112
|
# Describe this VPC
|
|
114
113
|
# @return [Hash]
|
|
115
114
|
def notify
|
|
116
|
-
base = {}
|
|
117
115
|
base = MU.structToHash(cloud_desc)
|
|
118
116
|
base["cloud_id"] = @cloud_id.name
|
|
119
117
|
base.merge!(@config.to_h)
|
|
120
118
|
base
|
|
121
119
|
end
|
|
122
|
-
|
|
120
|
+
|
|
123
121
|
# Describe this VPC from the cloud platform's perspective
|
|
124
122
|
# @return [Hash]
|
|
125
|
-
def cloud_desc
|
|
126
|
-
if @cloud_desc_cache
|
|
123
|
+
def cloud_desc(use_cache: true)
|
|
124
|
+
if @cloud_desc_cache and use_cache
|
|
127
125
|
return @cloud_desc_cache
|
|
128
126
|
end
|
|
129
127
|
@cloud_desc_cache = MU::Cloud::Azure::VPC.find(cloud_id: @cloud_id, resource_group: @resource_group).values.first
|
|
@@ -192,10 +190,9 @@ module MU
|
|
|
192
190
|
# @param use_cache [Boolean]: If available, use saved deployment metadata to describe subnets, instead of querying the cloud API
|
|
193
191
|
# @return [Array<Hash>]: A list of cloud provider identifiers of subnets associated with this VPC.
|
|
194
192
|
def loadSubnets(use_cache: false)
|
|
195
|
-
desc = cloud_desc
|
|
196
193
|
@subnets = []
|
|
197
194
|
|
|
198
|
-
MU::Cloud::Azure.network(credentials: @credentials).subnets.list(@resource_group, cloud_desc.name).each { |subnet|
|
|
195
|
+
MU::Cloud::Azure.network(credentials: @credentials).subnets.list(@resource_group, cloud_desc(use_cache: use_cache).name).each { |subnet|
|
|
199
196
|
subnet_cfg = {
|
|
200
197
|
"cloud_id" => subnet.name,
|
|
201
198
|
"mu_name" => subnet.name,
|
|
@@ -334,7 +331,7 @@ module MU
|
|
|
334
331
|
# We assume that any values we have in +@config+ are placeholders, and
|
|
335
332
|
# calculate our own accordingly based on what's live in the cloud.
|
|
336
333
|
# XXX add flag to return the diff between @config and live cloud
|
|
337
|
-
def toKitten(
|
|
334
|
+
def toKitten(**_args)
|
|
338
335
|
return nil if cloud_desc.name == "default" # parent project builds these
|
|
339
336
|
bok = {
|
|
340
337
|
"cloud" => "Azure",
|
|
@@ -346,9 +343,9 @@ module MU
|
|
|
346
343
|
end
|
|
347
344
|
|
|
348
345
|
# Cloud-specific configuration properties.
|
|
349
|
-
# @param
|
|
346
|
+
# @param _config [MU::Config]: The calling MU::Config object
|
|
350
347
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
|
351
|
-
def self.schema(
|
|
348
|
+
def self.schema(_config = nil)
|
|
352
349
|
toplevel_required = []
|
|
353
350
|
schema = {
|
|
354
351
|
"peers" => {
|
|
@@ -522,7 +519,6 @@ MU.structToHash(ext_vpc).diff(MU.structToHash(vpc_obj))
|
|
|
522
519
|
# this is slow, so maybe thread it
|
|
523
520
|
rtb_map = {}
|
|
524
521
|
routethreads = []
|
|
525
|
-
create_nat_gateway = false
|
|
526
522
|
@config['route_tables'].each { |rtb_cfg|
|
|
527
523
|
routethreads << Thread.new(rtb_cfg) { |rtb|
|
|
528
524
|
rtb_name = @mu_name+"-"+rtb['name'].upcase
|
|
@@ -573,6 +569,9 @@ MU.structToHash(ext_vpc).diff(MU.structToHash(vpc_obj))
|
|
|
573
569
|
routename = rtb_name+"-"+route['destination_network'].gsub(/[^a-z0-9]/i, "_")
|
|
574
570
|
route_obj.next_hop_type = if route['gateway'] == "#NAT" and @config['bastion']
|
|
575
571
|
routename = rtb_name+"-NAT"
|
|
572
|
+
if @config['bastion'].is_a?(Hash) and !@config['bastion']['id'] and !@config['bastion']['deploy_id']
|
|
573
|
+
@config['bastion']['deploy_id'] = @deploy.deploy_id
|
|
574
|
+
end
|
|
576
575
|
bastion_ref = MU::Config::Ref.get(@config['bastion'])
|
|
577
576
|
if bastion_ref.kitten and bastion_ref.kitten.cloud_desc
|
|
578
577
|
iface_id = Id.new(bastion_ref.kitten.cloud_desc.network_profile.network_interfaces.first.id)
|
|
@@ -718,8 +717,6 @@ MU.structToHash(ext_subnet).diff(MU.structToHash(subnet_obj))
|
|
|
718
717
|
loadSubnets
|
|
719
718
|
end
|
|
720
719
|
|
|
721
|
-
protected
|
|
722
|
-
|
|
723
720
|
# Subnets are almost a first-class resource. So let's kinda sorta treat
|
|
724
721
|
# them like one. This should only be invoked on objects that already
|
|
725
722
|
# exists in the cloud layer.
|
|
@@ -772,8 +769,8 @@ MU.structToHash(ext_subnet).diff(MU.structToHash(subnet_obj))
|
|
|
772
769
|
end
|
|
773
770
|
|
|
774
771
|
# Describe this VPC Subnet from the cloud platform's perspective
|
|
775
|
-
def cloud_desc
|
|
776
|
-
return @cloud_desc_cache if
|
|
772
|
+
def cloud_desc(use_cache: true)
|
|
773
|
+
return @cloud_desc_cache if @cloud_desc_cache and use_cache
|
|
777
774
|
@cloud_desc_cache = MU::Cloud::Azure.network(credentials: @parent.credentials).subnets.get(@parent.resource_group, @parent.cloud_desc.name, @cloud_id.to_s)
|
|
778
775
|
@cloud_desc_cache
|
|
779
776
|
end
|
|
@@ -73,8 +73,8 @@ module MU
|
|
|
73
73
|
# Stub method- there's no such thing as being "hosted" in a CloudFormation
|
|
74
74
|
# environment. Calls {MU::Cloud::AWS.listAZs} to return sensible
|
|
75
75
|
# values, if we happen to have AWS credentials configured.
|
|
76
|
-
def self.listAZs(region: MU.curRegion,
|
|
77
|
-
MU::Cloud::AWS.listAZs(region: region,
|
|
76
|
+
def self.listAZs(region: MU.curRegion, credentials: nil)
|
|
77
|
+
MU::Cloud::AWS.listAZs(region: region, credentials: credentials)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
# Stub method- there's no such thing as being "hosted" in a CloudFormation
|
|
@@ -466,7 +466,7 @@ module MU
|
|
|
466
466
|
desc["DependsOn"] = []
|
|
467
467
|
if !cloudobj.nil? and cloudobj.respond_to?(:dependencies) and type != "subnet"
|
|
468
468
|
cloudobj.dependencies(use_cache: true).first.each_pair { |resource_classname, resources|
|
|
469
|
-
resources.each_pair { |
|
|
469
|
+
resources.each_pair { |_sibling_name, sibling_obj|
|
|
470
470
|
next if sibling_obj == cloudobj
|
|
471
471
|
# desc["DependsOn"] << (resource_classname+sibling_obj.cloudobj.mu_name).gsub!(/[^a-z0-9]/i, "")
|
|
472
472
|
desc["DependsOn"] << sibling_obj.cloudobj.cfm_name
|
|
@@ -498,7 +498,6 @@ module MU
|
|
|
498
498
|
# @param name [String]: The name of key we're creating/appending
|
|
499
499
|
# @param value [MU::Config::Tail|String]: The value to set. If it's a {MU::Config::Tail} object, we'll treat it as a reference to a parameter.
|
|
500
500
|
def self.setCloudFormationProp(resource, name, value)
|
|
501
|
-
realvalue = value
|
|
502
501
|
is_list_element = false
|
|
503
502
|
|
|
504
503
|
# Recursively resolve MU::Config::Tail references
|
|
@@ -508,9 +507,11 @@ module MU
|
|
|
508
507
|
tree[key] = self.resolveTails(val)
|
|
509
508
|
}
|
|
510
509
|
elsif tree.is_a?(Array)
|
|
510
|
+
newtree = []
|
|
511
511
|
tree.each { |elt|
|
|
512
|
-
|
|
512
|
+
newtree << self.resolveTails(elt)
|
|
513
513
|
}
|
|
514
|
+
tree = newtree
|
|
514
515
|
elsif tree.class.to_s == "MU::Config::Tail"
|
|
515
516
|
if tree.is_list_element
|
|
516
517
|
return { "Fn::Select" => [tree.index, { "Ref" => "#{tree.getPrettyName}" }] }
|
|
@@ -584,7 +585,7 @@ module MU
|
|
|
584
585
|
cfm_template["Conditions"][cond['name']] = JSON.parse(cond['cloudcode'])
|
|
585
586
|
}
|
|
586
587
|
end
|
|
587
|
-
tails.each_pair { |
|
|
588
|
+
tails.each_pair { |_param, data|
|
|
588
589
|
tail = data
|
|
589
590
|
next if tail.is_a?(MU::Config::Tail) and (tail.pseudo or !tail.runtimecode.nil?)
|
|
590
591
|
default = ""
|
|
@@ -638,7 +639,7 @@ module MU
|
|
|
638
639
|
}
|
|
639
640
|
end
|
|
640
641
|
}
|
|
641
|
-
MU::Cloud.resource_types.each { |
|
|
642
|
+
MU::Cloud.resource_types.values.each { |data|
|
|
642
643
|
if !config[data[:cfg_plural]].nil? and
|
|
643
644
|
config[data[:cfg_plural]].size > 0
|
|
644
645
|
config[data[:cfg_plural]].each { |resource|
|
|
@@ -240,8 +240,6 @@ module MU
|
|
|
240
240
|
{}
|
|
241
241
|
end
|
|
242
242
|
|
|
243
|
-
protected
|
|
244
|
-
|
|
245
243
|
# Subnets are almost a first-class resource. So let's kinda sorta treat
|
|
246
244
|
# them like one. This should only be invoked on objects that already
|
|
247
245
|
# exists in the cloud layer.
|
|
@@ -288,13 +286,13 @@ module MU
|
|
|
288
286
|
|
|
289
287
|
# Placeholder. This is a NOOP for CloudFormation, which doesn't build
|
|
290
288
|
# resources directly.
|
|
291
|
-
def self.find(
|
|
289
|
+
def self.find(**args)
|
|
292
290
|
MU.log "find() not implemented for CloudFormation layer", MU::DEBUG
|
|
293
291
|
nil
|
|
294
292
|
end
|
|
295
293
|
# Placeholder. This is a NOOP for CloudFormation, which doesn't build
|
|
296
294
|
# resources directly.
|
|
297
|
-
def self.cleanup(
|
|
295
|
+
def self.cleanup(**args)
|
|
298
296
|
MU.log "cleanup() not implemented for CloudFormation layer", MU::DEBUG
|
|
299
297
|
nil
|
|
300
298
|
end
|
data/modules/mu/clouds/google.rb
CHANGED
|
@@ -52,6 +52,17 @@ module MU
|
|
|
52
52
|
[:url]
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# Most of our resource implementation +find+ methods have to mangle their
|
|
56
|
+
# args to make sure they've extracted a project or location argument from
|
|
57
|
+
# other available information. This does it for them.
|
|
58
|
+
# @return [Hash]
|
|
59
|
+
def self.findLocationArgs(**args)
|
|
60
|
+
args[:project] ||= args[:habitat]
|
|
61
|
+
args[:project] ||= MU::Cloud::Google.defaultProject(args[:credentials])
|
|
62
|
+
args[:location] ||= args[:region] || args[:availability_zone] || "-"
|
|
63
|
+
args
|
|
64
|
+
end
|
|
65
|
+
|
|
55
66
|
# A hook that is always called just before any of the instance method of
|
|
56
67
|
# our resource implementations gets invoked, so that we can ensure that
|
|
57
68
|
# repetitive setup tasks (like resolving +:resource_group+ for Azure
|
|
@@ -141,10 +152,9 @@ module MU
|
|
|
141
152
|
def self.habitat(cloudobj, nolookup: false, deploy: nil)
|
|
142
153
|
@@habmap ||= {}
|
|
143
154
|
# XXX whaddabout config['habitat'] HNNNGH
|
|
144
|
-
|
|
145
155
|
return nil if !cloudobj.cloudclass.canLiveIn.include?(:Habitat)
|
|
146
156
|
|
|
147
|
-
# XXX
|
|
157
|
+
# XXX these are assholes because they're valid two different ways ugh ugh
|
|
148
158
|
return nil if [MU::Cloud::Google::Group, MU::Cloud::Google::Folder].include?(cloudobj.cloudclass)
|
|
149
159
|
if cloudobj.config and cloudobj.config['project']
|
|
150
160
|
if nolookup
|
|
@@ -154,7 +164,6 @@ module MU
|
|
|
154
164
|
return @@habmap[cloudobj.config['project']]
|
|
155
165
|
end
|
|
156
166
|
deploy ||= cloudobj.deploy if cloudobj.respond_to?(:deploy)
|
|
157
|
-
|
|
158
167
|
projectobj = projectLookup(cloudobj.config['project'], deploy, raise_on_fail: false)
|
|
159
168
|
|
|
160
169
|
if projectobj
|
|
@@ -363,7 +372,7 @@ module MU
|
|
|
363
372
|
cfg = credConfig(credentials)
|
|
364
373
|
return if !cfg or !cfg['project']
|
|
365
374
|
flags["project"] ||= cfg['project']
|
|
366
|
-
|
|
375
|
+
|
|
367
376
|
resp = MU::Cloud::Google.storage(credentials: credentials).list_objects(
|
|
368
377
|
adminBucketName(credentials),
|
|
369
378
|
prefix: deploy_id
|
|
@@ -420,7 +429,7 @@ module MU
|
|
|
420
429
|
MU.log e.message, MU::WARN, details: e.inspect
|
|
421
430
|
if e.inspect.match(/body: "Not Found"/)
|
|
422
431
|
raise MuError, "Google admin bucket #{adminBucketName(credentials)} or key #{name} does not appear to exist or is not visible with #{credentials ? credentials : "default"} credentials"
|
|
423
|
-
elsif e.message.match(/notFound: |Unknown user
|
|
432
|
+
elsif e.message.match(/notFound: |Unknown user:|conflict: /)
|
|
424
433
|
if retries < 5
|
|
425
434
|
sleep 5
|
|
426
435
|
retries += 1
|
|
@@ -429,7 +438,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
429
438
|
raise e
|
|
430
439
|
end
|
|
431
440
|
elsif e.inspect.match(/The metadata for object "null" was edited during the operation/)
|
|
432
|
-
MU.log e.message+" - Google admin bucket #{adminBucketName(credentials)}/#{name} with #{credentials ? credentials : "default"} credentials", MU::
|
|
441
|
+
MU.log e.message+" - Google admin bucket #{adminBucketName(credentials)}/#{name} with #{credentials ? credentials : "default"} credentials", MU::DEBUG, details: aclobj
|
|
433
442
|
sleep 10
|
|
434
443
|
retry
|
|
435
444
|
else
|
|
@@ -540,7 +549,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
540
549
|
listRegions(credentials: credentials)
|
|
541
550
|
listInstanceTypes(credentials: credentials)
|
|
542
551
|
listProjects(credentials)
|
|
543
|
-
rescue ::Google::Apis::ClientError
|
|
552
|
+
rescue ::Google::Apis::ClientError
|
|
544
553
|
MU.log "Found machine credentials #{@@svc_account_name}, but these don't appear to have sufficient permissions or scopes", MU::WARN, details: scopes
|
|
545
554
|
@@authorizers.delete(credentials)
|
|
546
555
|
return nil
|
|
@@ -717,7 +726,6 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
717
726
|
raise e
|
|
718
727
|
end
|
|
719
728
|
|
|
720
|
-
regions = []
|
|
721
729
|
result.items.each { |region|
|
|
722
730
|
@@regions[region.name] = []
|
|
723
731
|
region.zones.each { |az|
|
|
@@ -846,7 +854,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
846
854
|
if subclass.nil?
|
|
847
855
|
begin
|
|
848
856
|
@@admin_directory_api[credentials] ||= MU::Cloud::Google::GoogleEndpoint.new(api: "AdminDirectoryV1::DirectoryService", scopes: use_scopes, masquerade: MU::Cloud::Google.credConfig(credentials)['masquerade_as'], credentials: credentials, auth_error_quiet: true)
|
|
849
|
-
rescue Signet::AuthorizationError
|
|
857
|
+
rescue Signet::AuthorizationError
|
|
850
858
|
MU.log "Falling back to read-only access to DirectoryService API for credential set '#{credentials}'", MU::WARN
|
|
851
859
|
@@admin_directory_api[credentials] ||= MU::Cloud::Google::GoogleEndpoint.new(api: "AdminDirectoryV1::DirectoryService", scopes: readscopes, masquerade: MU::Cloud::Google.credConfig(credentials)['masquerade_as'], credentials: credentials)
|
|
852
860
|
@@readonly[credentials] ||= {}
|
|
@@ -1052,8 +1060,6 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1052
1060
|
@@customer_ids_cache[credentials]
|
|
1053
1061
|
end
|
|
1054
1062
|
|
|
1055
|
-
private
|
|
1056
|
-
|
|
1057
1063
|
# Wrapper class for Google APIs, so that we can catch some common
|
|
1058
1064
|
# transient endpoint errors without having to spray rescues all over the
|
|
1059
1065
|
# codebase.
|
|
@@ -1109,12 +1115,13 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1109
1115
|
# @param filter [String]: The Compute API filter string to use to isolate appropriate resources
|
|
1110
1116
|
def delete(type, project, region = nil, noop = false, filter = "description eq #{MU.deploy_id}", credentials: nil)
|
|
1111
1117
|
list_sym = "list_#{type.sub(/y$/, "ie")}s".to_sym
|
|
1118
|
+
credentials ||= @credentials
|
|
1112
1119
|
resp = nil
|
|
1113
1120
|
begin
|
|
1114
1121
|
if region
|
|
1115
|
-
resp = MU::Cloud::Google.compute(credentials:
|
|
1122
|
+
resp = MU::Cloud::Google.compute(credentials: credentials).send(list_sym, project, region, filter: filter, mu_gcp_enable_apis: false)
|
|
1116
1123
|
else
|
|
1117
|
-
resp = MU::Cloud::Google.compute(credentials:
|
|
1124
|
+
resp = MU::Cloud::Google.compute(credentials: credentials).send(list_sym, project, filter: filter, mu_gcp_enable_apis: false)
|
|
1118
1125
|
end
|
|
1119
1126
|
|
|
1120
1127
|
rescue ::Google::Apis::ClientError => e
|
|
@@ -1137,9 +1144,9 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1137
1144
|
resp = nil
|
|
1138
1145
|
failed = false
|
|
1139
1146
|
if region
|
|
1140
|
-
resp = MU::Cloud::Google.compute(credentials:
|
|
1147
|
+
resp = MU::Cloud::Google.compute(credentials: credentials).send(delete_sym, project, region, obj.name)
|
|
1141
1148
|
else
|
|
1142
|
-
resp = MU::Cloud::Google.compute(credentials:
|
|
1149
|
+
resp = MU::Cloud::Google.compute(credentials: credentials).send(delete_sym, project, obj.name)
|
|
1143
1150
|
end
|
|
1144
1151
|
|
|
1145
1152
|
if resp.error and resp.error.errors and resp.error.errors.size > 0
|
|
@@ -1195,11 +1202,19 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1195
1202
|
retval = nil
|
|
1196
1203
|
retries = 0
|
|
1197
1204
|
wait_backoff = 5
|
|
1198
|
-
if next_page_token
|
|
1199
|
-
if
|
|
1200
|
-
arguments
|
|
1201
|
-
|
|
1202
|
-
|
|
1205
|
+
if next_page_token
|
|
1206
|
+
if method_sym != :list_entry_log_entries
|
|
1207
|
+
if arguments.size == 1 and arguments.first.is_a?(Hash)
|
|
1208
|
+
arguments[0][:page_token] = next_page_token
|
|
1209
|
+
else
|
|
1210
|
+
arguments << { :page_token => next_page_token }
|
|
1211
|
+
end
|
|
1212
|
+
elsif arguments.first.class == ::Google::Apis::LoggingV2::ListLogEntriesRequest
|
|
1213
|
+
arguments[0] = ::Google::Apis::LoggingV2::ListLogEntriesRequest.new(
|
|
1214
|
+
resource_names: arguments.first.resource_names,
|
|
1215
|
+
filter: arguments.first.filter,
|
|
1216
|
+
page_token: next_page_token
|
|
1217
|
+
)
|
|
1203
1218
|
end
|
|
1204
1219
|
end
|
|
1205
1220
|
begin
|
|
@@ -1318,7 +1333,6 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1318
1333
|
if retval.class.name.match(/.*?::Operation$/)
|
|
1319
1334
|
|
|
1320
1335
|
retries = 0
|
|
1321
|
-
orig_target = retval.name
|
|
1322
1336
|
|
|
1323
1337
|
# Check whether the various types of +Operation+ responses say
|
|
1324
1338
|
# they're done, without knowing which specific API they're from
|
|
@@ -1390,7 +1404,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1390
1404
|
# take advantage.
|
|
1391
1405
|
# XXX might want to do something similar for delete ops? just the
|
|
1392
1406
|
# but where we wait for the operation to definitely be done
|
|
1393
|
-
had_been_found = false
|
|
1407
|
+
# had_been_found = false
|
|
1394
1408
|
if method_sym.to_s.match(/^(insert|create|patch)_/)
|
|
1395
1409
|
get_method = method_sym.to_s.gsub(/^(insert|patch|create_disk|create)_/, "get_").to_sym
|
|
1396
1410
|
cloud_id = if retval.respond_to?(:target_link)
|
|
@@ -1417,7 +1431,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1417
1431
|
#if method_sym == :insert_instance
|
|
1418
1432
|
#MU.log "actual_resource", MU::WARN, details: actual_resource
|
|
1419
1433
|
#end
|
|
1420
|
-
had_been_found = true
|
|
1434
|
+
# had_been_found = true
|
|
1421
1435
|
if actual_resource.respond_to?(:status) and
|
|
1422
1436
|
["PROVISIONING", "STAGING", "PENDING", "CREATING", "RESTORING"].include?(actual_resource.status)
|
|
1423
1437
|
retries = 0
|
|
@@ -1440,6 +1454,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1440
1454
|
if overall_retval
|
|
1441
1455
|
if method_sym.to_s.match(/^list_(.*)/)
|
|
1442
1456
|
require 'google/apis/iam_v1'
|
|
1457
|
+
require 'google/apis/logging_v2'
|
|
1443
1458
|
what = Regexp.last_match[1].to_sym
|
|
1444
1459
|
whatassign = (Regexp.last_match[1]+"=").to_sym
|
|
1445
1460
|
if overall_retval.class == ::Google::Apis::IamV1::ListServiceAccountsResponse
|
|
@@ -1451,7 +1466,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
|
1451
1466
|
newarray = retval.public_send(what) + overall_retval.public_send(what)
|
|
1452
1467
|
overall_retval.public_send(whatassign, newarray)
|
|
1453
1468
|
end
|
|
1454
|
-
|
|
1469
|
+
elsif !retval.respond_to?(:next_page_token) or retval.next_page_token.nil? or retval.next_page_token.empty?
|
|
1455
1470
|
MU.log "Not sure how to append #{method_sym.to_s} results to #{overall_retval.class.name} (apparently #{what.to_s} and #{whatassign.to_s} aren't it), returning first page only", MU::WARN, details: retval
|
|
1456
1471
|
return retval
|
|
1457
1472
|
end
|
|
@@ -34,7 +34,7 @@ module MU
|
|
|
34
34
|
|
|
35
35
|
# Called automatically by {MU::Deploy#createResources}
|
|
36
36
|
def groom
|
|
37
|
-
@project_id = MU::Cloud::Google.projectLookup(@config['project'], @deploy).
|
|
37
|
+
@project_id = MU::Cloud::Google.projectLookup(@config['project'], @deploy).cloud_id
|
|
38
38
|
|
|
39
39
|
current = cloud_desc
|
|
40
40
|
changed = false
|
|
@@ -143,15 +143,14 @@ module MU
|
|
|
143
143
|
# Remove all buckets associated with the currently loaded deployment.
|
|
144
144
|
# @param noop [Boolean]: If true, will only print what would be done
|
|
145
145
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
|
146
|
-
# @param region [String]: The cloud provider region
|
|
147
146
|
# @return [void]
|
|
148
|
-
def self.cleanup(noop: false, ignoremaster: false,
|
|
147
|
+
def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
|
|
149
148
|
flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
|
|
150
149
|
|
|
151
150
|
resp = MU::Cloud::Google.storage(credentials: credentials).list_buckets(flags['project'])
|
|
152
151
|
if resp and resp.items
|
|
153
152
|
resp.items.each { |bucket|
|
|
154
|
-
if bucket.labels and bucket.labels["mu-id"] == MU.deploy_id.downcase
|
|
153
|
+
if bucket.labels and bucket.labels["mu-id"] == MU.deploy_id.downcase and (ignoremaster or bucket.labels['mu-master-ip'] == MU.mu_public_ip.gsub(/\./, "_"))
|
|
155
154
|
MU.log "Deleting Cloud Storage bucket #{bucket.name}"
|
|
156
155
|
if !noop
|
|
157
156
|
MU::Cloud::Google.storage(credentials: credentials).delete_bucket(bucket.name)
|
|
@@ -172,8 +171,7 @@ module MU
|
|
|
172
171
|
# Locate an existing bucket.
|
|
173
172
|
# @return [OpenStruct]: The cloud provider's complete descriptions of matching bucket.
|
|
174
173
|
def self.find(**args)
|
|
175
|
-
args
|
|
176
|
-
args[:project] ||= MU::Cloud::Google.defaultProject(args[:credentials])
|
|
174
|
+
args = MU::Cloud::Google.findLocationArgs(args)
|
|
177
175
|
|
|
178
176
|
found = {}
|
|
179
177
|
if args[:cloud_id]
|
|
@@ -198,7 +196,7 @@ module MU
|
|
|
198
196
|
# Reverse-map our cloud description into a runnable config hash.
|
|
199
197
|
# We assume that any values we have in +@config+ are placeholders, and
|
|
200
198
|
# calculate our own accordingly based on what's live in the cloud.
|
|
201
|
-
def toKitten(
|
|
199
|
+
def toKitten(**_args)
|
|
202
200
|
bok = {
|
|
203
201
|
"cloud" => "Google",
|
|
204
202
|
"credentials" => @config['credentials'],
|
|
@@ -300,9 +298,9 @@ module MU
|
|
|
300
298
|
end
|
|
301
299
|
|
|
302
300
|
# Cloud-specific configuration properties.
|
|
303
|
-
# @param
|
|
301
|
+
# @param _config [MU::Config]: The calling MU::Config object
|
|
304
302
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
|
305
|
-
def self.schema(
|
|
303
|
+
def self.schema(_config)
|
|
306
304
|
toplevel_required = []
|
|
307
305
|
schema = {
|
|
308
306
|
"storage_class" => {
|
|
@@ -322,9 +320,9 @@ module MU
|
|
|
322
320
|
# Cloud-specific pre-processing of {MU::Config::BasketofKittens::bucket}, bare and unvalidated.
|
|
323
321
|
|
|
324
322
|
# @param bucket [Hash]: The resource to process and validate
|
|
325
|
-
# @param
|
|
323
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
326
324
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
327
|
-
def self.validateConfig(bucket,
|
|
325
|
+
def self.validateConfig(bucket, _configurator)
|
|
328
326
|
ok = true
|
|
329
327
|
bucket['project'] ||= MU::Cloud::Google.defaultProject(bucket['credentials'])
|
|
330
328
|
|