cloud-mu 3.1.6 → 3.2.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/bin/mu-adopt +4 -12
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +37 -1
- data/bin/mu-deploy +3 -3
- data/bin/mu-findstray-tests +25 -0
- data/bin/mu-gen-docs +2 -4
- data/bin/mu-run-tests +23 -10
- data/cloud-mu.gemspec +2 -2
- data/cookbooks/mu-tools/libraries/helper.rb +1 -1
- data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
- data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
- data/extras/generate-stock-images +1 -0
- data/modules/mu.rb +82 -95
- data/modules/mu/adoption.rb +356 -56
- data/modules/mu/cleanup.rb +21 -20
- data/modules/mu/cloud.rb +79 -1753
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +46 -0
- data/modules/mu/cloud/machine_images.rb +212 -0
- data/modules/mu/cloud/providers.rb +81 -0
- data/modules/mu/cloud/resource_base.rb +920 -0
- data/modules/mu/cloud/server.rb +40 -0
- data/modules/mu/cloud/server_pool.rb +1 -0
- data/modules/mu/cloud/ssh_sessions.rb +228 -0
- data/modules/mu/cloud/winrm_sessions.rb +237 -0
- data/modules/mu/cloud/wrappers.rb +165 -0
- data/modules/mu/config.rb +122 -80
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +1 -1
- data/modules/mu/config/cache_cluster.rb +1 -1
- data/modules/mu/config/collection.rb +1 -1
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/database.rb +83 -104
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +1 -1
- data/modules/mu/config/doc_helpers.rb +4 -5
- data/modules/mu/config/endpoint.rb +1 -1
- data/modules/mu/config/firewall_rule.rb +3 -19
- data/modules/mu/config/folder.rb +1 -1
- data/modules/mu/config/function.rb +1 -1
- data/modules/mu/config/group.rb +1 -1
- data/modules/mu/config/habitat.rb +1 -1
- data/modules/mu/config/loadbalancer.rb +57 -11
- data/modules/mu/config/log.rb +1 -1
- data/modules/mu/config/msg_queue.rb +1 -1
- data/modules/mu/config/nosqldb.rb +1 -1
- data/modules/mu/config/notifier.rb +1 -1
- data/modules/mu/config/ref.rb +30 -4
- data/modules/mu/config/role.rb +1 -1
- data/modules/mu/config/schema_helpers.rb +30 -34
- data/modules/mu/config/search_domain.rb +1 -1
- data/modules/mu/config/server.rb +4 -12
- data/modules/mu/config/server_pool.rb +3 -7
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +10 -0
- data/modules/mu/config/user.rb +1 -1
- data/modules/mu/config/vpc.rb +12 -17
- data/modules/mu/defaults/AWS.yaml +32 -32
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +1 -0
- data/modules/mu/deploy.rb +16 -15
- data/modules/mu/groomer.rb +15 -0
- data/modules/mu/groomers/chef.rb +3 -0
- data/modules/mu/logger.rb +120 -144
- data/modules/mu/master.rb +1 -1
- data/modules/mu/mommacat.rb +54 -25
- data/modules/mu/mommacat/daemon.rb +10 -7
- data/modules/mu/mommacat/naming.rb +82 -3
- data/modules/mu/mommacat/search.rb +47 -15
- data/modules/mu/mommacat/storage.rb +72 -41
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +114 -47
- data/modules/mu/{clouds → providers}/aws/alarm.rb +1 -1
- data/modules/mu/{clouds → providers}/aws/bucket.rb +2 -2
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +10 -46
- data/modules/mu/{clouds → providers}/aws/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +15 -33
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +2 -5
- data/modules/mu/{clouds → providers}/aws/endpoint.rb +2 -11
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +33 -29
- data/modules/mu/{clouds → providers}/aws/folder.rb +0 -0
- data/modules/mu/{clouds → providers}/aws/function.rb +2 -10
- data/modules/mu/{clouds → providers}/aws/group.rb +9 -13
- data/modules/mu/{clouds → providers}/aws/habitat.rb +1 -1
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +41 -33
- data/modules/mu/{clouds → providers}/aws/log.rb +2 -2
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +2 -8
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +0 -0
- data/modules/mu/{clouds → providers}/aws/notifier.rb +0 -0
- data/modules/mu/{clouds → providers}/aws/role.rb +7 -7
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +8 -13
- data/modules/mu/{clouds → providers}/aws/server.rb +55 -90
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +10 -33
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +19 -36
- data/modules/mu/{clouds → providers}/aws/user.rb +8 -12
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/aws/vpc.rb +135 -70
- data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
- data/modules/mu/{clouds → providers}/azure.rb +4 -1
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
- data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/server.rb +30 -23
- data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
- data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
- data/modules/mu/{clouds → providers}/cloudformation.rb +1 -1
- data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
- data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
- data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
- data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +14 -6
- data/modules/mu/{clouds → providers}/google/bucket.rb +1 -1
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +28 -13
- data/modules/mu/{clouds → providers}/google/database.rb +1 -8
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +2 -2
- data/modules/mu/{clouds → providers}/google/folder.rb +4 -8
- data/modules/mu/{clouds → providers}/google/function.rb +3 -3
- data/modules/mu/{clouds → providers}/google/group.rb +8 -16
- data/modules/mu/{clouds → providers}/google/habitat.rb +3 -7
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +1 -1
- data/modules/mu/{clouds → providers}/google/role.rb +42 -34
- data/modules/mu/{clouds → providers}/google/server.rb +25 -10
- data/modules/mu/{clouds → providers}/google/server_pool.rb +10 -10
- data/modules/mu/{clouds → providers}/google/user.rb +31 -21
- data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/google/vpc.rb +37 -2
- data/modules/tests/centos6.yaml +11 -0
- data/modules/tests/centos7.yaml +11 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +108 -89
- data/modules/mu/clouds/aws/database.rb +0 -1974
|
@@ -88,16 +88,28 @@ module MU
|
|
|
88
88
|
}
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
+
|
|
91
92
|
# Overwrite this deployment's configuration with a new version. Save the
|
|
92
93
|
# previous version as well.
|
|
93
94
|
# @param new_conf [Hash]: A new configuration, fully resolved by {MU::Config}
|
|
94
|
-
def updateBasketofKittens(new_conf)
|
|
95
|
+
def updateBasketofKittens(new_conf, skip_validation: false, new_metadata: nil, save_now: false)
|
|
95
96
|
loadDeploy
|
|
96
97
|
if new_conf == @original_config
|
|
97
|
-
MU.log "#{@deploy_id}", MU::WARN
|
|
98
98
|
return
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
+
scrub_with = nil
|
|
102
|
+
|
|
103
|
+
# Make sure the new config that we were just handed resolves and makes
|
|
104
|
+
# sense
|
|
105
|
+
if !skip_validation
|
|
106
|
+
f = Tempfile.new(@deploy_id)
|
|
107
|
+
f.write JSON.parse(JSON.generate(new_conf)).to_yaml
|
|
108
|
+
conf_engine = MU::Config.new(f.path) # will throw an exception if it's bad, adoption should catch this and cope reasonably
|
|
109
|
+
scrub_with = conf_engine.config
|
|
110
|
+
f.close
|
|
111
|
+
end
|
|
112
|
+
|
|
101
113
|
backup = "#{deploy_dir}/basket_of_kittens.json.#{Time.now.to_i.to_s}"
|
|
102
114
|
MU.log "Saving previous config of #{@deploy_id} to #{backup}"
|
|
103
115
|
config = File.new(backup, File::CREAT|File::TRUNC|File::RDWR, 0600)
|
|
@@ -106,9 +118,26 @@ module MU
|
|
|
106
118
|
config.flock(File::LOCK_UN)
|
|
107
119
|
config.close
|
|
108
120
|
|
|
109
|
-
@original_config = new_conf
|
|
110
|
-
|
|
111
|
-
MU.
|
|
121
|
+
@original_config = new_conf.clone
|
|
122
|
+
|
|
123
|
+
MU::Cloud.resource_types.each_pair { |res_type, attrs|
|
|
124
|
+
next if !@deployment.has_key?(attrs[:cfg_plural])
|
|
125
|
+
deletia = []
|
|
126
|
+
@deployment[attrs[:cfg_plural]].each_pair { |res_name, data|
|
|
127
|
+
orig_cfg = findResourceConfig(attrs[:cfg_plural], res_name, (scrub_with || @original_config))
|
|
128
|
+
|
|
129
|
+
if orig_cfg.nil?
|
|
130
|
+
MU.log "#{res_type} #{res_name} no longer configured, will remove deployment metadata", MU::NOTICE
|
|
131
|
+
deletia << res_name
|
|
132
|
+
end
|
|
133
|
+
}
|
|
134
|
+
@deployment[attrs[:cfg_plural]].reject! { |k, v| deletia.include?(k) }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if save_now
|
|
138
|
+
save!
|
|
139
|
+
MU.log "New config saved to #{deploy_dir}/basket_of_kittens.json"
|
|
140
|
+
end
|
|
112
141
|
end
|
|
113
142
|
|
|
114
143
|
@lock_semaphore = Mutex.new
|
|
@@ -147,11 +176,11 @@ module MU
|
|
|
147
176
|
# @param id [String]: The lock identifier to release.
|
|
148
177
|
# @param nonblock [Boolean]: Whether to block while waiting for the lock. In non-blocking mode, we simply return false if the lock is not available.
|
|
149
178
|
# return [false, nil]
|
|
150
|
-
def self.lock(id, nonblock = false, global = false)
|
|
179
|
+
def self.lock(id, nonblock = false, global = false, deploy_id: MU.deploy_id)
|
|
151
180
|
raise MuError, "Can't pass a nil id to MU::MommaCat.lock" if id.nil?
|
|
152
181
|
|
|
153
182
|
if !global
|
|
154
|
-
lockdir = "#{deploy_dir(
|
|
183
|
+
lockdir = "#{deploy_dir(deploy_id)}/locks"
|
|
155
184
|
else
|
|
156
185
|
lockdir = File.expand_path(MU.dataDir+"/locks")
|
|
157
186
|
end
|
|
@@ -186,11 +215,11 @@ module MU
|
|
|
186
215
|
|
|
187
216
|
# Release a flock() lock.
|
|
188
217
|
# @param id [String]: The lock identifier to release.
|
|
189
|
-
def self.unlock(id, global = false)
|
|
218
|
+
def self.unlock(id, global = false, deploy_id: MU.deploy_id)
|
|
190
219
|
raise MuError, "Can't pass a nil id to MU::MommaCat.unlock" if id.nil?
|
|
191
220
|
lockdir = nil
|
|
192
221
|
if !global
|
|
193
|
-
lockdir = "#{deploy_dir(
|
|
222
|
+
lockdir = "#{deploy_dir(deploy_id)}/locks"
|
|
194
223
|
else
|
|
195
224
|
lockdir = File.expand_path(MU.dataDir+"/locks")
|
|
196
225
|
end
|
|
@@ -512,48 +541,30 @@ module MU
|
|
|
512
541
|
if !@original_config['scrub_mu_isms'] and !@no_artifacts
|
|
513
542
|
credsets.each_pair { |cloud, creds|
|
|
514
543
|
creds.uniq!
|
|
515
|
-
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
|
516
544
|
creds.each { |credentials|
|
|
517
|
-
|
|
545
|
+
MU::Cloud.cloudClass(cloud).writeDeploySecret(@deploy_id, @deploy_secret, credentials: credentials)
|
|
518
546
|
}
|
|
519
547
|
}
|
|
520
548
|
end
|
|
521
549
|
end
|
|
522
550
|
|
|
523
551
|
def loadObjects(delay_descriptor_load)
|
|
552
|
+
# Load up MU::Cloud objects for all our kittens in this deploy
|
|
553
|
+
|
|
524
554
|
MU::Cloud.resource_types.each_pair { |res_type, attrs|
|
|
525
555
|
type = attrs[:cfg_plural]
|
|
526
556
|
next if !@deployment.has_key?(type)
|
|
527
557
|
|
|
558
|
+
deletia = {}
|
|
528
559
|
@deployment[type].each_pair { |res_name, data|
|
|
529
|
-
orig_cfg =
|
|
530
|
-
if @original_config.has_key?(type)
|
|
531
|
-
@original_config[type].each { |resource|
|
|
532
|
-
if resource["name"] == res_name
|
|
533
|
-
orig_cfg = resource
|
|
534
|
-
break
|
|
535
|
-
end
|
|
536
|
-
}
|
|
537
|
-
end
|
|
538
|
-
|
|
539
|
-
# Some Server objects originated from ServerPools, get their
|
|
540
|
-
# configs from there
|
|
541
|
-
if type == "servers" and orig_cfg.nil? and
|
|
542
|
-
@original_config.has_key?("server_pools")
|
|
543
|
-
@original_config["server_pools"].each { |resource|
|
|
544
|
-
if resource["name"] == res_name
|
|
545
|
-
orig_cfg = resource
|
|
546
|
-
break
|
|
547
|
-
end
|
|
548
|
-
}
|
|
549
|
-
end
|
|
560
|
+
orig_cfg = findResourceConfig(type, res_name)
|
|
550
561
|
|
|
551
562
|
if orig_cfg.nil?
|
|
552
563
|
MU.log "Failed to locate original config for #{attrs[:cfg_name]} #{res_name} in #{@deploy_id}", MU::WARN if !["firewall_rules", "databases", "storage_pools", "cache_clusters", "alarms"].include?(type) # XXX shaddap
|
|
553
564
|
next
|
|
554
565
|
end
|
|
555
566
|
|
|
556
|
-
if orig_cfg['vpc']
|
|
567
|
+
if orig_cfg['vpc']
|
|
557
568
|
ref = if orig_cfg['vpc']['id'] and orig_cfg['vpc']['id'].is_a?(Hash)
|
|
558
569
|
orig_cfg['vpc']['id']['mommacat'] = self
|
|
559
570
|
MU::Config::Ref.get(orig_cfg['vpc']['id'])
|
|
@@ -566,18 +577,12 @@ module MU
|
|
|
566
577
|
end
|
|
567
578
|
|
|
568
579
|
begin
|
|
569
|
-
# Load up MU::Cloud objects for all our kittens in this deploy
|
|
570
|
-
orig_cfg['environment'] = @environment # not always set in old deploys
|
|
571
580
|
if attrs[:has_multiples]
|
|
572
581
|
data.keys.each { |mu_name|
|
|
573
|
-
attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: mu_name, delay_descriptor_load: delay_descriptor_load)
|
|
582
|
+
addKitten(type, res_name, attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: mu_name, delay_descriptor_load: delay_descriptor_load))
|
|
574
583
|
}
|
|
575
584
|
else
|
|
576
|
-
|
|
577
|
-
if data['mu_name'].nil?
|
|
578
|
-
raise MuError, "Unable to find or guess a Mu name for #{res_type}: #{res_name} in #{@deploy_id}"
|
|
579
|
-
end
|
|
580
|
-
attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: data['mu_name'], cloud_id: data['cloud_id'])
|
|
585
|
+
addKitten(type, res_name, attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: data['mu_name'], cloud_id: data['cloud_id']))
|
|
581
586
|
end
|
|
582
587
|
rescue StandardError => e
|
|
583
588
|
if e.class != MU::Cloud::MuCloudResourceNotImplemented
|
|
@@ -585,6 +590,7 @@ module MU
|
|
|
585
590
|
end
|
|
586
591
|
end
|
|
587
592
|
}
|
|
593
|
+
|
|
588
594
|
}
|
|
589
595
|
end
|
|
590
596
|
|
|
@@ -687,5 +693,30 @@ module MU
|
|
|
687
693
|
}
|
|
688
694
|
end
|
|
689
695
|
|
|
696
|
+
def findResourceConfig(type, name, config = @original_config)
|
|
697
|
+
orig_cfg = nil
|
|
698
|
+
if config.has_key?(type)
|
|
699
|
+
config[type].each { |resource|
|
|
700
|
+
if resource["name"] == name
|
|
701
|
+
orig_cfg = resource
|
|
702
|
+
break
|
|
703
|
+
end
|
|
704
|
+
}
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
# Some Server objects originated from ServerPools, get their
|
|
708
|
+
# configs from there
|
|
709
|
+
if type == "servers" and orig_cfg.nil? and config.has_key?("server_pools")
|
|
710
|
+
config["server_pools"].each { |resource|
|
|
711
|
+
if resource["name"] == name
|
|
712
|
+
orig_cfg = resource
|
|
713
|
+
break
|
|
714
|
+
end
|
|
715
|
+
}
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
orig_cfg
|
|
719
|
+
end
|
|
720
|
+
|
|
690
721
|
end #class
|
|
691
722
|
end #module
|
|
@@ -89,7 +89,7 @@ Looking elsewhere in `cloud.rb` let's see what all we have to do:
|
|
|
89
89
|
generic_instance_methods = [:create, :notify, :mu_name, :cloud_id, :config]
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
Just the basics, for now. Here's what that will look like in the AWS layer, in the file `modules/mu/
|
|
92
|
+
Just the basics, for now. Here's what that will look like in the AWS layer, in the file `modules/mu/providers/aws/function.rb`:
|
|
93
93
|
|
|
94
94
|
```
|
|
95
95
|
module MU
|
|
@@ -39,7 +39,7 @@ module MU
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
# List all AWS projects available to our credentials
|
|
42
|
-
def self.listHabitats(credentials = nil)
|
|
42
|
+
def self.listHabitats(credentials = nil, use_cache: true)
|
|
43
43
|
cfg = credConfig(credentials)
|
|
44
44
|
return [] if !cfg or !cfg['account_number']
|
|
45
45
|
[cfg['account_number']]
|
|
@@ -805,46 +805,41 @@ end
|
|
|
805
805
|
|
|
806
806
|
@@instance_types ||= {}
|
|
807
807
|
@@instance_types[region] ||= {}
|
|
808
|
-
next_token = nil
|
|
809
808
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
type: "TERM_MATCH"
|
|
830
|
-
}
|
|
831
|
-
],
|
|
832
|
-
next_token: next_token
|
|
833
|
-
)
|
|
834
|
-
resp.price_list.each { |pricing|
|
|
835
|
-
data = JSON.parse(pricing)
|
|
836
|
-
type = data["product"]["attributes"]["instanceType"]
|
|
837
|
-
next if @@instance_types[region].has_key?(type)
|
|
838
|
-
@@instance_types[region][type] = {}
|
|
839
|
-
["ecu", "vcpu", "memory", "storage"].each { |a|
|
|
840
|
-
@@instance_types[region][type][a] = data["product"]["attributes"][a]
|
|
809
|
+
# Pricing API isn't widely available, so ask a region we know supports
|
|
810
|
+
# it
|
|
811
|
+
resp = MU::Cloud::AWS.pricing(region: "us-east-1").get_products(
|
|
812
|
+
service_code: "AmazonEC2",
|
|
813
|
+
filters: [
|
|
814
|
+
{
|
|
815
|
+
field: "productFamily",
|
|
816
|
+
value: "Compute Instance",
|
|
817
|
+
type: "TERM_MATCH"
|
|
818
|
+
},
|
|
819
|
+
{
|
|
820
|
+
field: "tenancy",
|
|
821
|
+
value: "Shared",
|
|
822
|
+
type: "TERM_MATCH"
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
field: "location",
|
|
826
|
+
value: human_region,
|
|
827
|
+
type: "TERM_MATCH"
|
|
841
828
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
829
|
+
]
|
|
830
|
+
)
|
|
831
|
+
resp.price_list.each { |pricing|
|
|
832
|
+
data = JSON.parse(pricing)
|
|
833
|
+
type = data["product"]["attributes"]["instanceType"]
|
|
834
|
+
next if @@instance_types[region].has_key?(type)
|
|
835
|
+
@@instance_types[region][type] = {}
|
|
836
|
+
["ecu", "vcpu", "memory", "storage"].each { |a|
|
|
837
|
+
@@instance_types[region][type][a] = data["product"]["attributes"][a]
|
|
845
838
|
}
|
|
846
|
-
|
|
847
|
-
|
|
839
|
+
@@instance_types[region][type]["memory"].sub!(/ GiB/, "")
|
|
840
|
+
@@instance_types[region][type]["memory"] = @@instance_types[region][type]["memory"].to_f
|
|
841
|
+
@@instance_types[region][type]["vcpu"] = @@instance_types[region][type]["vcpu"].to_f
|
|
842
|
+
}
|
|
848
843
|
|
|
849
844
|
@@instance_types
|
|
850
845
|
end
|
|
@@ -1251,7 +1246,7 @@ end
|
|
|
1251
1246
|
# Mu Master, if we're in AWS.
|
|
1252
1247
|
# @return [void]
|
|
1253
1248
|
def self.openFirewallForClients
|
|
1254
|
-
MU::Cloud.
|
|
1249
|
+
MU::Cloud.resourceClass("AWS", :FirewallRule)
|
|
1255
1250
|
begin
|
|
1256
1251
|
if File.exist?(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
|
|
1257
1252
|
::Chef::Config.from_file(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
|
|
@@ -1454,21 +1449,93 @@ end
|
|
|
1454
1449
|
# Catch-all for AWS client methods. Essentially a pass-through with some
|
|
1455
1450
|
# rescues for known silly endpoint behavior.
|
|
1456
1451
|
def method_missing(method_sym, *arguments)
|
|
1452
|
+
# make sure error symbols are loaded for our exception handling later
|
|
1457
1453
|
require "aws-sdk-core"
|
|
1454
|
+
require "aws-sdk-core/rds"
|
|
1455
|
+
require "aws-sdk-core/ec2"
|
|
1456
|
+
require "aws-sdk-core/route53"
|
|
1457
|
+
require "aws-sdk-core/iam"
|
|
1458
|
+
require "aws-sdk-core/efs"
|
|
1459
|
+
require "aws-sdk-core/pricing"
|
|
1460
|
+
require "aws-sdk-core/apigateway"
|
|
1461
|
+
require "aws-sdk-core/ecs"
|
|
1462
|
+
require "aws-sdk-core/eks"
|
|
1463
|
+
require "aws-sdk-core/cloudwatchlogs"
|
|
1464
|
+
require "aws-sdk-core/elasticloadbalancing"
|
|
1465
|
+
require "aws-sdk-core/elasticloadbalancingv2"
|
|
1466
|
+
require "aws-sdk-core/autoscaling"
|
|
1467
|
+
require "aws-sdk-core/client_waiters"
|
|
1468
|
+
require "aws-sdk-core/waiters/errors"
|
|
1458
1469
|
|
|
1459
1470
|
retries = 0
|
|
1460
1471
|
begin
|
|
1461
1472
|
MU.log "Calling #{method_sym} in #{@region}", MU::DEBUG, details: arguments
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1473
|
+
|
|
1474
|
+
retval = if !arguments.nil? and arguments.size == 1
|
|
1475
|
+
@api.method(method_sym).call(arguments[0])
|
|
1476
|
+
elsif !arguments.nil? and arguments.size > 0
|
|
1477
|
+
@api.method(method_sym).call(*arguments)
|
|
1478
|
+
else
|
|
1479
|
+
@api.method(method_sym).call
|
|
1480
|
+
end
|
|
1481
|
+
|
|
1482
|
+
if !retval.nil?
|
|
1483
|
+
begin
|
|
1484
|
+
page_markers = [:marker, :next_token]
|
|
1485
|
+
paginator = nil
|
|
1486
|
+
new_page = nil
|
|
1487
|
+
[:next_token, :marker].each { |m|
|
|
1488
|
+
if !retval.nil? and retval.respond_to?(m)
|
|
1489
|
+
paginator = m
|
|
1490
|
+
new_page = retval.send(paginator)
|
|
1491
|
+
break
|
|
1492
|
+
end
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
if paginator and new_page and !new_page.empty?
|
|
1496
|
+
resp = retval.respond_to?(:__getobj__) ? retval.__getobj__ : retval
|
|
1497
|
+
concat_to = resp.class.instance_methods(false).reject { |m|
|
|
1498
|
+
m.to_s.match(/=$/) or m == paginator or resp.send(m).nil? or !resp.send(m).is_a?(Array)
|
|
1499
|
+
}
|
|
1500
|
+
if concat_to.size != 1
|
|
1501
|
+
MU.log "Tried to figure out where I might append paginated results for a #{resp.class.name}, but failed", MU::DEBUG, details: concat_to
|
|
1502
|
+
else
|
|
1503
|
+
concat_to = concat_to.first
|
|
1504
|
+
new_args = arguments ? arguments.dup : [{}]
|
|
1505
|
+
begin
|
|
1506
|
+
if new_args.is_a?(Array)
|
|
1507
|
+
new_args << {} if new_args.empty?
|
|
1508
|
+
if new_args.size == 1 and new_args.first.is_a?(Hash)
|
|
1509
|
+
new_args[0][paginator] = new_page
|
|
1510
|
+
else
|
|
1511
|
+
MU.log "I don't know how to insert a #{paginator} into these arguments for #{method_sym}", MU::WARN, details: new_args
|
|
1512
|
+
end
|
|
1513
|
+
elsif new_args.is_a?(Hash)
|
|
1514
|
+
new_args[paginator] = new_page
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
MU.log "Attempting magic pagination for #{method_sym}", MU::DEBUG, details: new_args
|
|
1518
|
+
|
|
1519
|
+
# resp = if !arguments.nil? and arguments.size == 1
|
|
1520
|
+
# @api.method(method_sym).call(new_args[0])
|
|
1521
|
+
# elsif !arguments.nil? and arguments.size > 0
|
|
1522
|
+
resp = @api.method(method_sym).call(*new_args)
|
|
1523
|
+
# end
|
|
1524
|
+
break if resp.nil?
|
|
1525
|
+
resp = resp.__getobj__ if resp.respond_to?(:__getobj__)
|
|
1526
|
+
retval.send(concat_to).concat(resp.send(concat_to))
|
|
1527
|
+
new_page = resp.send(paginator) if !resp.nil?
|
|
1528
|
+
end while !resp.nil? and !new_page.nil? and !new_page.empty?
|
|
1529
|
+
end
|
|
1530
|
+
end
|
|
1531
|
+
rescue StandardError => e
|
|
1532
|
+
MU.log "Made a good-faith effort to auto-paginate API call to #{method_sym} and failed with #{e.message}", MU::DEBUG, details: arguments
|
|
1533
|
+
raise e
|
|
1534
|
+
end
|
|
1469
1535
|
end
|
|
1536
|
+
|
|
1470
1537
|
return retval
|
|
1471
|
-
rescue Aws::EC2::Errors::InternalError, Aws::EC2::Errors::RequestLimitExceeded, Aws::EC2::Errors::Unavailable, Aws::Route53::Errors::Throttling, Aws::ElasticLoadBalancing::Errors::HttpFailureException, Aws::EC2::Errors::Http503Error, Aws::AutoScaling::Errors::Http503Error, Aws::AutoScaling::Errors::InternalFailure, Aws::AutoScaling::Errors::ServiceUnavailable, Aws::Route53::Errors::ServiceUnavailable, Aws::ElasticLoadBalancing::Errors::Throttling, Aws::RDS::Errors::ClientUnavailable, Aws::Waiters::Errors::UnexpectedError, Aws::ElasticLoadBalancing::Errors::ServiceUnavailable, Aws::ElasticLoadBalancingV2::Errors::Throttling, Seahorse::Client::NetworkingError, Aws::IAM::Errors::Throttling, Aws::EFS::Errors::ThrottlingException, Aws::Pricing::Errors::ThrottlingException, Aws::APIGateway::Errors::TooManyRequestsException, Aws::ECS::Errors::ThrottlingException, Net::ReadTimeout, Faraday::TimeoutError, Aws::CloudWatchLogs::Errors::ThrottlingException => e
|
|
1538
|
+
rescue Aws::RDS::Errors::Throttling, Aws::EC2::Errors::InternalError, Aws::EC2::Errors::RequestLimitExceeded, Aws::EC2::Errors::Unavailable, Aws::Route53::Errors::Throttling, Aws::ElasticLoadBalancing::Errors::HttpFailureException, Aws::EC2::Errors::Http503Error, Aws::AutoScaling::Errors::Http503Error, Aws::AutoScaling::Errors::InternalFailure, Aws::AutoScaling::Errors::ServiceUnavailable, Aws::Route53::Errors::ServiceUnavailable, Aws::ElasticLoadBalancing::Errors::Throttling, Aws::RDS::Errors::ClientUnavailable, Aws::Waiters::Errors::UnexpectedError, Aws::ElasticLoadBalancing::Errors::ServiceUnavailable, Aws::ElasticLoadBalancingV2::Errors::Throttling, Seahorse::Client::NetworkingError, Aws::IAM::Errors::Throttling, Aws::EFS::Errors::ThrottlingException, Aws::Pricing::Errors::ThrottlingException, Aws::APIGateway::Errors::TooManyRequestsException, Aws::ECS::Errors::ThrottlingException, Net::ReadTimeout, Faraday::TimeoutError, Aws::CloudWatchLogs::Errors::ThrottlingException => e
|
|
1472
1539
|
if e.class.name == "Seahorse::Client::NetworkingError" and e.message.match(/Name or service not known/)
|
|
1473
1540
|
MU.log e.inspect, MU::ERR
|
|
1474
1541
|
raise e
|
|
@@ -321,7 +321,7 @@ module MU
|
|
|
321
321
|
if !depclass.nil?
|
|
322
322
|
dimension["depclass"] = depclass
|
|
323
323
|
if !dimension["name"].nil? and !dimension["name"].empty?
|
|
324
|
-
alarm
|
|
324
|
+
MU::Config.addDependency(alarm, dimension["name"], depclass)
|
|
325
325
|
end
|
|
326
326
|
end
|
|
327
327
|
}
|
|
@@ -97,7 +97,7 @@ module MU
|
|
|
97
97
|
]
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
policy_docs = MU::Cloud
|
|
100
|
+
policy_docs = MU::Cloud.resourceClass("AWS", "Role").genPolicyDocument(@config['policies'], deploy_obj: @deploy, bucket_style: true)
|
|
101
101
|
policy_docs.each { |doc|
|
|
102
102
|
MU.log "Applying S3 bucket policy #{doc.keys.first} to bucket #{@cloud_id}", MU::NOTICE, details: JSON.pretty_generate(doc.values.first)
|
|
103
103
|
MU::Cloud::AWS.s3(credentials: @config['credentials'], region: @config['region']).put_bucket_policy(
|
|
@@ -309,7 +309,7 @@ module MU
|
|
|
309
309
|
def self.schema(_config)
|
|
310
310
|
toplevel_required = []
|
|
311
311
|
schema = {
|
|
312
|
-
"policies" => MU::Cloud
|
|
312
|
+
"policies" => MU::Cloud.resourceClass("AWS", "Role").condition_schema,
|
|
313
313
|
"acl" => {
|
|
314
314
|
"type" => "string",
|
|
315
315
|
"enum" => ["private", "public-read", "public-read-write", "authenticated-read"],
|
|
@@ -199,7 +199,7 @@ module MU
|
|
|
199
199
|
addStandardTags(member, "cluster", region: @config['region'])
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
MU::Cloud
|
|
202
|
+
MU::Cloud.resourceClass("AWS", "DNSZone").genericMuDNSEntry(
|
|
203
203
|
name: resp.replication_group_id,
|
|
204
204
|
target: "#{resp.node_groups.first.primary_endpoint.address}.",
|
|
205
205
|
cloudclass: MU::Cloud::CacheCluster,
|
|
@@ -207,7 +207,7 @@ module MU
|
|
|
207
207
|
)
|
|
208
208
|
|
|
209
209
|
resp.node_groups.first.node_group_members.each { |member|
|
|
210
|
-
MU::Cloud
|
|
210
|
+
MU::Cloud.resourceClass("AWS", "DNSZone").genericMuDNSEntry(
|
|
211
211
|
name: member.cache_cluster_id,
|
|
212
212
|
target: "#{member.read_endpoint.address}.",
|
|
213
213
|
cloudclass: MU::Cloud::CacheCluster,
|
|
@@ -270,7 +270,7 @@ module MU
|
|
|
270
270
|
def createSubnetGroup
|
|
271
271
|
subnet_ids = []
|
|
272
272
|
if @config["vpc"] && !@config["vpc"].empty?
|
|
273
|
-
raise MuError
|
|
273
|
+
raise MuError.new "Didn't find the VPC specified for #{@mu_name}", details: @config["vpc"].to_h unless @vpc
|
|
274
274
|
|
|
275
275
|
vpc_id = @vpc.cloud_id
|
|
276
276
|
|
|
@@ -283,7 +283,7 @@ module MU
|
|
|
283
283
|
else
|
|
284
284
|
@config["vpc"]["subnets"].each { |subnet|
|
|
285
285
|
subnet_obj = @vpc.getSubnet(cloud_id: subnet["subnet_id"].to_s, name: subnet["subnet_name"].to_s)
|
|
286
|
-
raise MuError
|
|
286
|
+
raise MuError.new "Couldn't find a live subnet matching #{subnet} in #{@vpc}", details: @vpc.subnets if subnet_obj.nil?
|
|
287
287
|
subnet_ids << subnet_obj.cloud_id
|
|
288
288
|
}
|
|
289
289
|
end
|
|
@@ -333,24 +333,7 @@ module MU
|
|
|
333
333
|
subnet_ids: subnet_ids
|
|
334
334
|
)
|
|
335
335
|
|
|
336
|
-
|
|
337
|
-
# Adding just for consistency, but do we really need this for cache clusters? I guess Nagios and such..
|
|
338
|
-
if @config["vpc"]["nat_host_name"] || @config["vpc"]["nat_host_id"] || @config["vpc"]["nat_host_tag"] || @config["vpc"]["nat_host_ip"]
|
|
339
|
-
nat = @nat
|
|
340
|
-
if nat.is_a?(Struct) && nat.nat_gateway_id && nat.nat_gateway_id.start_with?("nat-")
|
|
341
|
-
MU.log "Using NAT Gateway, not modifying security groups"
|
|
342
|
-
else
|
|
343
|
-
_nat_name, _nat_conf, nat_deploydata = @nat.describe
|
|
344
|
-
@deploy.kittens['firewall_rules'].values.each { |acl|
|
|
345
|
-
# XXX if a user doesn't set up dependencies correctly, this can die horribly on a NAT that's still in mid-creation. Fix this... possibly in the config parser.
|
|
346
|
-
if acl.config["admin"]
|
|
347
|
-
acl.addRule([nat_deploydata["private_ip_address"]], proto: "tcp")
|
|
348
|
-
acl.addRule([nat_deploydata["private_ip_address"]], proto: "udp")
|
|
349
|
-
break
|
|
350
|
-
end
|
|
351
|
-
}
|
|
352
|
-
end
|
|
353
|
-
end
|
|
336
|
+
allowBastionAccess
|
|
354
337
|
|
|
355
338
|
if @dependencies.has_key?('firewall_rule')
|
|
356
339
|
@config["security_group_ids"] = []
|
|
@@ -430,7 +413,7 @@ module MU
|
|
|
430
413
|
}
|
|
431
414
|
end
|
|
432
415
|
# XXX this should be a call to @deploy.nameKitten
|
|
433
|
-
MU::Cloud
|
|
416
|
+
MU::Cloud.resourceClass("AWS", "DNSZone").createRecordsFromConfig(@config['dns_records'], target: repl_group.node_groups.first.primary_endpoint.address)
|
|
434
417
|
|
|
435
418
|
deploy_struct = {
|
|
436
419
|
"identifier" => repl_group.replication_group_id,
|
|
@@ -703,26 +686,7 @@ module MU
|
|
|
703
686
|
"type" => "boolean",
|
|
704
687
|
"description" => "Create a replication group; will be set automatically if +engine+ is +redis+ and +node_count+ is greated than one."
|
|
705
688
|
},
|
|
706
|
-
"ingress_rules" =>
|
|
707
|
-
"items" => {
|
|
708
|
-
"properties" => {
|
|
709
|
-
"sgs" => {
|
|
710
|
-
"type" => "array",
|
|
711
|
-
"items" => {
|
|
712
|
-
"description" => "Other AWS Security Groups; resources that are associated with this group will have this rule applied to their traffic",
|
|
713
|
-
"type" => "string"
|
|
714
|
-
}
|
|
715
|
-
},
|
|
716
|
-
"lbs" => {
|
|
717
|
-
"type" => "array",
|
|
718
|
-
"items" => {
|
|
719
|
-
"description" => "AWS Load Balancers which will have this rule applied to their traffic",
|
|
720
|
-
"type" => "string"
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
}
|
|
689
|
+
"ingress_rules" => MU::Cloud.resourceClass("AWS", "FirewallRule").ingressRuleAddtlSchema
|
|
726
690
|
}
|
|
727
691
|
[toplevel_required, schema]
|
|
728
692
|
end
|
|
@@ -823,7 +787,7 @@ module MU
|
|
|
823
787
|
end
|
|
824
788
|
|
|
825
789
|
# The API is broken, cluster.cache_nodes is returnning an empty array, and the only URL we can get is the config one with cluster.configuration_endpoint.address.
|
|
826
|
-
# MU::Cloud
|
|
790
|
+
# MU::Cloud.resourceClass("AWS", "DNSZone").genericMuDNSEntry(name: cluster_id, target: , cloudclass: MU::Cloud::CacheCluster, delete: true)
|
|
827
791
|
|
|
828
792
|
if %w{deleting deleted}.include?(cluster.cache_cluster_status)
|
|
829
793
|
MU.log "#{cluster_id} has already been terminated", MU::WARN
|
|
@@ -925,10 +889,10 @@ module MU
|
|
|
925
889
|
end
|
|
926
890
|
|
|
927
891
|
# What's the likelihood of having more than one node group? maybe iterate over node_groups instead of assuming there is only one?
|
|
928
|
-
MU::Cloud
|
|
892
|
+
MU::Cloud.resourceClass("AWS", "DNSZone").genericMuDNSEntry(name: repl_group_id, target: repl_group.node_groups.first.primary_endpoint.address, cloudclass: MU::Cloud::CacheCluster, delete: true)
|
|
929
893
|
# Assuming we also created DNS records for each of our cluster's read endpoint.
|
|
930
894
|
repl_group.node_groups.first.node_group_members.each { |member|
|
|
931
|
-
MU::Cloud
|
|
895
|
+
MU::Cloud.resourceClass("AWS", "DNSZone").genericMuDNSEntry(name: member.cache_cluster_id, target: member.read_endpoint.address, cloudclass: MU::Cloud::CacheCluster, delete: true)
|
|
932
896
|
}
|
|
933
897
|
|
|
934
898
|
if %w{deleting deleted}.include?(repl_group.status)
|