cloud-mu 3.2.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/ansible/roles/mu-nat/tasks/main.yml +3 -0
- data/bin/mu-adopt +12 -1
- data/bin/mu-aws-setup +41 -7
- data/bin/mu-azure-setup +34 -0
- data/bin/mu-configure +214 -119
- data/bin/mu-gcp-setup +37 -2
- data/bin/mu-load-config.rb +2 -1
- data/bin/mu-node-manage +3 -0
- data/bin/mu-refresh-ssl +67 -0
- data/bin/mu-run-tests +28 -6
- data/bin/mu-self-update +30 -10
- data/bin/mu-upload-chef-artifacts +30 -26
- data/cloud-mu.gemspec +10 -8
- data/cookbooks/mu-master/attributes/default.rb +5 -1
- data/cookbooks/mu-master/metadata.rb +2 -2
- data/cookbooks/mu-master/recipes/default.rb +81 -26
- data/cookbooks/mu-master/recipes/init.rb +197 -62
- data/cookbooks/mu-master/recipes/update_nagios_only.rb +1 -1
- data/cookbooks/mu-master/recipes/vault.rb +78 -77
- data/cookbooks/mu-master/templates/default/mods/rewrite.conf.erb +1 -0
- data/cookbooks/mu-master/templates/default/nagios.conf.erb +103 -0
- data/cookbooks/mu-master/templates/default/web_app.conf.erb +14 -30
- data/cookbooks/mu-tools/attributes/default.rb +12 -0
- data/cookbooks/mu-tools/files/centos-6/CentOS-Base.repo +47 -0
- data/cookbooks/mu-tools/libraries/helper.rb +98 -4
- data/cookbooks/mu-tools/libraries/monkey.rb +1 -1
- data/cookbooks/mu-tools/recipes/apply_security.rb +31 -9
- data/cookbooks/mu-tools/recipes/aws_api.rb +8 -2
- data/cookbooks/mu-tools/recipes/base_repositories.rb +1 -1
- data/cookbooks/mu-tools/recipes/gcloud.rb +2 -9
- data/cookbooks/mu-tools/recipes/google_api.rb +7 -0
- data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
- data/cookbooks/mu-tools/resources/disk.rb +113 -42
- data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
- data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
- data/extras/Gemfile.lock.bootstrap +394 -0
- data/extras/bucketstubs/error.html +0 -0
- data/extras/bucketstubs/index.html +0 -0
- data/extras/clean-stock-amis +11 -3
- data/extras/generate-stock-images +6 -3
- data/extras/git_rpm/build.sh +20 -0
- data/extras/git_rpm/mugit.spec +53 -0
- data/extras/image-generators/AWS/centos7.yaml +19 -16
- data/extras/image-generators/AWS/{rhel7.yaml → rhel71.yaml} +0 -0
- data/extras/image-generators/AWS/{win2k12.yaml → win2k12r2.yaml} +0 -0
- data/extras/image-generators/VMWare/centos8.yaml +15 -0
- data/extras/openssl_rpm/build.sh +19 -0
- data/extras/openssl_rpm/mussl.spec +46 -0
- data/extras/python_rpm/muthon.spec +14 -4
- data/extras/ruby_rpm/muby.spec +9 -5
- data/extras/sqlite_rpm/build.sh +19 -0
- data/extras/sqlite_rpm/muqlite.spec +47 -0
- data/install/installer +7 -5
- data/modules/mommacat.ru +2 -2
- data/modules/mu.rb +14 -7
- data/modules/mu/adoption.rb +5 -5
- data/modules/mu/cleanup.rb +47 -25
- data/modules/mu/cloud.rb +29 -1
- data/modules/mu/cloud/dnszone.rb +0 -2
- data/modules/mu/cloud/machine_images.rb +1 -1
- data/modules/mu/cloud/providers.rb +6 -1
- data/modules/mu/cloud/resource_base.rb +16 -7
- data/modules/mu/cloud/ssh_sessions.rb +5 -1
- data/modules/mu/cloud/wrappers.rb +20 -7
- data/modules/mu/config.rb +28 -12
- data/modules/mu/config/bucket.rb +31 -2
- data/modules/mu/config/cache_cluster.rb +1 -1
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/container_cluster.rb +1 -1
- data/modules/mu/config/database.rb +3 -3
- data/modules/mu/config/dnszone.rb +4 -3
- data/modules/mu/config/endpoint.rb +1 -0
- data/modules/mu/config/firewall_rule.rb +1 -1
- data/modules/mu/config/function.rb +16 -7
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/notifier.rb +7 -18
- data/modules/mu/config/ref.rb +55 -9
- data/modules/mu/config/schema_helpers.rb +12 -3
- data/modules/mu/config/server.rb +11 -5
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/vpc.rb +11 -10
- data/modules/mu/defaults/AWS.yaml +106 -106
- data/modules/mu/deploy.rb +40 -14
- data/modules/mu/groomers/chef.rb +2 -2
- data/modules/mu/master.rb +70 -3
- data/modules/mu/mommacat.rb +28 -9
- data/modules/mu/mommacat/daemon.rb +13 -7
- data/modules/mu/mommacat/naming.rb +2 -2
- data/modules/mu/mommacat/search.rb +16 -5
- data/modules/mu/mommacat/storage.rb +67 -32
- data/modules/mu/providers/aws.rb +298 -85
- data/modules/mu/providers/aws/alarm.rb +5 -5
- data/modules/mu/providers/aws/bucket.rb +284 -50
- data/modules/mu/providers/aws/cache_cluster.rb +26 -26
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/providers/aws/collection.rb +16 -16
- data/modules/mu/providers/aws/container_cluster.rb +84 -64
- data/modules/mu/providers/aws/database.rb +59 -55
- data/modules/mu/providers/aws/dnszone.rb +29 -12
- data/modules/mu/providers/aws/endpoint.rb +535 -50
- data/modules/mu/providers/aws/firewall_rule.rb +32 -26
- data/modules/mu/providers/aws/folder.rb +1 -1
- data/modules/mu/providers/aws/function.rb +300 -134
- data/modules/mu/providers/aws/group.rb +16 -14
- data/modules/mu/providers/aws/habitat.rb +4 -4
- data/modules/mu/providers/aws/job.rb +469 -0
- data/modules/mu/providers/aws/loadbalancer.rb +67 -45
- data/modules/mu/providers/aws/log.rb +17 -17
- data/modules/mu/providers/aws/msg_queue.rb +22 -13
- data/modules/mu/providers/aws/nosqldb.rb +99 -8
- data/modules/mu/providers/aws/notifier.rb +137 -65
- data/modules/mu/providers/aws/role.rb +119 -83
- data/modules/mu/providers/aws/search_domain.rb +166 -30
- data/modules/mu/providers/aws/server.rb +209 -118
- data/modules/mu/providers/aws/server_pool.rb +95 -130
- data/modules/mu/providers/aws/storage_pool.rb +19 -11
- data/modules/mu/providers/aws/user.rb +5 -5
- data/modules/mu/providers/aws/userdata/linux.erb +5 -4
- data/modules/mu/providers/aws/vpc.rb +109 -54
- data/modules/mu/providers/aws/vpc_subnet.rb +43 -39
- data/modules/mu/providers/azure.rb +78 -12
- data/modules/mu/providers/azure/server.rb +20 -4
- data/modules/mu/providers/cloudformation/server.rb +1 -1
- data/modules/mu/providers/google.rb +21 -5
- data/modules/mu/providers/google/bucket.rb +1 -1
- data/modules/mu/providers/google/container_cluster.rb +1 -1
- data/modules/mu/providers/google/database.rb +1 -1
- data/modules/mu/providers/google/firewall_rule.rb +1 -1
- data/modules/mu/providers/google/folder.rb +7 -3
- data/modules/mu/providers/google/function.rb +66 -31
- data/modules/mu/providers/google/group.rb +1 -1
- data/modules/mu/providers/google/habitat.rb +1 -1
- data/modules/mu/providers/google/loadbalancer.rb +1 -1
- data/modules/mu/providers/google/role.rb +6 -3
- data/modules/mu/providers/google/server.rb +1 -1
- data/modules/mu/providers/google/server_pool.rb +1 -1
- data/modules/mu/providers/google/user.rb +1 -1
- data/modules/mu/providers/google/vpc.rb +28 -3
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/aws-servers-with-handrolled-iam.yaml +37 -0
- data/modules/tests/centos6.yaml +4 -0
- data/modules/tests/centos7.yaml +4 -0
- data/modules/tests/ecs.yaml +2 -2
- data/modules/tests/eks.yaml +1 -1
- data/modules/tests/functions/node-function/lambda_function.js +10 -0
- data/modules/tests/functions/python-function/lambda_function.py +12 -0
- data/modules/tests/k8s.yaml +1 -1
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +5 -5
- data/modules/tests/regrooms/rds.yaml +5 -5
- data/modules/tests/server-with-scrub-muisms.yaml +1 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +2 -2
- metadata +42 -17
@@ -29,18 +29,21 @@ module MU
|
|
29
29
|
attr_reader :mu_name
|
30
30
|
attr_reader :name
|
31
31
|
attr_reader :az
|
32
|
+
attr_reader :config
|
32
33
|
attr_reader :cloud_desc
|
33
34
|
|
34
35
|
# @param parent [MU::Cloud::AWS::VPC]: The parent VPC of this subnet.
|
35
36
|
# @param config [Hash<String>]:
|
36
37
|
def initialize(parent, config)
|
37
|
-
@parent = parent
|
38
38
|
@config = MU::Config.manxify(config)
|
39
|
+
MU::Cloud::AWS.resourceInitHook(self, @deploy)
|
40
|
+
@parent = parent
|
39
41
|
@cloud_id = config['cloud_id']
|
42
|
+
@credentials ||= config['credentials']
|
40
43
|
@mu_name = config['mu_name']
|
41
44
|
@name = config['name']
|
42
45
|
@deploydata = config # This is a dummy for the sake of describe()
|
43
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
46
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
|
44
47
|
@az = resp.availability_zone
|
45
48
|
@ip_block = resp.cidr_block
|
46
49
|
@cloud_desc = resp # XXX this really isn't the cloud implementation's business
|
@@ -50,11 +53,11 @@ module MU
|
|
50
53
|
# Return the cloud identifier for the default route of this subnet.
|
51
54
|
# @return [String,nil]
|
52
55
|
def defaultRoute
|
53
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
56
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
|
54
57
|
filters: [{name: "association.subnet-id", values: [@cloud_id]}]
|
55
58
|
)
|
56
59
|
if resp.route_tables.size == 0 # use default route table for the VPC
|
57
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
60
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
|
58
61
|
filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
|
59
62
|
)
|
60
63
|
end
|
@@ -75,11 +78,11 @@ module MU
|
|
75
78
|
# @return [Boolean]
|
76
79
|
def private?
|
77
80
|
return false if @cloud_id.nil?
|
78
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
81
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
|
79
82
|
filters: [{name: "association.subnet-id", values: [@cloud_id]}]
|
80
83
|
)
|
81
84
|
if resp.route_tables.size == 0 # use default route table for the VPC
|
82
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
85
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_route_tables(
|
83
86
|
filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
|
84
87
|
)
|
85
88
|
end
|
@@ -106,14 +109,14 @@ module MU
|
|
106
109
|
|
107
110
|
subnetthreads = Array.new
|
108
111
|
|
109
|
-
azs = MU::Cloud::AWS.listAZs(region: @
|
112
|
+
azs = MU::Cloud::AWS.listAZs(region: @region, credentials: @credentials)
|
110
113
|
@config['subnets'].each { |subnet|
|
111
114
|
subnet_name = @config['name']+"-"+subnet['name']
|
112
115
|
az = subnet['availability_zone'] ? subnet['availability_zone'] : azs.op
|
113
116
|
MU.log "Creating Subnet #{subnet_name} (#{subnet['ip_block']}) in #{az}", details: subnet
|
114
117
|
|
115
118
|
subnetthreads << Thread.new {
|
116
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
119
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_subnet(
|
117
120
|
vpc_id: @cloud_id,
|
118
121
|
cidr_block: subnet['ip_block'],
|
119
122
|
availability_zone: az
|
@@ -123,7 +126,7 @@ module MU
|
|
123
126
|
tag_me(subnet_id, @mu_name+"-"+subnet['name'])
|
124
127
|
|
125
128
|
loop_if = Proc.new {
|
126
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
129
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_subnets(subnet_ids: [subnet_id]).subnets.first
|
127
130
|
(!resp or resp.state != "available")
|
128
131
|
}
|
129
132
|
|
@@ -141,7 +144,7 @@ module MU
|
|
141
144
|
end
|
142
145
|
MU.log "Associating Route Table '#{subnet['route_table']}' (#{routes[subnet['route_table']]['route_table_id']}) with #{subnet_name}"
|
143
146
|
MU.retrier([Aws::EC2::Errors::InvalidRouteTableIDNotFound], wait: 10, max: 10) {
|
144
|
-
MU::Cloud::AWS.ec2(region: @
|
147
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).associate_route_table(
|
145
148
|
route_table_id: routes[subnet['route_table']]['route_table_id'],
|
146
149
|
subnet_id: subnet_id
|
147
150
|
)
|
@@ -150,7 +153,7 @@ module MU
|
|
150
153
|
|
151
154
|
if subnet.has_key?("map_public_ips")
|
152
155
|
MU.retrier([Aws::EC2::Errors::InvalidSubnetIDNotFound], wait: 10, max: 10) {
|
153
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
156
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_subnet_attribute(
|
154
157
|
subnet_id: subnet_id,
|
155
158
|
map_public_ip_on_launch: {
|
156
159
|
value: subnet['map_public_ips'],
|
@@ -167,7 +170,7 @@ module MU
|
|
167
170
|
loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
|
168
171
|
logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
|
169
172
|
MU.log "Enabling traffic logging on Subnet #{subnet_name} in VPC #{@mu_name} to log group #{loggroup.mu_name}"
|
170
|
-
MU::Cloud::AWS.ec2(region: @
|
173
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_flow_logs(
|
171
174
|
resource_ids: [subnet_id],
|
172
175
|
resource_type: "Subnet",
|
173
176
|
traffic_type: subnet["traffic_type_to_log"],
|
@@ -188,30 +191,31 @@ module MU
|
|
188
191
|
def allocate_eip_for_nat
|
189
192
|
MU::MommaCat.lock("nat-gateway-eipalloc")
|
190
193
|
|
191
|
-
eips = MU::Cloud::AWS.ec2(region: @
|
192
|
-
filters: [
|
193
|
-
{
|
194
|
-
name: "domain",
|
195
|
-
values: ["vpc"]
|
196
|
-
}
|
197
|
-
]
|
198
|
-
).addresses
|
199
|
-
|
200
|
-
allocation_id = nil
|
201
|
-
eips.each { |eip|
|
202
|
-
next if !eip.association_id.nil? and !eip.association_id.empty?
|
203
|
-
if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
|
204
|
-
if !@eip_allocation_ids.include?(eip.allocation_id)
|
205
|
-
allocation_id = eip.allocation_id
|
206
|
-
break
|
207
|
-
end
|
208
|
-
end
|
209
|
-
}
|
210
|
-
|
211
|
-
if allocation_id.nil?
|
212
|
-
allocation_id = MU::Cloud::AWS.ec2(region: @
|
213
|
-
|
214
|
-
|
194
|
+
# eips = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_addresses(
|
195
|
+
# filters: [
|
196
|
+
# {
|
197
|
+
# name: "domain",
|
198
|
+
# values: ["vpc"]
|
199
|
+
# }
|
200
|
+
# ]
|
201
|
+
# ).addresses
|
202
|
+
|
203
|
+
# allocation_id = nil
|
204
|
+
# eips.each { |eip|
|
205
|
+
# next if !eip.association_id.nil? and !eip.association_id.empty?
|
206
|
+
# if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
|
207
|
+
# if !@eip_allocation_ids.include?(eip.allocation_id)
|
208
|
+
# allocation_id = eip.allocation_id
|
209
|
+
# break
|
210
|
+
# end
|
211
|
+
# end
|
212
|
+
# }
|
213
|
+
|
214
|
+
# if allocation_id.nil?
|
215
|
+
allocation_id = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).allocate_address(domain: "vpc").allocation_id
|
216
|
+
tag_me(allocation_id)
|
217
|
+
# MU::MommaCat.lock(allocation_id, false, true)
|
218
|
+
# end
|
215
219
|
|
216
220
|
@eip_allocation_ids << allocation_id
|
217
221
|
|
@@ -223,15 +227,15 @@ module MU
|
|
223
227
|
def create_nat_gateway(subnet)
|
224
228
|
allocation_id = allocate_eip_for_nat
|
225
229
|
|
226
|
-
nat_gateway_id = MU::Cloud::AWS.ec2(region: @
|
230
|
+
nat_gateway_id = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_nat_gateway(
|
227
231
|
subnet_id: subnet['subnet_id'],
|
228
232
|
allocation_id: allocation_id,
|
229
233
|
).nat_gateway.nat_gateway_id
|
230
234
|
|
231
235
|
ensure_unlock = Proc.new { MU::MommaCat.unlock(allocation_id, true) }
|
232
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
236
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
|
233
237
|
loop_if = Proc.new {
|
234
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
238
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
|
235
239
|
resp.class != Aws::EC2::Types::NatGateway or resp.state == "pending"
|
236
240
|
}
|
237
241
|
|
@@ -288,9 +288,14 @@ module MU
|
|
288
288
|
raise MuError, "Nil response from Azure API attempting list_locations(#{subscription})"
|
289
289
|
end
|
290
290
|
|
291
|
-
sdk_response.value.each
|
292
|
-
|
293
|
-
|
291
|
+
sdk_response.value.each { |region|
|
292
|
+
begin
|
293
|
+
listInstanceTypes(region.name) # use this to filter for broken regions
|
294
|
+
@@regions.push(region.name)
|
295
|
+
rescue APIError => e
|
296
|
+
MU.log "Azure region "+region.name+" does not appear operational, skipping", MU::WARN
|
297
|
+
end
|
298
|
+
}
|
294
299
|
|
295
300
|
return us_only ? @@regions.reject { |r| !r.match(/us\d?$/) } : @@regions
|
296
301
|
end
|
@@ -350,13 +355,42 @@ module MU
|
|
350
355
|
listRegions.each { |region|
|
351
356
|
next if !deploy.regionsUsed.include?(region)
|
352
357
|
begin
|
353
|
-
createResourceGroup(deploy.deploy_id+"-"+region.upcase, region, credentials: creds)
|
358
|
+
rg_obj = createResourceGroup(deploy.deploy_id+"-"+region.upcase, region, credentials: creds)
|
359
|
+
createVault(rg_obj.name, region, deploy, credentials: creds)
|
354
360
|
rescue ::MsRestAzure::AzureOperationError
|
355
361
|
end
|
356
362
|
}
|
357
363
|
}
|
358
364
|
end
|
359
365
|
|
366
|
+
# Arguably this should be a first class resource, but for now we'll do
|
367
|
+
# it here since we're going to have a generic deployment vault in every
|
368
|
+
# resource group.
|
369
|
+
# @param rg [String]: The name of the resource group in which we'll reside
|
370
|
+
# @param region [String]: The region in which we'll reside
|
371
|
+
# @param deploy [MU::MommaCat]: The deployment which we serve
|
372
|
+
# @param credentials [String]:
|
373
|
+
def self.createVault(rg, region, deploy, credentials: nil)
|
374
|
+
cred_hash = MU::Cloud::Azure.getSDKOptions(credentials)
|
375
|
+
vaultname = deploy.getResourceName(region, max_length: 23, disallowed_chars: /[^a-z0-9-]/i, never_gen_unique: true)
|
376
|
+
MU::Cloud::Azure.ensureProvider("Microsoft.KeyVault", credentials: credentials)
|
377
|
+
sku = MU::Cloud::Azure.keyvault(:Sku).new
|
378
|
+
sku.name = "standard" # ...I'm angry about this
|
379
|
+
|
380
|
+
props = MU::Cloud::Azure.keyvault(:VaultProperties).new
|
381
|
+
props.tenant_id = cred_hash[:tenant_id]
|
382
|
+
props.enabled_for_deployment = true
|
383
|
+
props.sku = sku
|
384
|
+
props.access_policies = []
|
385
|
+
|
386
|
+
params = MU::Cloud::Azure.keyvault(:VaultCreateOrUpdateParameters).new
|
387
|
+
params.location = region
|
388
|
+
params.properties = props
|
389
|
+
|
390
|
+
MU.log "Creating KeyVault #{vaultname} in #{region}"
|
391
|
+
MU::Cloud::Azure.keyvault(credentials: credentials).vaults.create_or_update(rg, vaultname, params)
|
392
|
+
end
|
393
|
+
|
360
394
|
@@rg_semaphore = Mutex.new
|
361
395
|
|
362
396
|
# Purge cloud-specific deploy meta-artifacts (SSH keys, resource groups,
|
@@ -400,17 +434,30 @@ module MU
|
|
400
434
|
end
|
401
435
|
}
|
402
436
|
MU.log "Configuring resource group #{name} in #{region}", details: rg_obj
|
403
|
-
MU::Cloud::Azure.resources(credentials: credentials).resource_groups.create_or_update(
|
437
|
+
rg = MU::Cloud::Azure.resources(credentials: credentials).resource_groups.create_or_update(
|
404
438
|
name,
|
405
439
|
rg_obj
|
406
440
|
)
|
441
|
+
|
442
|
+
rg
|
407
443
|
end
|
408
444
|
|
409
445
|
# Plant a Mu deploy secret into a storage bucket somewhere for so our kittens can consume it
|
410
|
-
# @param
|
446
|
+
# @param deploy [MU::MommaCat]: The deploy for which we're writing the secret
|
411
447
|
# @param value [String]: The contents of the secret
|
412
|
-
def self.writeDeploySecret(
|
413
|
-
|
448
|
+
def self.writeDeploySecret(deploy, value, name = nil, credentials: nil)
|
449
|
+
deploy_id = deploy.deploy_id
|
450
|
+
|
451
|
+
listRegions.each { |region|
|
452
|
+
next if !deploy.regionsUsed.include?(region)
|
453
|
+
rg = deploy_id+"-"+region.upcase
|
454
|
+
vaultname = deploy.getResourceName(region, max_length: 23, disallowed_chars: /[^a-z0-9-]/i, never_gen_unique: true)
|
455
|
+
|
456
|
+
resp = MU::Cloud::Azure.keyvault(credentials: credentials).vaults.get(rg, vaultname)
|
457
|
+
next if !resp
|
458
|
+
MU.log "vault existence check #{vaultname}", MU::WARN, details: resp
|
459
|
+
|
460
|
+
}
|
414
461
|
end
|
415
462
|
|
416
463
|
# Return the name strings of all known sets of credentials for this cloud
|
@@ -522,7 +569,7 @@ module MU
|
|
522
569
|
|
523
570
|
begin
|
524
571
|
Timeout.timeout(2) do
|
525
|
-
resp = JSON.parse(open("#{base_url}/?#{arg_str}","Metadata"=>"true").read)
|
572
|
+
resp = JSON.parse(URI.open("#{base_url}/?#{arg_str}","Metadata"=>"true").read)
|
526
573
|
MU.log "curl -H Metadata:true "+"#{base_url}/?#{arg_str}", loglevel, details: resp
|
527
574
|
if svc != "instance"
|
528
575
|
return resp
|
@@ -777,6 +824,24 @@ module MU
|
|
777
824
|
return @@resources_api[credentials]
|
778
825
|
end
|
779
826
|
|
827
|
+
# The Azure KeyVault API
|
828
|
+
# @param model [<Azure::Apis::KeyVault::Mgmt::V2018_02_14::Models>]: If specified, will return the class ::Azure::Apis::KeyVault::Mgmt::V2018_02_14::Models::model instead of an API client instance
|
829
|
+
# @param model_version [String]: Use an alternative model version supported by the SDK when requesting a +model+
|
830
|
+
# @param alt_object [String]: Return an instance of something other than the usual API client object
|
831
|
+
# @param credentials [String]: The credential set (subscription, effectively) in which to operate
|
832
|
+
# @return [MU::Cloud::Azure::SDKClient]
|
833
|
+
def self.keyvault(model = nil, alt_object: nil, credentials: nil, model_version: "V2018_02_14")
|
834
|
+
require 'azure_mgmt_key_vault'
|
835
|
+
|
836
|
+
if model and model.is_a?(Symbol)
|
837
|
+
return Object.const_get("Azure").const_get("KeyVault").const_get("Mgmt").const_get(model_version).const_get("Models").const_get(model)
|
838
|
+
else
|
839
|
+
@@keyvault_api[credentials] ||= MU::Cloud::Azure::SDKClient.new(api: "KeyVault", credentials: credentials, subclass: alt_object)
|
840
|
+
end
|
841
|
+
|
842
|
+
return @@keyvault_api[credentials]
|
843
|
+
end
|
844
|
+
|
780
845
|
# The Azure Features API
|
781
846
|
# @param model [<Azure::Apis::Features::Mgmt::V2015_12_01::Models>]: If specified, will return the class ::Azure::Apis::Features::Mgmt::V2015_12_01::Models::model instead of an API client instance
|
782
847
|
# @param model_version [String]: Use an alternative model version supported by the SDK when requesting a +model+
|
@@ -931,6 +996,7 @@ module MU
|
|
931
996
|
@@resources_api = {}
|
932
997
|
@@containers_api = {}
|
933
998
|
@@features_api = {}
|
999
|
+
@@keyvault_api = {}
|
934
1000
|
@@apis_api = {}
|
935
1001
|
@@marketplace_api = {}
|
936
1002
|
@@service_identity_api = {}
|
@@ -1069,9 +1135,9 @@ module MU
|
|
1069
1135
|
retry
|
1070
1136
|
end
|
1071
1137
|
|
1072
|
-
MU.log "#{@parent.api.class.name}.#{@myname}.#{method_sym.to_s} returned '"+err["code"]+"' - "+err["message"], MU::WARN, details: caller
|
1073
|
-
MU.log e.backtrace[0], MU::WARN, details: parsed
|
1074
|
-
raise MU::Cloud::Azure::APIError
|
1138
|
+
# MU.log "#{@parent.api.class.name}.#{@myname}.#{method_sym.to_s} returned '"+err["code"]+"' - "+err["message"], MU::WARN, details: caller
|
1139
|
+
# MU.log e.backtrace[0], MU::WARN, details: parsed
|
1140
|
+
raise MU::Cloud::Azure::APIError.new err["code"]+": "+err["message"]+" (call was #{@parent.api.class.name}.#{@myname}.#{method_sym.to_s})", details: parsed, silent: true
|
1075
1141
|
end
|
1076
1142
|
end
|
1077
1143
|
rescue JSON::ParserError
|
@@ -150,7 +150,7 @@ module MU
|
|
150
150
|
|
151
151
|
if !@nat.nil? and @nat.mu_name != @mu_name
|
152
152
|
if @nat.cloud_desc.nil?
|
153
|
-
MU.log "NAT was missing cloud descriptor when called in #{@mu_name}'s getSSHConfig", MU::ERR
|
153
|
+
MU.log "NAT #{@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
|
@@ -220,6 +220,7 @@ module MU
|
|
220
220
|
# @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching instances
|
221
221
|
def self.find(**args)
|
222
222
|
found = {}
|
223
|
+
MU.log "Azure::Server.find called", MU::NOTICE, details: args
|
223
224
|
# told one, we may have to search all the ones we can see.
|
224
225
|
resource_groups = if args[:resource_group]
|
225
226
|
[args[:resource_group]]
|
@@ -417,6 +418,7 @@ module MU
|
|
417
418
|
|
418
419
|
# return [String]: A password string.
|
419
420
|
def getWindowsAdminPassword
|
421
|
+
@deploy.fetchSecret(@mu_name, "windows_admin_password")
|
420
422
|
end
|
421
423
|
|
422
424
|
# Add a volume to this instance
|
@@ -452,7 +454,7 @@ module MU
|
|
452
454
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
453
455
|
# @param region [String]: The cloud provider region
|
454
456
|
# @return [void]
|
455
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
457
|
+
def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
456
458
|
end
|
457
459
|
|
458
460
|
# Cloud-specific configuration properties.
|
@@ -612,7 +614,7 @@ module MU
|
|
612
614
|
ok = false
|
613
615
|
end
|
614
616
|
MU::Config.addDependency(server, server['name']+"vpc", "vpc")
|
615
|
-
MU::Config.addDependency(server, server['name']+"vpc-natstion", "server",
|
617
|
+
MU::Config.addDependency(server, server['name']+"vpc-natstion", "server", their_phase: "groom")
|
616
618
|
server['vpc'] = {
|
617
619
|
"name" => server['name']+"vpc",
|
618
620
|
"subnet_pref" => "private"
|
@@ -636,6 +638,7 @@ module MU
|
|
636
638
|
ok
|
637
639
|
end
|
638
640
|
|
641
|
+
# stub
|
639
642
|
def self.diskConfig(config, create = true, disk_as_url = true, credentials: nil)
|
640
643
|
end
|
641
644
|
|
@@ -769,10 +772,23 @@ module MU
|
|
769
772
|
|
770
773
|
os_obj = MU::Cloud::Azure.compute(:OSProfile).new
|
771
774
|
if windows?
|
775
|
+
winrm_listen = MU::Cloud::Azure.compute(:WinRMListener).new
|
776
|
+
winrm_listen.certificate_url = "goddamn stupid ass thing"
|
777
|
+
winrm_listen.protocol = "https"
|
778
|
+
winrm = MU::Cloud::Azure.compute(:WinRMConfiguration).new
|
779
|
+
winrm.listeners = [winrm_listen]
|
780
|
+
|
772
781
|
win_obj = MU::Cloud::Azure.compute(:WindowsConfiguration).new
|
782
|
+
win_obj.win_rmconfiguration = winrm
|
773
783
|
os_obj.windows_configuration = win_obj
|
774
784
|
os_obj.admin_username = @config['windows_admin_username']
|
775
|
-
os_obj.admin_password =
|
785
|
+
os_obj.admin_password = begin
|
786
|
+
@deploy.fetchSecret(@mu_name, "windows_admin_password")
|
787
|
+
rescue MU::MommaCat::SecretError
|
788
|
+
pw = MU.generateWindowsPassword
|
789
|
+
@deploy.saveNodeSecret(@mu_name, pw, "windows_admin_password")
|
790
|
+
pw
|
791
|
+
end
|
776
792
|
os_obj.computer_name = @deploy.getResourceName(@config["name"], max_length: 15, disallowed_chars: /[~!@#$%^&*()=+_\[\]{}\\\|;:\.'",<>\/\?]/)
|
777
793
|
else
|
778
794
|
os_obj.admin_username = @config['ssh_user']
|
@@ -236,7 +236,7 @@ module MU
|
|
236
236
|
# @param sibling_only [Boolean]
|
237
237
|
# @return [MU::Config::Habitat,nil]
|
238
238
|
def self.projectLookup(name, deploy = MU.mommacat, raise_on_fail: true, sibling_only: false)
|
239
|
-
project_obj = deploy.findLitterMate(type: "habitats", name: name) if deploy
|
239
|
+
project_obj = deploy.findLitterMate(type: "habitats", name: name) if deploy and caller.grep(/`findLitterMate'/).empty? # XXX the dumbest
|
240
240
|
|
241
241
|
if !project_obj and !sibling_only
|
242
242
|
resp = MU::MommaCat.findStray(
|
@@ -348,7 +348,8 @@ module MU
|
|
348
348
|
# Plant a Mu deploy secret into a storage bucket somewhere for so our kittens can consume it
|
349
349
|
# @param deploy_id [String]: The deploy for which we're writing the secret
|
350
350
|
# @param value [String]: The contents of the secret
|
351
|
-
def self.writeDeploySecret(
|
351
|
+
def self.writeDeploySecret(deploy, value, name = nil, credentials: nil)
|
352
|
+
deploy_id = deploy.deploy_id
|
352
353
|
name ||= deploy_id+"-secret"
|
353
354
|
begin
|
354
355
|
MU.log "Writing #{name} to Cloud Storage bucket #{adminBucketName(credentials)}"
|
@@ -487,7 +488,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
487
488
|
base_url = "http://metadata.google.internal/computeMetadata/v1"
|
488
489
|
begin
|
489
490
|
Timeout.timeout(2) do
|
490
|
-
response = open(
|
491
|
+
response = URI.open(
|
491
492
|
"#{base_url}/#{param}",
|
492
493
|
"Metadata-Flavor" => "Google"
|
493
494
|
).read
|
@@ -981,7 +982,20 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
981
982
|
end
|
982
983
|
|
983
984
|
# Google's Cloud Billing Service API
|
984
|
-
# @param subclass [<Google::Apis::
|
985
|
+
# @param subclass [<Google::Apis::CloudbillingV1>]: If specified, will return the class ::Google::Apis::CloudbillingV1::subclass instead of an API client instance
|
986
|
+
def self.budgets(subclass = nil, credentials: nil)
|
987
|
+
require 'google/apis/billingbudgets_v1'
|
988
|
+
|
989
|
+
if subclass.nil?
|
990
|
+
@@budgets_api[credentials] ||= MU::Cloud::Google::GoogleEndpoint.new(api: "BillingbudgetsV1::CloudBillingBudgetService", scopes: ['cloud-platform', 'cloud-billing'], credentials: credentials, masquerade: MU::Cloud::Google.credConfig(credentials)['masquerade_as'])
|
991
|
+
return @@budgets_api[credentials]
|
992
|
+
elsif subclass.is_a?(Symbol)
|
993
|
+
return Object.const_get("::Google").const_get("Apis").const_get("BillingbudgetsV1").const_get(subclass)
|
994
|
+
end
|
995
|
+
end
|
996
|
+
|
997
|
+
# Google's Cloud Billing Budget Service API
|
998
|
+
# @param subclass [<Google::Apis::CloudbillingV1>]: If specified, will return the class ::Google::Apis::CloudbillingV1::subclass instead of an API client instance
|
985
999
|
def self.billing(subclass = nil, credentials: nil)
|
986
1000
|
require 'google/apis/cloudbilling_v1'
|
987
1001
|
|
@@ -1024,6 +1038,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
1024
1038
|
# @return [Array<OpenStruct>],nil]
|
1025
1039
|
def self.getOrg(credentials = nil, with_id: nil)
|
1026
1040
|
creds = MU::Cloud::Google.credConfig(credentials)
|
1041
|
+
return nil if !creds
|
1027
1042
|
credname = if creds and creds['name']
|
1028
1043
|
creds['name']
|
1029
1044
|
else
|
@@ -1309,7 +1324,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
1309
1324
|
|
1310
1325
|
svc_name = Regexp.last_match[1]
|
1311
1326
|
save_verbosity = MU.verbosity
|
1312
|
-
if
|
1327
|
+
if !["servicemanagement.googleapis.com", "billingbudgets.googleapis.com"].include?(svc_name) and method_sym != :delete
|
1313
1328
|
retries += 1
|
1314
1329
|
@@enable_semaphores[project].synchronize {
|
1315
1330
|
MU.setLogging(MU::Logger::NORMAL)
|
@@ -1564,6 +1579,7 @@ MU.log e.message, MU::WARN, details: e.inspect
|
|
1564
1579
|
@@firestore_api = {}
|
1565
1580
|
@@admin_directory_api = {}
|
1566
1581
|
@@billing_api = {}
|
1582
|
+
@@budgets_api = {}
|
1567
1583
|
@@function_api = {}
|
1568
1584
|
end
|
1569
1585
|
end
|