cloud-mu 3.2.0 → 3.5.0
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 +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
|