cloud-mu 2.1.0beta → 3.0.0beta
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 +5 -5
- data/Berksfile +4 -5
- data/Berksfile.lock +179 -0
- data/README.md +1 -6
- data/ansible/roles/geerlingguy.firewall/templates/firewall.bash.j2 +0 -0
- data/ansible/roles/mu-installer/README.md +33 -0
- data/ansible/roles/mu-installer/defaults/main.yml +2 -0
- data/ansible/roles/mu-installer/handlers/main.yml +2 -0
- data/ansible/roles/mu-installer/meta/main.yml +60 -0
- data/ansible/roles/mu-installer/tasks/main.yml +13 -0
- data/ansible/roles/mu-installer/tests/inventory +2 -0
- data/ansible/roles/mu-installer/tests/test.yml +5 -0
- data/ansible/roles/mu-installer/vars/main.yml +2 -0
- data/bin/mu-adopt +125 -0
- data/bin/mu-aws-setup +4 -4
- data/bin/mu-azure-setup +265 -0
- data/bin/mu-azure-tests +43 -0
- data/bin/mu-cleanup +20 -8
- data/bin/mu-configure +224 -98
- data/bin/mu-deploy +8 -3
- data/bin/mu-gcp-setup +16 -8
- data/bin/mu-gen-docs +92 -8
- data/bin/mu-load-config.rb +52 -12
- data/bin/mu-momma-cat +36 -0
- data/bin/mu-node-manage +34 -27
- data/bin/mu-self-update +2 -2
- data/bin/mu-ssh +12 -8
- data/bin/mu-upload-chef-artifacts +11 -4
- data/bin/mu-user-manage +3 -0
- data/cloud-mu.gemspec +8 -11
- data/cookbooks/firewall/libraries/helpers_iptables.rb +2 -2
- data/cookbooks/firewall/metadata.json +1 -1
- data/cookbooks/firewall/recipes/default.rb +5 -9
- data/cookbooks/mu-firewall/attributes/default.rb +2 -0
- data/cookbooks/mu-firewall/metadata.rb +1 -1
- data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +0 -0
- data/cookbooks/mu-master/Berksfile +2 -2
- data/cookbooks/mu-master/files/default/check_mem.pl +0 -0
- data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
- data/cookbooks/mu-master/metadata.rb +5 -4
- data/cookbooks/mu-master/recipes/389ds.rb +1 -1
- data/cookbooks/mu-master/recipes/basepackages.rb +30 -10
- data/cookbooks/mu-master/recipes/default.rb +59 -7
- data/cookbooks/mu-master/recipes/firewall-holes.rb +1 -1
- data/cookbooks/mu-master/recipes/init.rb +65 -47
- data/cookbooks/mu-master/recipes/{eks-kubectl.rb → kubectl.rb} +4 -10
- data/cookbooks/mu-master/recipes/sssd.rb +2 -1
- data/cookbooks/mu-master/recipes/update_nagios_only.rb +6 -6
- data/cookbooks/mu-master/templates/default/web_app.conf.erb +2 -2
- data/cookbooks/mu-master/templates/mods/ldap.conf.erb +4 -0
- data/cookbooks/mu-php54/Berksfile +1 -2
- data/cookbooks/mu-php54/metadata.rb +4 -5
- data/cookbooks/mu-php54/recipes/default.rb +1 -1
- data/cookbooks/mu-splunk/templates/default/splunk-init.erb +0 -0
- data/cookbooks/mu-tools/Berksfile +3 -2
- data/cookbooks/mu-tools/files/default/Mu_CA.pem +33 -0
- data/cookbooks/mu-tools/libraries/helper.rb +20 -8
- data/cookbooks/mu-tools/metadata.rb +5 -2
- data/cookbooks/mu-tools/recipes/apply_security.rb +2 -3
- data/cookbooks/mu-tools/recipes/eks.rb +1 -1
- data/cookbooks/mu-tools/recipes/gcloud.rb +5 -30
- data/cookbooks/mu-tools/recipes/nagios.rb +1 -1
- data/cookbooks/mu-tools/recipes/rsyslog.rb +1 -0
- data/cookbooks/mu-tools/recipes/selinux.rb +19 -0
- data/cookbooks/mu-tools/recipes/split_var_partitions.rb +0 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +256 -122
- data/cookbooks/mu-tools/resources/disk.rb +3 -1
- data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +1 -1
- data/cookbooks/mu-tools/templates/default/etc_hosts.erb +1 -1
- data/cookbooks/mu-tools/templates/default/{kubeconfig.erb → kubeconfig-eks.erb} +0 -0
- data/cookbooks/mu-tools/templates/default/kubeconfig-gke.erb +27 -0
- data/cookbooks/mu-tools/templates/windows-10/sshd_config.erb +137 -0
- data/cookbooks/mu-utility/recipes/nat.rb +4 -0
- data/extras/alpha.png +0 -0
- data/extras/beta.png +0 -0
- data/extras/clean-stock-amis +2 -2
- data/extras/generate-stock-images +131 -0
- data/extras/git-fix-permissions-hook +0 -0
- data/extras/image-generators/AWS/centos6.yaml +17 -0
- data/extras/image-generators/{aws → AWS}/centos7-govcloud.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/centos7.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/rhel7.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/win2k12.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/win2k16.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/windows.yaml +0 -0
- data/extras/image-generators/{gcp → Google}/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +18 -0
- data/extras/python_rpm/build.sh +0 -0
- data/extras/release.png +0 -0
- data/extras/ruby_rpm/build.sh +0 -0
- data/extras/ruby_rpm/muby.spec +1 -1
- data/install/README.md +43 -5
- data/install/deprecated-bash-library.sh +0 -0
- data/install/installer +1 -1
- data/install/jenkinskeys.rb +0 -0
- data/install/mu-master.yaml +55 -0
- data/modules/mommacat.ru +41 -7
- data/modules/mu.rb +444 -149
- data/modules/mu/adoption.rb +500 -0
- data/modules/mu/cleanup.rb +235 -158
- data/modules/mu/cloud.rb +675 -138
- data/modules/mu/clouds/aws.rb +156 -24
- data/modules/mu/clouds/aws/alarm.rb +4 -14
- data/modules/mu/clouds/aws/bucket.rb +60 -18
- data/modules/mu/clouds/aws/cache_cluster.rb +8 -20
- data/modules/mu/clouds/aws/collection.rb +12 -22
- data/modules/mu/clouds/aws/container_cluster.rb +209 -118
- data/modules/mu/clouds/aws/database.rb +120 -45
- data/modules/mu/clouds/aws/dnszone.rb +7 -18
- data/modules/mu/clouds/aws/endpoint.rb +5 -15
- data/modules/mu/clouds/aws/firewall_rule.rb +144 -72
- data/modules/mu/clouds/aws/folder.rb +4 -11
- data/modules/mu/clouds/aws/function.rb +6 -16
- data/modules/mu/clouds/aws/group.rb +4 -12
- data/modules/mu/clouds/aws/habitat.rb +11 -13
- data/modules/mu/clouds/aws/loadbalancer.rb +40 -28
- data/modules/mu/clouds/aws/log.rb +5 -13
- data/modules/mu/clouds/aws/msg_queue.rb +9 -24
- data/modules/mu/clouds/aws/nosqldb.rb +4 -12
- data/modules/mu/clouds/aws/notifier.rb +6 -13
- data/modules/mu/clouds/aws/role.rb +69 -40
- data/modules/mu/clouds/aws/search_domain.rb +17 -20
- data/modules/mu/clouds/aws/server.rb +184 -94
- data/modules/mu/clouds/aws/server_pool.rb +33 -38
- data/modules/mu/clouds/aws/storage_pool.rb +5 -12
- data/modules/mu/clouds/aws/user.rb +59 -33
- data/modules/mu/clouds/aws/userdata/linux.erb +18 -30
- data/modules/mu/clouds/aws/userdata/windows.erb +9 -9
- data/modules/mu/clouds/aws/vpc.rb +214 -145
- data/modules/mu/clouds/azure.rb +978 -44
- data/modules/mu/clouds/azure/container_cluster.rb +413 -0
- data/modules/mu/clouds/azure/firewall_rule.rb +500 -0
- data/modules/mu/clouds/azure/habitat.rb +167 -0
- data/modules/mu/clouds/azure/loadbalancer.rb +205 -0
- data/modules/mu/clouds/azure/role.rb +211 -0
- data/modules/mu/clouds/azure/server.rb +810 -0
- data/modules/mu/clouds/azure/user.rb +257 -0
- data/modules/mu/clouds/azure/userdata/README.md +4 -0
- data/modules/mu/clouds/azure/userdata/linux.erb +137 -0
- data/modules/mu/clouds/azure/userdata/windows.erb +275 -0
- data/modules/mu/clouds/azure/vpc.rb +782 -0
- data/modules/mu/clouds/cloudformation.rb +12 -9
- data/modules/mu/clouds/cloudformation/firewall_rule.rb +5 -13
- data/modules/mu/clouds/cloudformation/server.rb +10 -1
- data/modules/mu/clouds/cloudformation/server_pool.rb +1 -0
- data/modules/mu/clouds/cloudformation/vpc.rb +0 -2
- data/modules/mu/clouds/google.rb +554 -117
- data/modules/mu/clouds/google/bucket.rb +173 -32
- data/modules/mu/clouds/google/container_cluster.rb +1112 -157
- data/modules/mu/clouds/google/database.rb +24 -47
- data/modules/mu/clouds/google/firewall_rule.rb +344 -89
- data/modules/mu/clouds/google/folder.rb +156 -79
- data/modules/mu/clouds/google/group.rb +272 -82
- data/modules/mu/clouds/google/habitat.rb +177 -52
- data/modules/mu/clouds/google/loadbalancer.rb +9 -34
- data/modules/mu/clouds/google/role.rb +1211 -0
- data/modules/mu/clouds/google/server.rb +491 -227
- data/modules/mu/clouds/google/server_pool.rb +233 -48
- data/modules/mu/clouds/google/user.rb +479 -125
- data/modules/mu/clouds/google/userdata/linux.erb +3 -3
- data/modules/mu/clouds/google/userdata/windows.erb +9 -9
- data/modules/mu/clouds/google/vpc.rb +381 -223
- data/modules/mu/config.rb +689 -214
- data/modules/mu/config/bucket.rb +1 -1
- data/modules/mu/config/cache_cluster.rb +1 -1
- data/modules/mu/config/cache_cluster.yml +0 -4
- data/modules/mu/config/container_cluster.rb +18 -9
- data/modules/mu/config/database.rb +6 -23
- data/modules/mu/config/firewall_rule.rb +9 -15
- data/modules/mu/config/folder.rb +22 -21
- data/modules/mu/config/habitat.rb +22 -21
- data/modules/mu/config/loadbalancer.rb +2 -2
- data/modules/mu/config/role.rb +9 -40
- data/modules/mu/config/server.rb +26 -5
- data/modules/mu/config/server_pool.rb +1 -1
- data/modules/mu/config/storage_pool.rb +2 -2
- data/modules/mu/config/user.rb +4 -0
- data/modules/mu/config/vpc.rb +350 -110
- data/modules/mu/defaults/{amazon_images.yaml → AWS.yaml} +37 -39
- data/modules/mu/defaults/Azure.yaml +17 -0
- data/modules/mu/defaults/Google.yaml +24 -0
- data/modules/mu/defaults/README.md +1 -1
- data/modules/mu/deploy.rb +168 -125
- data/modules/mu/groomer.rb +2 -1
- data/modules/mu/groomers/ansible.rb +104 -32
- data/modules/mu/groomers/chef.rb +96 -44
- data/modules/mu/kittens.rb +20602 -0
- data/modules/mu/logger.rb +38 -11
- data/modules/mu/master.rb +90 -8
- data/modules/mu/master/chef.rb +2 -3
- data/modules/mu/master/ldap.rb +0 -1
- data/modules/mu/master/ssl.rb +250 -0
- data/modules/mu/mommacat.rb +917 -513
- data/modules/scratchpad.erb +1 -1
- data/modules/tests/super_complex_bok.yml +0 -0
- data/modules/tests/super_simple_bok.yml +0 -0
- data/roles/mu-master.json +2 -1
- data/spec/azure_creds +5 -0
- data/spec/mu.yaml +56 -0
- data/spec/mu/clouds/azure_spec.rb +164 -27
- data/spec/spec_helper.rb +5 -0
- data/test/clean_up.py +0 -0
- data/test/exec_inspec.py +0 -0
- data/test/exec_mu_install.py +0 -0
- data/test/exec_retry.py +0 -0
- data/test/smoke_test.rb +0 -0
- metadata +90 -118
- data/cookbooks/mu-jenkins/Berksfile +0 -14
- data/cookbooks/mu-jenkins/CHANGELOG.md +0 -13
- data/cookbooks/mu-jenkins/LICENSE +0 -37
- data/cookbooks/mu-jenkins/README.md +0 -105
- data/cookbooks/mu-jenkins/attributes/default.rb +0 -42
- data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +0 -73
- data/cookbooks/mu-jenkins/files/default/deploy_config.xml +0 -44
- data/cookbooks/mu-jenkins/metadata.rb +0 -21
- data/cookbooks/mu-jenkins/recipes/default.rb +0 -195
- data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +0 -54
- data/cookbooks/mu-jenkins/recipes/public_key.rb +0 -24
- data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +0 -24
- data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +0 -14
- data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +0 -6
- data/cookbooks/nagios/Berksfile +0 -11
- data/cookbooks/nagios/CHANGELOG.md +0 -589
- data/cookbooks/nagios/CONTRIBUTING.md +0 -11
- data/cookbooks/nagios/LICENSE +0 -37
- data/cookbooks/nagios/README.md +0 -328
- data/cookbooks/nagios/TESTING.md +0 -2
- data/cookbooks/nagios/attributes/config.rb +0 -171
- data/cookbooks/nagios/attributes/default.rb +0 -228
- data/cookbooks/nagios/chefignore +0 -102
- data/cookbooks/nagios/definitions/command.rb +0 -33
- data/cookbooks/nagios/definitions/contact.rb +0 -33
- data/cookbooks/nagios/definitions/contactgroup.rb +0 -33
- data/cookbooks/nagios/definitions/host.rb +0 -33
- data/cookbooks/nagios/definitions/hostdependency.rb +0 -33
- data/cookbooks/nagios/definitions/hostescalation.rb +0 -34
- data/cookbooks/nagios/definitions/hostgroup.rb +0 -33
- data/cookbooks/nagios/definitions/nagios_conf.rb +0 -38
- data/cookbooks/nagios/definitions/resource.rb +0 -33
- data/cookbooks/nagios/definitions/service.rb +0 -33
- data/cookbooks/nagios/definitions/servicedependency.rb +0 -33
- data/cookbooks/nagios/definitions/serviceescalation.rb +0 -34
- data/cookbooks/nagios/definitions/servicegroup.rb +0 -33
- data/cookbooks/nagios/definitions/timeperiod.rb +0 -33
- data/cookbooks/nagios/libraries/base.rb +0 -314
- data/cookbooks/nagios/libraries/command.rb +0 -91
- data/cookbooks/nagios/libraries/contact.rb +0 -230
- data/cookbooks/nagios/libraries/contactgroup.rb +0 -112
- data/cookbooks/nagios/libraries/custom_option.rb +0 -36
- data/cookbooks/nagios/libraries/data_bag_helper.rb +0 -23
- data/cookbooks/nagios/libraries/default.rb +0 -90
- data/cookbooks/nagios/libraries/host.rb +0 -412
- data/cookbooks/nagios/libraries/hostdependency.rb +0 -181
- data/cookbooks/nagios/libraries/hostescalation.rb +0 -173
- data/cookbooks/nagios/libraries/hostgroup.rb +0 -119
- data/cookbooks/nagios/libraries/nagios.rb +0 -282
- data/cookbooks/nagios/libraries/resource.rb +0 -59
- data/cookbooks/nagios/libraries/service.rb +0 -455
- data/cookbooks/nagios/libraries/servicedependency.rb +0 -215
- data/cookbooks/nagios/libraries/serviceescalation.rb +0 -195
- data/cookbooks/nagios/libraries/servicegroup.rb +0 -144
- data/cookbooks/nagios/libraries/timeperiod.rb +0 -160
- data/cookbooks/nagios/libraries/users_helper.rb +0 -54
- data/cookbooks/nagios/metadata.rb +0 -25
- data/cookbooks/nagios/recipes/_load_databag_config.rb +0 -153
- data/cookbooks/nagios/recipes/_load_default_config.rb +0 -241
- data/cookbooks/nagios/recipes/apache.rb +0 -48
- data/cookbooks/nagios/recipes/default.rb +0 -204
- data/cookbooks/nagios/recipes/nginx.rb +0 -82
- data/cookbooks/nagios/recipes/pagerduty.rb +0 -143
- data/cookbooks/nagios/recipes/server_package.rb +0 -40
- data/cookbooks/nagios/recipes/server_source.rb +0 -164
- data/cookbooks/nagios/templates/default/apache2.conf.erb +0 -96
- data/cookbooks/nagios/templates/default/cgi.cfg.erb +0 -266
- data/cookbooks/nagios/templates/default/commands.cfg.erb +0 -13
- data/cookbooks/nagios/templates/default/contacts.cfg.erb +0 -37
- data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +0 -25
- data/cookbooks/nagios/templates/default/hosts.cfg.erb +0 -15
- data/cookbooks/nagios/templates/default/htpasswd.users.erb +0 -6
- data/cookbooks/nagios/templates/default/nagios.cfg.erb +0 -22
- data/cookbooks/nagios/templates/default/nginx.conf.erb +0 -62
- data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +0 -185
- data/cookbooks/nagios/templates/default/resource.cfg.erb +0 -27
- data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +0 -15
- data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +0 -14
- data/cookbooks/nagios/templates/default/services.cfg.erb +0 -14
- data/cookbooks/nagios/templates/default/templates.cfg.erb +0 -31
- data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +0 -13
- data/extras/image-generators/aws/centos6.yaml +0 -18
- data/modules/mu/defaults/google_images.yaml +0 -16
- data/roles/mu-master-jenkins.json +0 -24
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
# Copyright:: Copyright (c) 2019 eGlobalTech, Inc., all rights reserved
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the BSD-3 license (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License in the root of the project or at
|
|
6
|
+
#
|
|
7
|
+
# http://egt-labs.com/mu/LICENSE.html
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
module MU
|
|
16
|
+
class Cloud
|
|
17
|
+
class Azure
|
|
18
|
+
|
|
19
|
+
# Creation of Virtual Private Clouds and associated artifacts (routes, subnets, etc).
|
|
20
|
+
class VPC < MU::Cloud::VPC
|
|
21
|
+
attr_reader :cloud_desc_cache
|
|
22
|
+
attr_reader :resource_group
|
|
23
|
+
|
|
24
|
+
# Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like <tt>@vpc</tt>, for us.
|
|
25
|
+
# @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
|
|
26
|
+
def initialize(**args)
|
|
27
|
+
super
|
|
28
|
+
@subnets = []
|
|
29
|
+
@subnetcachesemaphore = Mutex.new
|
|
30
|
+
|
|
31
|
+
if !mu_name.nil?
|
|
32
|
+
@mu_name = mu_name
|
|
33
|
+
if @cloud_id
|
|
34
|
+
cloud_desc
|
|
35
|
+
@cloud_id = Id.new(cloud_desc.id)
|
|
36
|
+
@resource_group ||= @cloud_id.resource_group
|
|
37
|
+
loadSubnets(use_cache: true)
|
|
38
|
+
end
|
|
39
|
+
elsif @config['scrub_mu_isms']
|
|
40
|
+
@mu_name = @config['name']
|
|
41
|
+
else
|
|
42
|
+
@mu_name = @deploy.getResourceName(@config['name'])
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Called automatically by {MU::Deploy#createResources}
|
|
47
|
+
def create
|
|
48
|
+
create_update
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# Called automatically by {MU::Deploy#createResources}
|
|
53
|
+
def groom
|
|
54
|
+
|
|
55
|
+
if @config['peers']
|
|
56
|
+
count = 0
|
|
57
|
+
@config['peers'].each { |peer|
|
|
58
|
+
if peer['vpc']['name']
|
|
59
|
+
peer_obj = @deploy.findLitterMate(name: peer['vpc']['name'], type: "vpcs", habitat: peer['vpc']['project'])
|
|
60
|
+
next if peer_obj.mu_name < @mu_name # both of us would try to create this peering, otherwise, so don't step on each other
|
|
61
|
+
else
|
|
62
|
+
tag_key, tag_value = peer['vpc']['tag'].split(/=/, 2) if !peer['vpc']['tag'].nil?
|
|
63
|
+
if peer['vpc']['deploy_id'].nil? and peer['vpc']['id'].nil? and tag_key.nil?
|
|
64
|
+
peer['vpc']['deploy_id'] = @deploy.deploy_id
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
peer_obj = MU::MommaCat.findStray(
|
|
68
|
+
"Azure",
|
|
69
|
+
"vpcs",
|
|
70
|
+
deploy_id: peer['vpc']['deploy_id'],
|
|
71
|
+
cloud_id: peer['vpc']['id'],
|
|
72
|
+
name: peer['vpc']['name'],
|
|
73
|
+
tag_key: tag_key,
|
|
74
|
+
tag_value: tag_value,
|
|
75
|
+
dummy_ok: true
|
|
76
|
+
).first
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
raise MuError, "No result looking for #{@mu_name}'s peer VPCs (#{peer['vpc']})" if peer_obj.nil?
|
|
80
|
+
|
|
81
|
+
ext_peerings = MU::Cloud::Azure.network(credentials: @credentials).virtual_network_peerings.list(@resource_group, @cloud_id)
|
|
82
|
+
peer_name = @mu_name+"-"+@config['name'].upcase+"-"+peer_obj.config['name'].upcase
|
|
83
|
+
peer_params = MU::Cloud::Azure.network(:VirtualNetworkPeering).new
|
|
84
|
+
peer_params.remote_virtual_network = peer_obj.cloud_desc
|
|
85
|
+
peer['allow_forwarded_traffic'] ||= false
|
|
86
|
+
peer_params.allow_forwarded_traffic = peer['allow_forwarded_traffic']
|
|
87
|
+
peer['allow_gateway_traffic'] ||= false
|
|
88
|
+
peer_params.allow_gateway_transit = peer['allow_gateway_traffic']
|
|
89
|
+
|
|
90
|
+
need_update = true
|
|
91
|
+
exists = false
|
|
92
|
+
ext_peerings.each { |ext_peering|
|
|
93
|
+
if ext_peering.remote_virtual_network.id == peer_obj.cloud_desc.id
|
|
94
|
+
exists = true
|
|
95
|
+
need_update = (ext_peering.allow_forwarded_traffic != peer_params.allow_forwarded_traffic or ext_peering.allow_gateway_transit != peer_params.allow_gateway_transit)
|
|
96
|
+
end
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if need_update
|
|
100
|
+
if !exists
|
|
101
|
+
MU.log "Creating peering connection from #{@mu_name} to #{peer_obj.mu_name}", details: peer_params
|
|
102
|
+
else
|
|
103
|
+
MU.log "Updating peering connection from #{@mu_name} to #{peer_obj.mu_name}", MU::NOTICE, details: peer_params
|
|
104
|
+
end
|
|
105
|
+
MU::Cloud::Azure.network(credentials: @credentials).virtual_network_peerings.create_or_update(@resource_group, @cloud_id, peer_name, peer_params)
|
|
106
|
+
end
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
create_update
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Describe this VPC
|
|
114
|
+
# @return [Hash]
|
|
115
|
+
def notify
|
|
116
|
+
base = {}
|
|
117
|
+
base = MU.structToHash(cloud_desc)
|
|
118
|
+
base["cloud_id"] = @cloud_id.name
|
|
119
|
+
base.merge!(@config.to_h)
|
|
120
|
+
base
|
|
121
|
+
end
|
|
122
|
+
#
|
|
123
|
+
# Describe this VPC from the cloud platform's perspective
|
|
124
|
+
# @return [Hash]
|
|
125
|
+
def cloud_desc
|
|
126
|
+
if @cloud_desc_cache
|
|
127
|
+
return @cloud_desc_cache
|
|
128
|
+
end
|
|
129
|
+
@cloud_desc_cache = MU::Cloud::Azure::VPC.find(cloud_id: @cloud_id, resource_group: @resource_group).values.first
|
|
130
|
+
|
|
131
|
+
@cloud_id ||= Id.new(@cloud_desc_cache.id)
|
|
132
|
+
@cloud_desc_cache
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Locate and return cloud provider descriptors of this resource type
|
|
136
|
+
# which match the provided parameters, or all visible resources if no
|
|
137
|
+
# filters are specified. At minimum, implementations of +find+ must
|
|
138
|
+
# honor +credentials+ and +cloud_id+ arguments. We may optionally
|
|
139
|
+
# support other search methods, such as +tag_key+ and +tag_value+, or
|
|
140
|
+
# cloud-specific arguments like +project+. See also {MU::MommaCat.findStray}.
|
|
141
|
+
# @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
|
|
142
|
+
# @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching resources
|
|
143
|
+
def self.find(**args)
|
|
144
|
+
found = {}
|
|
145
|
+
|
|
146
|
+
# Azure resources are namedspaced by resource group. If we weren't
|
|
147
|
+
# told one, we may have to search all the ones we can see.
|
|
148
|
+
resource_groups = if args[:resource_group]
|
|
149
|
+
[args[:resource_group]]
|
|
150
|
+
elsif args[:cloud_id] and args[:cloud_id].is_a?(MU::Cloud::Azure::Id)
|
|
151
|
+
[args[:cloud_id].resource_group]
|
|
152
|
+
else
|
|
153
|
+
MU::Cloud::Azure.resources(credentials: args[:credentials]).resource_groups.list.map { |rg| rg.name }
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
if args[:cloud_id]
|
|
157
|
+
id_str = args[:cloud_id].is_a?(MU::Cloud::Azure::Id) ? args[:cloud_id].name : args[:cloud_id]
|
|
158
|
+
resource_groups.each { |rg|
|
|
159
|
+
resp = MU::Cloud::Azure.network(credentials: args[:credentials]).virtual_networks.get(rg, id_str)
|
|
160
|
+
|
|
161
|
+
found[Id.new(resp.id)] = resp if resp
|
|
162
|
+
}
|
|
163
|
+
else
|
|
164
|
+
if args[:resource_group]
|
|
165
|
+
MU::Cloud::Azure.network(credentials: args[:credentials]).virtual_networks.list(args[:resource_group]).each { |net|
|
|
166
|
+
found[Id.new(net.id)] = net
|
|
167
|
+
}
|
|
168
|
+
else
|
|
169
|
+
MU::Cloud::Azure.network(credentials: args[:credentials]).virtual_networks.list_all.each { |net|
|
|
170
|
+
found[Id.new(net.id)] = net
|
|
171
|
+
}
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
found
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Return an array of MU::Cloud::Azure::VPC::Subnet objects describe the
|
|
179
|
+
# member subnets of this VPC.
|
|
180
|
+
#
|
|
181
|
+
# @return [Array<MU::Cloud::Azure::VPC::Subnet>]
|
|
182
|
+
def subnets
|
|
183
|
+
if @subnets.nil? or @subnets.size == 0
|
|
184
|
+
return loadSubnets
|
|
185
|
+
end
|
|
186
|
+
return @subnets
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Describe subnets associated with this VPC. We'll compose identifying
|
|
190
|
+
# information similar to what MU::Cloud.describe builds for first-class
|
|
191
|
+
# resources.
|
|
192
|
+
# @param use_cache [Boolean]: If available, use saved deployment metadata to describe subnets, instead of querying the cloud API
|
|
193
|
+
# @return [Array<Hash>]: A list of cloud provider identifiers of subnets associated with this VPC.
|
|
194
|
+
def loadSubnets(use_cache: false)
|
|
195
|
+
desc = cloud_desc
|
|
196
|
+
@subnets = []
|
|
197
|
+
|
|
198
|
+
MU::Cloud::Azure.network(credentials: @credentials).subnets.list(@resource_group, cloud_desc.name).each { |subnet|
|
|
199
|
+
subnet_cfg = {
|
|
200
|
+
"cloud_id" => subnet.name,
|
|
201
|
+
"mu_name" => subnet.name,
|
|
202
|
+
"credentials" => @config['credentials'],
|
|
203
|
+
"region" => @config['region'],
|
|
204
|
+
"ip_block" => subnet.address_prefix
|
|
205
|
+
}
|
|
206
|
+
if @config['subnets']
|
|
207
|
+
@config['subnets'].each { |s|
|
|
208
|
+
if s['ip_block'] == subnet_cfg['ip_block']
|
|
209
|
+
subnet_cfg['name'] = s['name']
|
|
210
|
+
break
|
|
211
|
+
end
|
|
212
|
+
}
|
|
213
|
+
end
|
|
214
|
+
subnet_cfg['name'] ||= subnet.name
|
|
215
|
+
@subnets << MU::Cloud::Azure::VPC::Subnet.new(self, subnet_cfg)
|
|
216
|
+
}
|
|
217
|
+
@subnets
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Given some search criteria try locating a NAT Gaateway in this VPC.
|
|
221
|
+
# @param nat_cloud_id [String]: The cloud provider's identifier for this NAT.
|
|
222
|
+
# @param nat_filter_key [String]: A cloud provider filter to help identify the resource, used in conjunction with nat_filter_value.
|
|
223
|
+
# @param nat_filter_value [String]: A cloud provider filter to help identify the resource, used in conjunction with nat_filter_key.
|
|
224
|
+
# @param region [String]: The cloud provider region of the target instance.
|
|
225
|
+
def findNat(nat_cloud_id: nil, nat_filter_key: nil, nat_filter_value: nil, region: MU.curRegion)
|
|
226
|
+
nil
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Given some search criteria for a {MU::Cloud::Server}, see if we can
|
|
230
|
+
# locate a NAT host in this VPC.
|
|
231
|
+
# @param nat_name [String]: The name of the resource as defined in its 'name' Basket of Kittens field, typically used in conjunction with deploy_id.
|
|
232
|
+
# @param nat_cloud_id [String]: The cloud provider's identifier for this NAT.
|
|
233
|
+
# @param nat_tag_key [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_value.
|
|
234
|
+
# @param nat_tag_value [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_key.
|
|
235
|
+
# @param nat_ip [String]: An IP address associated with the NAT instance.
|
|
236
|
+
def findBastion(nat_name: nil, nat_cloud_id: nil, nat_tag_key: nil, nat_tag_value: nil, nat_ip: nil)
|
|
237
|
+
[:nat_name, :nat_cloud_id, :nat_tag_key, :nat_tag_value, :nat_ip].each { |var|
|
|
238
|
+
if binding.local_variable_get(var) != nil
|
|
239
|
+
binding.local_variable_set(var, var.to_s)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# If we're searching by name, assume it's part of this here deploy.
|
|
243
|
+
if nat_cloud_id.nil? and !@deploy.nil?
|
|
244
|
+
deploy_id = @deploy.deploy_id
|
|
245
|
+
end
|
|
246
|
+
found = MU::MommaCat.findStray(
|
|
247
|
+
"Azure",
|
|
248
|
+
"server",
|
|
249
|
+
name: nat_name,
|
|
250
|
+
cloud_id: nat_cloud_id,
|
|
251
|
+
deploy_id: deploy_id,
|
|
252
|
+
tag_key: nat_tag_key,
|
|
253
|
+
tag_value: nat_tag_value,
|
|
254
|
+
allow_multi: true,
|
|
255
|
+
dummy_ok: true,
|
|
256
|
+
calling_deploy: @deploy
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
return nil if found.nil? || found.empty?
|
|
260
|
+
if found.size == 1
|
|
261
|
+
return found.first
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
nil
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Check for a subnet in this VPC matching one or more of the specified
|
|
269
|
+
# criteria, and return it if found.
|
|
270
|
+
def getSubnet(cloud_id: nil, name: nil, tag_key: nil, tag_value: nil, ip_block: nil)
|
|
271
|
+
loadSubnets
|
|
272
|
+
if !cloud_id.nil? and cloud_id.match(/^https:\/\//)
|
|
273
|
+
cloud_id.gsub!(/.*?\//, "")
|
|
274
|
+
end
|
|
275
|
+
MU.log "getSubnet(cloud_id: #{cloud_id}, name: #{name}, tag_key: #{tag_key}, tag_value: #{tag_value}, ip_block: #{ip_block})", MU::DEBUG, details: caller[0]
|
|
276
|
+
|
|
277
|
+
@subnets.each { |subnet|
|
|
278
|
+
if !cloud_id.nil? and !subnet.cloud_id.nil? and subnet.cloud_id.to_s == cloud_id.to_s
|
|
279
|
+
return subnet
|
|
280
|
+
elsif !name.nil? and !subnet.name.nil? and subnet.name.to_s == name.to_s
|
|
281
|
+
return subnet
|
|
282
|
+
end
|
|
283
|
+
}
|
|
284
|
+
return nil
|
|
285
|
+
end
|
|
286
|
+
@route_cache = {}
|
|
287
|
+
@rtb_cache = {}
|
|
288
|
+
@rtb_cache_semaphore = Mutex.new
|
|
289
|
+
# Check whether we (the Mu Master) have a direct route to a particular
|
|
290
|
+
# instance. Useful for skipping hops through bastion hosts to get
|
|
291
|
+
# directly at child nodes in peered VPCs, the public internet, and the
|
|
292
|
+
# like.
|
|
293
|
+
# @param target_instance [OpenStruct]: The cloud descriptor of the instance to check.
|
|
294
|
+
# @param region [String]: The cloud provider region of the target subnet.
|
|
295
|
+
# @return [Boolean]
|
|
296
|
+
def self.haveRouteToInstance?(target_instance, region: MU.curRegion, credentials: nil)
|
|
297
|
+
|
|
298
|
+
# target_instance.network_profile.network_interfaces.each { |iface|
|
|
299
|
+
# iface_id = Id.new(iface.is_a?(Hash) ? iface['id'] : iface.id)
|
|
300
|
+
# iface_desc = MU::Cloud::Azure.network(credentials: credentials).network_interfaces.get(iface_id.resource_group, iface_id.to_s)
|
|
301
|
+
# iface_desc.ip_configurations.each { |ipcfg|
|
|
302
|
+
# if ipcfg.respond_to?(:public_ipaddress) and ipcfg.public_ipaddress
|
|
303
|
+
# return true # XXX invalid if Mu can't talk to the internet
|
|
304
|
+
# end
|
|
305
|
+
# }
|
|
306
|
+
# }
|
|
307
|
+
|
|
308
|
+
return false if MU.myCloud != "Azure"
|
|
309
|
+
# XXX if we're in Azure, see if this is in our VPC or if we're peered to its VPC
|
|
310
|
+
false
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
# Does this resource type exist as a global (cloud-wide) artifact, or
|
|
315
|
+
# is it localized to a region/zone?
|
|
316
|
+
# @return [Boolean]
|
|
317
|
+
def self.isGlobal?
|
|
318
|
+
false
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Denote whether this resource implementation is experiment, ready for
|
|
322
|
+
# testing, or ready for production use.
|
|
323
|
+
def self.quality
|
|
324
|
+
MU::Cloud::BETA
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Stub method. Azure resources are cleaned up by removing the parent
|
|
328
|
+
# resource group.
|
|
329
|
+
# @return [void]
|
|
330
|
+
def self.cleanup(**args)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Reverse-map our cloud description into a runnable config hash.
|
|
334
|
+
# We assume that any values we have in +@config+ are placeholders, and
|
|
335
|
+
# calculate our own accordingly based on what's live in the cloud.
|
|
336
|
+
# XXX add flag to return the diff between @config and live cloud
|
|
337
|
+
def toKitten(rootparent: nil, billing: nil)
|
|
338
|
+
return nil if cloud_desc.name == "default" # parent project builds these
|
|
339
|
+
bok = {
|
|
340
|
+
"cloud" => "Azure",
|
|
341
|
+
"project" => @config['project'],
|
|
342
|
+
"credentials" => @config['credentials']
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
bok
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Cloud-specific configuration properties.
|
|
349
|
+
# @param config [MU::Config]: The calling MU::Config object
|
|
350
|
+
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
|
351
|
+
def self.schema(config = nil)
|
|
352
|
+
toplevel_required = []
|
|
353
|
+
schema = {
|
|
354
|
+
"peers" => {
|
|
355
|
+
"items" => {
|
|
356
|
+
"properties" => {
|
|
357
|
+
"allow_forwarded_traffic" => {
|
|
358
|
+
"type" => "boolean",
|
|
359
|
+
"default" => false,
|
|
360
|
+
"description" => "Allow traffic originating from outside peered networks"
|
|
361
|
+
},
|
|
362
|
+
"allow_gateway_traffic" => {
|
|
363
|
+
"type" => "boolean",
|
|
364
|
+
"default" => false,
|
|
365
|
+
"description" => "Permit peered networks to use each others' VPN gateways"
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
[toplevel_required, schema]
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# Cloud-specific pre-processing of {MU::Config::BasketofKittens::vpcs}, bare and unvalidated.
|
|
376
|
+
# @param vpc [Hash]: The resource to process and validate
|
|
377
|
+
# @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
378
|
+
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
379
|
+
def self.validateConfig(vpc, configurator)
|
|
380
|
+
ok = true
|
|
381
|
+
vpc['region'] ||= MU::Cloud::Azure.myRegion(vpc['credentials'])
|
|
382
|
+
|
|
383
|
+
if vpc['subnets']
|
|
384
|
+
vpc['subnets'].each { |subnet|
|
|
385
|
+
subnet_routes[subnet['route_table']] = Array.new if subnet_routes[subnet['route_table']].nil?
|
|
386
|
+
subnet_routes[subnet['route_table']] << subnet['name']
|
|
387
|
+
}
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
if (!vpc['subnets'] or vpc['subnets'].empty?) and vpc['create_standard_subnets']
|
|
391
|
+
subnets = configurator.divideNetwork(vpc['ip_block'], vpc['route_tables'].size, 28)
|
|
392
|
+
vpc['subnets'] ||= []
|
|
393
|
+
vpc['route_tables'].each { |rtb|
|
|
394
|
+
is_public = false
|
|
395
|
+
rtb['routes'].each { |route|
|
|
396
|
+
if route['gateway'] == "#INTERNET"
|
|
397
|
+
is_public = true
|
|
398
|
+
break
|
|
399
|
+
end
|
|
400
|
+
}
|
|
401
|
+
vpc['subnets'] << {
|
|
402
|
+
"name" => "Subnet#{rtb['name'].capitalize}",
|
|
403
|
+
"is_public" => is_public,
|
|
404
|
+
"ip_block" => subnets.shift,
|
|
405
|
+
"route_table" => rtb['name']
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
vpc['route_tables'].each { |rtb|
|
|
411
|
+
rtb['routes'] ||= []
|
|
412
|
+
rtb['routes'] << { "destination_network" => vpc['ip_block'] }
|
|
413
|
+
rtb['routes'].uniq!
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
default_acl = {
|
|
417
|
+
"name" => vpc['name']+"-defaultfw",
|
|
418
|
+
"cloud" => "Azure",
|
|
419
|
+
"region" => vpc['region'],
|
|
420
|
+
"credentials" => vpc['credentials'],
|
|
421
|
+
"rules" => [
|
|
422
|
+
{
|
|
423
|
+
"ingress" => true, "proto" => "all", "hosts" => [vpc['ip_block']]
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"egress" => true, "proto" => "all", "hosts" => [vpc['ip_block']]
|
|
427
|
+
}
|
|
428
|
+
]
|
|
429
|
+
}
|
|
430
|
+
vpc["dependencies"] ||= []
|
|
431
|
+
vpc["dependencies"] << {
|
|
432
|
+
"type" => "firewall_rule",
|
|
433
|
+
"name" => vpc['name']+"-defaultfw"
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if !configurator.insertKitten(default_acl, "firewall_rules", true)
|
|
437
|
+
ok = false
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
ok
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# @param route [Hash]: A route description, per the Basket of Kittens schema
|
|
444
|
+
# @param server [MU::Cloud::Azure::Server]: Instance to which this route will apply
|
|
445
|
+
def createRouteForInstance(route, server)
|
|
446
|
+
createRoute(route, network: @url, tags: [MU::Cloud::Azure.nameStr(server.mu_name)])
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
private
|
|
450
|
+
|
|
451
|
+
def create_update
|
|
452
|
+
@config = MU::Config.manxify(@config)
|
|
453
|
+
@config['region'] ||= MU::Cloud::Azure.myRegion(@config['credentials'])
|
|
454
|
+
tags = {}
|
|
455
|
+
if !@config['scrub_mu_isms']
|
|
456
|
+
tags = MU::MommaCat.listStandardTags
|
|
457
|
+
end
|
|
458
|
+
if @config['tags']
|
|
459
|
+
@config['tags'].each { |tag|
|
|
460
|
+
tags[tag['key']] = tag['value']
|
|
461
|
+
}
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
vpc_obj = MU::Cloud::Azure.network(:VirtualNetwork).new
|
|
465
|
+
addr_space_obj = MU::Cloud::Azure.network(:AddressSpace).new
|
|
466
|
+
addr_space_obj.address_prefixes = [
|
|
467
|
+
@config['ip_block']
|
|
468
|
+
]
|
|
469
|
+
vpc_obj.address_space = addr_space_obj
|
|
470
|
+
vpc_obj.location = @config['region']
|
|
471
|
+
vpc_obj.tags = tags
|
|
472
|
+
|
|
473
|
+
my_fw = deploy.findLitterMate(type: "firewall_rule", name: @config['name']+"-defaultfw")
|
|
474
|
+
|
|
475
|
+
@resource_group = @deploy.deploy_id+"-"+@config['region'].upcase
|
|
476
|
+
|
|
477
|
+
need_apply = false
|
|
478
|
+
ext_vpc = nil
|
|
479
|
+
begin
|
|
480
|
+
ext_vpc = MU::Cloud::Azure.network(credentials: @config['credentials']).virtual_networks.get(
|
|
481
|
+
@resource_group,
|
|
482
|
+
@mu_name
|
|
483
|
+
)
|
|
484
|
+
rescue ::MU::Cloud::Azure::APIError => e
|
|
485
|
+
if e.message.match(/: ResourceNotFound:/)
|
|
486
|
+
need_apply = true
|
|
487
|
+
else
|
|
488
|
+
raise e
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
# XXX raw update seems to destroy child resources; if we just need to update
|
|
492
|
+
# tags, do that with .update_tags
|
|
493
|
+
if !ext_vpc
|
|
494
|
+
MU.log "Creating VPC #{@mu_name} (#{@config['ip_block']}) in #{@config['region']}", details: vpc_obj
|
|
495
|
+
need_apply = true
|
|
496
|
+
elsif ext_vpc.location != vpc_obj.location or
|
|
497
|
+
ext_vpc.tags != vpc_obj.tags or
|
|
498
|
+
ext_vpc.address_space.address_prefixes != vpc_obj.address_space.address_prefixes
|
|
499
|
+
MU.log "Updating VPC #{@mu_name} (#{@config['ip_block']}) in #{@config['region']}", MU::NOTICE, details: vpc_obj
|
|
500
|
+
need_apply = true
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
if need_apply
|
|
504
|
+
resp = MU::Cloud::Azure.network(credentials: @config['credentials']).virtual_networks.create_or_update(
|
|
505
|
+
@resource_group,
|
|
506
|
+
@mu_name,
|
|
507
|
+
vpc_obj
|
|
508
|
+
)
|
|
509
|
+
@cloud_id = Id.new(resp.id)
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
# this is slow, so maybe thread it
|
|
513
|
+
rtb_map = {}
|
|
514
|
+
routethreads = []
|
|
515
|
+
create_nat_gateway = false
|
|
516
|
+
@config['route_tables'].each { |rtb_cfg|
|
|
517
|
+
routethreads << Thread.new(rtb_cfg) { |rtb|
|
|
518
|
+
rtb_name = @mu_name+"-"+rtb['name'].upcase
|
|
519
|
+
rtb_obj = MU::Cloud::Azure.network(:RouteTable).new
|
|
520
|
+
rtb_obj.location = @config['region']
|
|
521
|
+
|
|
522
|
+
rtb_obj.tags = tags
|
|
523
|
+
rtb_ref_obj = MU::Cloud::Azure.network(:RouteTable).new
|
|
524
|
+
rtb_ref_obj.name = rtb_name
|
|
525
|
+
rtb_map[rtb['name']] = rtb_ref_obj
|
|
526
|
+
|
|
527
|
+
need_apply = false
|
|
528
|
+
ext_rtb = nil
|
|
529
|
+
begin
|
|
530
|
+
ext_rtb = MU::Cloud::Azure.network(credentials: @config['credentials']).route_tables.get(
|
|
531
|
+
@resource_group,
|
|
532
|
+
rtb_name
|
|
533
|
+
)
|
|
534
|
+
rtb_map[rtb['name']] = ext_rtb
|
|
535
|
+
rescue MU::Cloud::Azure::APIError => e
|
|
536
|
+
if e.message.match(/: ResourceNotFound:/)
|
|
537
|
+
need_apply = true
|
|
538
|
+
else
|
|
539
|
+
raise e
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
if !ext_rtb
|
|
544
|
+
MU.log "Creating route table #{rtb_name} in VPC #{@mu_name}", details: rtb_obj
|
|
545
|
+
need_apply = true
|
|
546
|
+
elsif ext_rtb.location != rtb_obj.location or
|
|
547
|
+
ext_rtb.tags != rtb_obj.tags
|
|
548
|
+
need_apply = true
|
|
549
|
+
MU.log "Updating route table #{rtb_name} in VPC #{@mu_name}", MU::NOTICE, details: rtb_obj
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
if need_apply
|
|
553
|
+
rtb_map[rtb['name']] = MU::Cloud::Azure.network(credentials: @config['credentials']).route_tables.create_or_update(
|
|
554
|
+
@resource_group,
|
|
555
|
+
rtb_name,
|
|
556
|
+
rtb_obj
|
|
557
|
+
)
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
rtb['routes'].each { |route|
|
|
561
|
+
route_obj = MU::Cloud::Azure.network(:Route).new
|
|
562
|
+
route_obj.address_prefix = route['destination_network']
|
|
563
|
+
routename = rtb_name+"-"+route['destination_network'].gsub(/[^a-z0-9]/i, "_")
|
|
564
|
+
route_obj.next_hop_type = if route['gateway'] == "#NAT" and @config['bastion']
|
|
565
|
+
routename = rtb_name+"-NAT"
|
|
566
|
+
bastion_ref = MU::Config::Ref.get(@config['bastion'])
|
|
567
|
+
if bastion_ref.kitten and bastion_ref.kitten.cloud_desc
|
|
568
|
+
iface_id = Id.new(bastion_ref.kitten.cloud_desc.network_profile.network_interfaces.first.id)
|
|
569
|
+
iface_desc = MU::Cloud::Azure.network(credentials: @credentials).network_interfaces.get(@resource_group, iface_id.name)
|
|
570
|
+
if iface_desc and iface_desc.ip_configurations and iface_desc.ip_configurations.size > 0
|
|
571
|
+
route_obj.next_hop_ip_address = iface_desc.ip_configurations.first.private_ipaddress
|
|
572
|
+
"VirtualAppliance"
|
|
573
|
+
else
|
|
574
|
+
"VnetLocal"
|
|
575
|
+
end
|
|
576
|
+
else
|
|
577
|
+
"VnetLocal"
|
|
578
|
+
end
|
|
579
|
+
# create_nat_gateway = true
|
|
580
|
+
elsif route['gateway'] == "#INTERNET"
|
|
581
|
+
routename = rtb_name+"-INTERNET"
|
|
582
|
+
"Internet"
|
|
583
|
+
else
|
|
584
|
+
routename = rtb_name+"-LOCAL"
|
|
585
|
+
"VnetLocal"
|
|
586
|
+
end
|
|
587
|
+
#next_hop_type 'VirtualNetworkGateway' is for VPNs I think
|
|
588
|
+
|
|
589
|
+
need_apply = false
|
|
590
|
+
ext_route = nil
|
|
591
|
+
begin
|
|
592
|
+
ext_route = MU::Cloud::Azure.network(credentials: @config['credentials']).routes.get(
|
|
593
|
+
@resource_group,
|
|
594
|
+
rtb_name,
|
|
595
|
+
routename
|
|
596
|
+
)
|
|
597
|
+
rescue MU::Cloud::Azure::APIError => e
|
|
598
|
+
if e.message.match(/\bNotFound\b/)
|
|
599
|
+
need_apply = true
|
|
600
|
+
else
|
|
601
|
+
raise e
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
if !ext_route
|
|
606
|
+
MU.log "Creating route #{routename} for #{route['destination_network']} in route table #{rtb_name}", details: rtb_obj
|
|
607
|
+
need_apply = true
|
|
608
|
+
elsif ext_route.next_hop_type != route_obj.next_hop_type or
|
|
609
|
+
ext_route.address_prefix != route_obj.address_prefix
|
|
610
|
+
MU.log "Updating route #{routename} for #{route['destination_network']} in route table #{rtb_name}", MU::NOTICE, details: [route_obj, ext_route]
|
|
611
|
+
need_apply = true
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
if need_apply
|
|
615
|
+
MU::Cloud::Azure.network(credentials: @config['credentials']).routes.create_or_update(
|
|
616
|
+
@resource_group,
|
|
617
|
+
rtb_name,
|
|
618
|
+
routename,
|
|
619
|
+
route_obj
|
|
620
|
+
)
|
|
621
|
+
end
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
routethreads.each { |t|
|
|
627
|
+
t.join
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
# TODO this is only available in westus as of 2019-09-29
|
|
631
|
+
# if create_nat_gateway
|
|
632
|
+
# nat_obj = MU::Cloud::Azure.network(:NatGateway).new
|
|
633
|
+
# nat_obj.location = @config['region']
|
|
634
|
+
# nat_obj.tags = tags
|
|
635
|
+
# MU.log "Creating NAT Gateway #{@mu_name}-NAT", details: nat_obj
|
|
636
|
+
# MU::Cloud::Azure.network(credentials: @config['credentials']).nat_gateways.create_or_update(
|
|
637
|
+
# @resource_group,
|
|
638
|
+
# @mu_name+"-NAT",
|
|
639
|
+
# nat_obj
|
|
640
|
+
# )
|
|
641
|
+
# end
|
|
642
|
+
|
|
643
|
+
if @config['subnets']
|
|
644
|
+
subnetthreads = []
|
|
645
|
+
@config['subnets'].each { |subnet_cfg|
|
|
646
|
+
subnetthreads << Thread.new(subnet_cfg) { |subnet|
|
|
647
|
+
subnet_obj = MU::Cloud::Azure.network(:Subnet).new
|
|
648
|
+
subnet_name = @mu_name+"-"+subnet['name'].upcase
|
|
649
|
+
subnet_obj.address_prefix = subnet['ip_block']
|
|
650
|
+
subnet_obj.route_table = rtb_map[subnet['route_table']]
|
|
651
|
+
if my_fw and my_fw.cloud_desc
|
|
652
|
+
subnet_obj.network_security_group = my_fw.cloud_desc
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
need_apply = false
|
|
656
|
+
ext_subnet = nil
|
|
657
|
+
begin
|
|
658
|
+
ext_subnet = MU::Cloud::Azure.network(credentials: @config['credentials']).subnets.get(
|
|
659
|
+
@resource_group,
|
|
660
|
+
@cloud_id.to_s,
|
|
661
|
+
subnet_name
|
|
662
|
+
)
|
|
663
|
+
rescue APIError => e
|
|
664
|
+
if e.message.match(/\bNotFound\b/)
|
|
665
|
+
need_apply = true
|
|
666
|
+
else
|
|
667
|
+
# raise e
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
if !ext_subnet
|
|
672
|
+
MU.log "Creating Subnet #{subnet_name} in VPC #{@mu_name}", details: subnet_obj
|
|
673
|
+
need_apply = true
|
|
674
|
+
elsif (!ext_subnet.route_table.nil? and !subnet_obj.route_table.nil? and ext_subnet.route_table.id != subnet_obj.route_table.id) or
|
|
675
|
+
ext_subnet.address_prefix != subnet_obj.address_prefix or
|
|
676
|
+
ext_subnet.network_security_group.nil? and !subnet_obj.network_security_group.nil? or
|
|
677
|
+
(!ext_subnet.network_security_group.nil? and !subnet_obj.network_security_group.nil? and ext_subnet.network_security_group.id != subnet_obj.network_security_group.id)
|
|
678
|
+
MU.log "Updating Subnet #{subnet_name} in VPC #{@mu_name}", MU::NOTICE, details: subnet_obj
|
|
679
|
+
need_apply = true
|
|
680
|
+
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
if need_apply
|
|
684
|
+
MU::Cloud::Azure.network(credentials: @config['credentials']).subnets.create_or_update(
|
|
685
|
+
@resource_group,
|
|
686
|
+
@cloud_id.to_s,
|
|
687
|
+
subnet_name,
|
|
688
|
+
subnet_obj
|
|
689
|
+
)
|
|
690
|
+
end
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
subnetthreads.each { |t|
|
|
695
|
+
t.join
|
|
696
|
+
}
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
loadSubnets
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
protected
|
|
703
|
+
|
|
704
|
+
# Subnets are almost a first-class resource. So let's kinda sorta treat
|
|
705
|
+
# them like one. This should only be invoked on objects that already
|
|
706
|
+
# exists in the cloud layer.
|
|
707
|
+
class Subnet < MU::Cloud::Azure::VPC
|
|
708
|
+
|
|
709
|
+
attr_reader :cloud_id
|
|
710
|
+
attr_reader :id
|
|
711
|
+
attr_reader :ip_block
|
|
712
|
+
attr_reader :mu_name
|
|
713
|
+
attr_reader :name
|
|
714
|
+
attr_reader :cloud_desc_cache
|
|
715
|
+
attr_reader :resource_group
|
|
716
|
+
attr_reader :az
|
|
717
|
+
|
|
718
|
+
# @param parent [MU::Cloud::Azure::VPC]: The parent VPC of this subnet.
|
|
719
|
+
# @param config [Hash<String>]:
|
|
720
|
+
def initialize(parent, config, precache_description: true)
|
|
721
|
+
@parent = parent
|
|
722
|
+
@deploy = parent.deploy
|
|
723
|
+
@config = MU::Config.manxify(config)
|
|
724
|
+
@cloud_id = config['cloud_id']
|
|
725
|
+
@mu_name = config['mu_name']
|
|
726
|
+
@name = config['name']
|
|
727
|
+
@deploydata = config # This is a dummy for the sake of describe()
|
|
728
|
+
@ip_block = config['ip_block']
|
|
729
|
+
@cloud_desc_cache = nil
|
|
730
|
+
@az = parent.config['region']
|
|
731
|
+
cloud_desc if precache_description
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
# Return the cloud identifier for the default route of this subnet.
|
|
735
|
+
def defaultRoute
|
|
736
|
+
if cloud_desc and cloud_desc.route_table
|
|
737
|
+
rtb_id = MU::Cloud::Azure::Id.new(cloud_desc.route_table.id)
|
|
738
|
+
routes = MU::Cloud::Azure.network(credentials: @config['credentials']).routes.list(
|
|
739
|
+
rtb_id.resource_group,
|
|
740
|
+
rtb_id.name
|
|
741
|
+
)
|
|
742
|
+
routes.each { |route|
|
|
743
|
+
return route if route.address_prefix == "0.0.0.0/0"
|
|
744
|
+
}
|
|
745
|
+
end
|
|
746
|
+
nil
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
# Describe this VPC Subnet
|
|
750
|
+
# @return [Hash]
|
|
751
|
+
def notify
|
|
752
|
+
MU.structToHash(cloud_desc)
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
# Describe this VPC Subnet from the cloud platform's perspective
|
|
756
|
+
def cloud_desc
|
|
757
|
+
return @cloud_desc_cache if !@cloud_desc_cache.nil?
|
|
758
|
+
@cloud_desc_cache = MU::Cloud::Azure.network(credentials: @parent.credentials).subnets.get(@parent.resource_group, @parent.cloud_desc.name, @cloud_id.to_s)
|
|
759
|
+
@cloud_desc_cache
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
# Is this subnet privately-routable only, or public?
|
|
763
|
+
# @return [Boolean]
|
|
764
|
+
def private?
|
|
765
|
+
if cloud_desc and cloud_desc.route_table
|
|
766
|
+
rtb_id = MU::Cloud::Azure::Id.new(cloud_desc.route_table.id)
|
|
767
|
+
routes = MU::Cloud::Azure.network(credentials: @config['credentials']).routes.list(
|
|
768
|
+
rtb_id.resource_group,
|
|
769
|
+
rtb_id.name
|
|
770
|
+
)
|
|
771
|
+
routes.each { |route|
|
|
772
|
+
return false if route.next_hop_type == "Internet"
|
|
773
|
+
}
|
|
774
|
+
true
|
|
775
|
+
end
|
|
776
|
+
end
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
end #class
|
|
780
|
+
end #class
|
|
781
|
+
end
|
|
782
|
+
end #module
|