cloud-mu 1.9.0.pre.beta
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 +7 -0
- data/Berksfile +56 -0
- data/Berksfile.lock +250 -0
- data/Jenkinsfile +184 -0
- data/LICENSE.md +37 -0
- data/README.md +26 -0
- data/bin/mu-aws-setup +376 -0
- data/bin/mu-cleanup +68 -0
- data/bin/mu-configure +1133 -0
- data/bin/mu-deploy +166 -0
- data/bin/mu-firewall-allow-clients +30 -0
- data/bin/mu-gcp-setup +200 -0
- data/bin/mu-gen-docs +34 -0
- data/bin/mu-gen-env +42 -0
- data/bin/mu-load-config.rb +158 -0
- data/bin/mu-node-manage +683 -0
- data/bin/mu-self-update +228 -0
- data/bin/mu-ssh +23 -0
- data/bin/mu-tunnel-nagios +144 -0
- data/bin/mu-upload-chef-artifacts +757 -0
- data/bin/mu-user-manage +275 -0
- data/cookbooks/awscli/LICENSE +37 -0
- data/cookbooks/awscli/README.md +58 -0
- data/cookbooks/awscli/attributes/default.rb +1 -0
- data/cookbooks/awscli/libraries/instance_metadata.rb +21 -0
- data/cookbooks/awscli/metadata.rb +20 -0
- data/cookbooks/awscli/recipes/default.rb +56 -0
- data/cookbooks/awscli/templates/default/config.erb +18 -0
- data/cookbooks/mu-activedirectory/CHANGELOG.md +13 -0
- data/cookbooks/mu-activedirectory/LICENSE +37 -0
- data/cookbooks/mu-activedirectory/README.md +6 -0
- data/cookbooks/mu-activedirectory/attributes/default.rb +98 -0
- data/cookbooks/mu-activedirectory/files/default/password-auth +32 -0
- data/cookbooks/mu-activedirectory/files/default/sshd_pol.pp +0 -0
- data/cookbooks/mu-activedirectory/files/default/sshd_pol.te +32 -0
- data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.pp +0 -0
- data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.te +10 -0
- data/cookbooks/mu-activedirectory/files/default/system-auth +34 -0
- data/cookbooks/mu-activedirectory/files/default/winbindpol.pp +0 -0
- data/cookbooks/mu-activedirectory/files/default/winbindpol.te +37 -0
- data/cookbooks/mu-activedirectory/libraries/config.rb +106 -0
- data/cookbooks/mu-activedirectory/libraries/helper.rb +86 -0
- data/cookbooks/mu-activedirectory/metadata.rb +17 -0
- data/cookbooks/mu-activedirectory/providers/domain.rb +152 -0
- data/cookbooks/mu-activedirectory/providers/domain_controller.rb +89 -0
- data/cookbooks/mu-activedirectory/providers/domain_node.rb +275 -0
- data/cookbooks/mu-activedirectory/recipes/default.rb +8 -0
- data/cookbooks/mu-activedirectory/recipes/domain-controller.rb +44 -0
- data/cookbooks/mu-activedirectory/recipes/domain-node.rb +50 -0
- data/cookbooks/mu-activedirectory/recipes/domain.rb +43 -0
- data/cookbooks/mu-activedirectory/recipes/sssd.rb +185 -0
- data/cookbooks/mu-activedirectory/resources/domain.rb +25 -0
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +25 -0
- data/cookbooks/mu-activedirectory/resources/domain_node.rb +20 -0
- data/cookbooks/mu-activedirectory/templates/default/dhclient-eth0.conf.erb +4 -0
- data/cookbooks/mu-activedirectory/templates/default/interface +0 -0
- data/cookbooks/mu-activedirectory/templates/default/krb5.conf.erb +23 -0
- data/cookbooks/mu-activedirectory/templates/default/ntp.conf.erb +56 -0
- data/cookbooks/mu-activedirectory/templates/default/smb.conf.erb +33 -0
- data/cookbooks/mu-activedirectory/templates/default/sssd.conf.erb +60 -0
- data/cookbooks/mu-activedirectory/templates/windows/Backup.xml.erb +20 -0
- data/cookbooks/mu-activedirectory/templates/windows/bkupInfo.xml.erb +1 -0
- data/cookbooks/mu-activedirectory/templates/windows/gpreprt.xml.erb +198 -0
- data/cookbooks/mu-activedirectory/templates/windows/gptmpl.inf.erb +12 -0
- data/cookbooks/mu-activedirectory/templates/windows/manifest.xml.erb +1 -0
- data/cookbooks/mu-firewall/CHANGELOG.md +11 -0
- data/cookbooks/mu-firewall/LICENSE +37 -0
- data/cookbooks/mu-firewall/README.md +5 -0
- data/cookbooks/mu-firewall/attributes/default.rb +3 -0
- data/cookbooks/mu-firewall/metadata.rb +16 -0
- data/cookbooks/mu-firewall/recipes/default.rb +10 -0
- data/cookbooks/mu-glusterfs/CHANGELOG.md +13 -0
- data/cookbooks/mu-glusterfs/LICENSE +37 -0
- data/cookbooks/mu-glusterfs/README.md +5 -0
- data/cookbooks/mu-glusterfs/attributes/default.rb +34 -0
- data/cookbooks/mu-glusterfs/metadata.rb +17 -0
- data/cookbooks/mu-glusterfs/recipes/client.rb +62 -0
- data/cookbooks/mu-glusterfs/recipes/default.rb +16 -0
- data/cookbooks/mu-glusterfs/recipes/samba.rb +57 -0
- data/cookbooks/mu-glusterfs/recipes/server.rb +200 -0
- data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +71 -0
- data/cookbooks/mu-glusterfs/templates/default/smb.conf.erb +14 -0
- data/cookbooks/mu-jenkins/CHANGELOG.md +13 -0
- data/cookbooks/mu-jenkins/LICENSE +37 -0
- data/cookbooks/mu-jenkins/README.md +105 -0
- data/cookbooks/mu-jenkins/attributes/default.rb +42 -0
- data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +73 -0
- data/cookbooks/mu-jenkins/files/default/deploy_config.xml +44 -0
- data/cookbooks/mu-jenkins/metadata.rb +21 -0
- data/cookbooks/mu-jenkins/recipes/default.rb +195 -0
- data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +54 -0
- data/cookbooks/mu-jenkins/recipes/public_key.rb +24 -0
- data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +24 -0
- data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +14 -0
- data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +6 -0
- data/cookbooks/mu-master/CHANGELOG.md +13 -0
- data/cookbooks/mu-master/LICENSE +37 -0
- data/cookbooks/mu-master/README.md +6 -0
- data/cookbooks/mu-master/attributes/default.rb +95 -0
- data/cookbooks/mu-master/files/default/0-mu-log-server.conf +19 -0
- data/cookbooks/mu-master/files/default/addRSA.ldif +8 -0
- data/cookbooks/mu-master/files/default/check_mem.pl +197 -0
- data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
- data/cookbooks/mu-master/files/default/dirsrv_admin.pp +0 -0
- data/cookbooks/mu-master/files/default/dirsrv_admin.te +13 -0
- data/cookbooks/mu-master/files/default/nagios_selinux.pp +0 -0
- data/cookbooks/mu-master/files/default/nagios_selinux.te +51 -0
- data/cookbooks/mu-master/files/default/nagios_selinux_7.pp +0 -0
- data/cookbooks/mu-master/files/default/nagios_selinux_7.te +17 -0
- data/cookbooks/mu-master/files/default/pam_sshd +18 -0
- data/cookbooks/mu-master/files/default/ssl_enable.ldif +18 -0
- data/cookbooks/mu-master/files/default/syslogd_oddjobd.pp +0 -0
- data/cookbooks/mu-master/files/default/syslogd_oddjobd.te +10 -0
- data/cookbooks/mu-master/files/default/vimrc +19 -0
- data/cookbooks/mu-master/libraries/mu.rb +29 -0
- data/cookbooks/mu-master/metadata.rb +30 -0
- data/cookbooks/mu-master/providers/user.rb +41 -0
- data/cookbooks/mu-master/recipes/389ds.rb +164 -0
- data/cookbooks/mu-master/recipes/basepackages.rb +58 -0
- data/cookbooks/mu-master/recipes/caching_nameserver.rb +37 -0
- data/cookbooks/mu-master/recipes/default.rb +451 -0
- data/cookbooks/mu-master/recipes/eks-kubectl.rb +41 -0
- data/cookbooks/mu-master/recipes/firewall-holes.rb +70 -0
- data/cookbooks/mu-master/recipes/init.rb +542 -0
- data/cookbooks/mu-master/recipes/ssl-certs.rb +109 -0
- data/cookbooks/mu-master/recipes/sssd.rb +89 -0
- data/cookbooks/mu-master/recipes/update_nagios_only.rb +242 -0
- data/cookbooks/mu-master/recipes/vault.rb +111 -0
- data/cookbooks/mu-master/resources/user.rb +19 -0
- data/cookbooks/mu-master/templates/default/389-directory-setup.inf.erb +28 -0
- data/cookbooks/mu-master/templates/default/chef-server.rb.erb +18 -0
- data/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb +9 -0
- data/cookbooks/mu-master/templates/default/mu-momma-cat.erb +149 -0
- data/cookbooks/mu-master/templates/default/mu.rc.erb +9 -0
- data/cookbooks/mu-master/templates/default/openssl.cnf.erb +354 -0
- data/cookbooks/mu-master/templates/default/sssd.conf.erb +44 -0
- data/cookbooks/mu-master/templates/default/web_app.conf.erb +90 -0
- data/cookbooks/mu-mongo/CHANGELOG.md +13 -0
- data/cookbooks/mu-mongo/LICENSE +37 -0
- data/cookbooks/mu-mongo/README.md +5 -0
- data/cookbooks/mu-mongo/attributes/default.rb +22 -0
- data/cookbooks/mu-mongo/files/default/keyfile +16 -0
- data/cookbooks/mu-mongo/files/default/remove_nodes.js +5 -0
- data/cookbooks/mu-mongo/metadata.rb +17 -0
- data/cookbooks/mu-mongo/recipes/default.rb +149 -0
- data/cookbooks/mu-mongo/recipes/yum-update-rule.rb +18 -0
- data/cookbooks/mu-mongo/templates/default/mongo_create_openfema_db.js.erb +2 -0
- data/cookbooks/mu-mongo/templates/default/mongo_init.js.erb +1 -0
- data/cookbooks/mu-mongo/templates/default/mongo_logrotate.erb +14 -0
- data/cookbooks/mu-mongo/templates/default/mongo_replset_addnodes.js.erb +6 -0
- data/cookbooks/mu-mongo/templates/default/replset_init.js.erb +2 -0
- data/cookbooks/mu-openvpn/CHANGELOG.md +13 -0
- data/cookbooks/mu-openvpn/LICENSE +37 -0
- data/cookbooks/mu-openvpn/README.md +6 -0
- data/cookbooks/mu-openvpn/attributes/default.rb +119 -0
- data/cookbooks/mu-openvpn/metadata.rb +18 -0
- data/cookbooks/mu-openvpn/recipes/default.rb +108 -0
- data/cookbooks/mu-openvpn/templates/default/users.json.erb +42 -0
- data/cookbooks/mu-php54/CHANGELOG.md +12 -0
- data/cookbooks/mu-php54/LICENSE +37 -0
- data/cookbooks/mu-php54/README.md +0 -0
- data/cookbooks/mu-php54/files/centos/php.ini +1802 -0
- data/cookbooks/mu-php54/files/ubuntu/php.ini +1870 -0
- data/cookbooks/mu-php54/metadata.rb +21 -0
- data/cookbooks/mu-php54/recipes/default.rb +97 -0
- data/cookbooks/mu-splunk/CHANGELOG.md +37 -0
- data/cookbooks/mu-splunk/LICENSE +37 -0
- data/cookbooks/mu-splunk/README.md +451 -0
- data/cookbooks/mu-splunk/attributes/default.rb +95 -0
- data/cookbooks/mu-splunk/attributes/upgrade.rb +49 -0
- data/cookbooks/mu-splunk/definitions/splunk_installer.rb +103 -0
- data/cookbooks/mu-splunk/files/default/splunk-nocheck +10 -0
- data/cookbooks/mu-splunk/libraries/helpers.rb +72 -0
- data/cookbooks/mu-splunk/libraries/splunk_app_provider.rb +156 -0
- data/cookbooks/mu-splunk/libraries/splunk_app_resource.rb +43 -0
- data/cookbooks/mu-splunk/metadata.json +30 -0
- data/cookbooks/mu-splunk/metadata.rb +17 -0
- data/cookbooks/mu-splunk/recipes/client.rb +143 -0
- data/cookbooks/mu-splunk/recipes/default.rb +31 -0
- data/cookbooks/mu-splunk/recipes/disabled.rb +41 -0
- data/cookbooks/mu-splunk/recipes/install_forwarder.rb +23 -0
- data/cookbooks/mu-splunk/recipes/install_server.rb +23 -0
- data/cookbooks/mu-splunk/recipes/server.rb +53 -0
- data/cookbooks/mu-splunk/recipes/service.rb +95 -0
- data/cookbooks/mu-splunk/recipes/setup_auth.rb +49 -0
- data/cookbooks/mu-splunk/recipes/setup_ssl.rb +63 -0
- data/cookbooks/mu-splunk/recipes/upgrade.rb +94 -0
- data/cookbooks/mu-splunk/recipes/user.rb +34 -0
- data/cookbooks/mu-splunk/templates/default/base_logs_unix_inputs.conf.erb +26 -0
- data/cookbooks/mu-splunk/templates/default/inputs.conf.erb +13 -0
- data/cookbooks/mu-splunk/templates/default/outputs.conf.erb +9 -0
- data/cookbooks/mu-splunk/templates/default/splunk-init.erb +74 -0
- data/cookbooks/mu-splunk/templates/default/system-web.conf.erb +7 -0
- data/cookbooks/mu-tools/CHANGELOG.md +12 -0
- data/cookbooks/mu-tools/LICENSE +37 -0
- data/cookbooks/mu-tools/README.md +188 -0
- data/cookbooks/mu-tools/attributes/default.rb +142 -0
- data/cookbooks/mu-tools/attributes/ebs_rolling_snapshots.rb +3 -0
- data/cookbooks/mu-tools/files/amazon/etc/freshclam.conf +235 -0
- data/cookbooks/mu-tools/files/centos/CentOS-Base.repo +52 -0
- data/cookbooks/mu-tools/files/centos/etc/bashrc +93 -0
- data/cookbooks/mu-tools/files/centos/etc/freshclam.conf +235 -0
- data/cookbooks/mu-tools/files/centos/etc/login.defs +72 -0
- data/cookbooks/mu-tools/files/centos/etc/profile +77 -0
- data/cookbooks/mu-tools/files/centos/etc/security/limits.conf +57 -0
- data/cookbooks/mu-tools/files/centos/etc/sysconfig/init +19 -0
- data/cookbooks/mu-tools/files/centos/etc/sysctl.conf +82 -0
- data/cookbooks/mu-tools/files/centos-6/README_MU +0 -0
- data/cookbooks/mu-tools/files/centos-6/etc/audit/stig.rules +173 -0
- data/cookbooks/mu-tools/files/centos-6/etc/bashrc +90 -0
- data/cookbooks/mu-tools/files/centos-6/etc/login.defs +70 -0
- data/cookbooks/mu-tools/files/centos-6/etc/pam.d/su +12 -0
- data/cookbooks/mu-tools/files/centos-6/etc/profile +83 -0
- data/cookbooks/mu-tools/files/centos-6/etc/securetty +12 -0
- data/cookbooks/mu-tools/files/centos-6/etc/sysconfig/init +30 -0
- data/cookbooks/mu-tools/files/centos-6/etc/sysctl.conf +40 -0
- data/cookbooks/mu-tools/files/default/Mu_CA.pem +34 -0
- data/cookbooks/mu-tools/files/default/PSWindowsUpdate.zip +0 -0
- data/cookbooks/mu-tools/files/default/ebs_snapshots.py +123 -0
- data/cookbooks/mu-tools/files/default/etc/BANNER +0 -0
- data/cookbooks/mu-tools/files/default/etc/BANNER-FEDERAL +19 -0
- data/cookbooks/mu-tools/files/default/gpo_no_uac.zip +0 -0
- data/cookbooks/mu-tools/files/default/mypol.pp +0 -0
- data/cookbooks/mu-tools/files/default/mypol.te +37 -0
- data/cookbooks/mu-tools/files/default/nrpe_c7.pp +0 -0
- data/cookbooks/mu-tools/files/default/nrpe_c7.te +31 -0
- data/cookbooks/mu-tools/files/default/nrpe_check_disk.pp +0 -0
- data/cookbooks/mu-tools/files/default/nrpe_check_disk.te +11 -0
- data/cookbooks/mu-tools/files/default/nrpe_disk.pp +0 -0
- data/cookbooks/mu-tools/files/default/nrpe_disk.te +10 -0
- data/cookbooks/mu-tools/files/default/nrpe_file.pp +0 -0
- data/cookbooks/mu-tools/files/default/nrpe_file.te +31 -0
- data/cookbooks/mu-tools/files/default/ntrights +0 -0
- data/cookbooks/mu-tools/files/default/serverclass.conf +18 -0
- data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/app.conf +1 -0
- data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/inputs.conf +13 -0
- data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/app.conf +1 -0
- data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/inputs.conf +8 -0
- data/cookbooks/mu-tools/files/default/sshd_pol.pp +0 -0
- data/cookbooks/mu-tools/files/default/sshd_pol.te +32 -0
- data/cookbooks/mu-tools/files/redhat/etc/bashrc +93 -0
- data/cookbooks/mu-tools/files/redhat/etc/freshclam.conf +235 -0
- data/cookbooks/mu-tools/files/redhat/etc/login.defs +72 -0
- data/cookbooks/mu-tools/files/redhat/etc/profile +77 -0
- data/cookbooks/mu-tools/files/redhat/etc/security/limits.conf +57 -0
- data/cookbooks/mu-tools/files/redhat/etc/sysconfig/init +19 -0
- data/cookbooks/mu-tools/files/redhat/etc/sysctl.conf +82 -0
- data/cookbooks/mu-tools/files/redhat-6/README_MU +0 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/audit/stig.rules +173 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/bashrc +90 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/login.defs +70 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/pam.d/su +12 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/profile +83 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/securetty +12 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/sysconfig/init +30 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/sysctl.conf +40 -0
- data/cookbooks/mu-tools/files/redhat-7.1/etc/freshclam.conf +235 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/bash.bashrc +64 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/common-session +30 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/login.defs +338 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/profile +30 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/security/limits.conf +56 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/sysctl.conf +60 -0
- data/cookbooks/mu-tools/libraries/helper.rb +292 -0
- data/cookbooks/mu-tools/metadata.rb +28 -0
- data/cookbooks/mu-tools/recipes/add_admin_ssh_keys.rb +35 -0
- data/cookbooks/mu-tools/recipes/apply_security.rb +440 -0
- data/cookbooks/mu-tools/recipes/aws_api.rb +23 -0
- data/cookbooks/mu-tools/recipes/base_repositories.rb +31 -0
- data/cookbooks/mu-tools/recipes/cisbenchmark.rb +59 -0
- data/cookbooks/mu-tools/recipes/clamav.rb +53 -0
- data/cookbooks/mu-tools/recipes/cloudinit.rb +58 -0
- data/cookbooks/mu-tools/recipes/configure_oracle_tools.rb +81 -0
- data/cookbooks/mu-tools/recipes/disable-requiretty.rb +22 -0
- data/cookbooks/mu-tools/recipes/ebs_rolling_snapshots.rb +75 -0
- data/cookbooks/mu-tools/recipes/efs.rb +70 -0
- data/cookbooks/mu-tools/recipes/eks.rb +160 -0
- data/cookbooks/mu-tools/recipes/gcloud.rb +98 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +25 -0
- data/cookbooks/mu-tools/recipes/maldet.rb +67 -0
- data/cookbooks/mu-tools/recipes/nagios.rb +19 -0
- data/cookbooks/mu-tools/recipes/newclient.rb +23 -0
- data/cookbooks/mu-tools/recipes/nrpe.rb +115 -0
- data/cookbooks/mu-tools/recipes/python_pip.rb +35 -0
- data/cookbooks/mu-tools/recipes/retrieve_application.rb +51 -0
- data/cookbooks/mu-tools/recipes/rsyslog.rb +65 -0
- data/cookbooks/mu-tools/recipes/set_local_fw.rb +57 -0
- data/cookbooks/mu-tools/recipes/set_mu_hostname.rb +81 -0
- data/cookbooks/mu-tools/recipes/split_var_partitions.rb +86 -0
- data/cookbooks/mu-tools/recipes/splunk-client.rb +69 -0
- data/cookbooks/mu-tools/recipes/splunk-server.rb +104 -0
- data/cookbooks/mu-tools/recipes/store_inspec_attr.rb +8 -0
- data/cookbooks/mu-tools/recipes/updates.rb +96 -0
- data/cookbooks/mu-tools/recipes/windows-client.rb +202 -0
- data/cookbooks/mu-tools/resources/aws_windows.rb +33 -0
- data/cookbooks/mu-tools/resources/disk.rb +88 -0
- data/cookbooks/mu-tools/resources/mommacat_request.rb +11 -0
- data/cookbooks/mu-tools/resources/scheduled_tasks.rb +29 -0
- data/cookbooks/mu-tools/resources/sshd_service.rb +45 -0
- data/cookbooks/mu-tools/resources/windows_users.rb +242 -0
- data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +168 -0
- data/cookbooks/mu-tools/templates/centos-6/sshd_config.erb +212 -0
- data/cookbooks/mu-tools/templates/centos-7/sshd_config.erb +215 -0
- data/cookbooks/mu-tools/templates/default/0-mu-log-client.conf.erb +13 -0
- data/cookbooks/mu-tools/templates/default/conf.maldet.erb +137 -0
- data/cookbooks/mu-tools/templates/default/etc_hosts.erb +30 -0
- data/cookbooks/mu-tools/templates/default/etc_pamd_password-auth.erb +14 -0
- data/cookbooks/mu-tools/templates/default/etc_pamd_system-auth.erb +14 -0
- data/cookbooks/mu-tools/templates/default/etc_sysconfig_network.erb +12 -0
- data/cookbooks/mu-tools/templates/default/kubeconfig.erb +29 -0
- data/cookbooks/mu-tools/templates/default/kubelet.service.erb +35 -0
- data/cookbooks/mu-tools/templates/default/maldet_scanall.sh.erb +15 -0
- data/cookbooks/mu-tools/templates/default/nrpe.cfg.erb +233 -0
- data/cookbooks/mu-tools/templates/redhat-6/sshd_config.erb +213 -0
- data/cookbooks/mu-tools/templates/redhat-7/sshd_config.erb +215 -0
- data/cookbooks/mu-tools/templates/ubuntu-12.04/sshd_config.erb +146 -0
- data/cookbooks/mu-tools/templates/ubuntu-14.04/sshd_config.erb +145 -0
- data/cookbooks/mu-tools/templates/windows/Backup.xml.erb +20 -0
- data/cookbooks/mu-tools/templates/windows/bkupInfo.xml.erb +1 -0
- data/cookbooks/mu-tools/templates/windows/gpreprt.xml.erb +214 -0
- data/cookbooks/mu-tools/templates/windows/gptmpl.inf.erb +12 -0
- data/cookbooks/mu-tools/templates/windows/manifest.xml.erb +1 -0
- data/cookbooks/mu-tools/templates/windows/set_ad_dns_scheduled_task.ps1.erb +6 -0
- data/cookbooks/mu-tools/templates/windows/sshd_config.erb +136 -0
- data/cookbooks/mu-utility/CHANGELOG.md +12 -0
- data/cookbooks/mu-utility/LICENSE +37 -0
- data/cookbooks/mu-utility/README.md +6 -0
- data/cookbooks/mu-utility/attributes/default.rb +1 -0
- data/cookbooks/mu-utility/libraries/matchers.rb +21 -0
- data/cookbooks/mu-utility/metadata.rb +16 -0
- data/cookbooks/mu-utility/recipes/apt.rb +23 -0
- data/cookbooks/mu-utility/recipes/cleanup_image_helper.rb +118 -0
- data/cookbooks/mu-utility/recipes/iptables.rb +26 -0
- data/cookbooks/mu-utility/recipes/luks.rb +18 -0
- data/cookbooks/mu-utility/recipes/nat.rb +104 -0
- data/cookbooks/mu-utility/recipes/php.rb +33 -0
- data/cookbooks/mu-utility/recipes/rdp_gateway.rb +83 -0
- data/cookbooks/mu-utility/recipes/remi.rb +44 -0
- data/cookbooks/mu-utility/recipes/vim.rb +26 -0
- data/cookbooks/mu-utility/recipes/windows_basics.rb +37 -0
- data/cookbooks/mu-utility/recipes/zip.rb +26 -0
- data/cookbooks/mu-utility/templates/default/BundleConfig.xml.erb +34 -0
- data/cookbooks/mu-utility/templates/default/config.xml.erb +60 -0
- data/cookbooks/nagios/Berksfile +8 -0
- data/cookbooks/nagios/CHANGELOG.md +589 -0
- data/cookbooks/nagios/CONTRIBUTING.md +11 -0
- data/cookbooks/nagios/LICENSE +37 -0
- data/cookbooks/nagios/README.md +328 -0
- data/cookbooks/nagios/TESTING.md +2 -0
- data/cookbooks/nagios/attributes/config.rb +171 -0
- data/cookbooks/nagios/attributes/default.rb +228 -0
- data/cookbooks/nagios/chefignore +102 -0
- data/cookbooks/nagios/definitions/command.rb +33 -0
- data/cookbooks/nagios/definitions/contact.rb +33 -0
- data/cookbooks/nagios/definitions/contactgroup.rb +33 -0
- data/cookbooks/nagios/definitions/host.rb +33 -0
- data/cookbooks/nagios/definitions/hostdependency.rb +33 -0
- data/cookbooks/nagios/definitions/hostescalation.rb +34 -0
- data/cookbooks/nagios/definitions/hostgroup.rb +33 -0
- data/cookbooks/nagios/definitions/nagios_conf.rb +38 -0
- data/cookbooks/nagios/definitions/resource.rb +33 -0
- data/cookbooks/nagios/definitions/service.rb +33 -0
- data/cookbooks/nagios/definitions/servicedependency.rb +33 -0
- data/cookbooks/nagios/definitions/serviceescalation.rb +34 -0
- data/cookbooks/nagios/definitions/servicegroup.rb +33 -0
- data/cookbooks/nagios/definitions/timeperiod.rb +33 -0
- data/cookbooks/nagios/libraries/base.rb +314 -0
- data/cookbooks/nagios/libraries/command.rb +91 -0
- data/cookbooks/nagios/libraries/contact.rb +230 -0
- data/cookbooks/nagios/libraries/contactgroup.rb +112 -0
- data/cookbooks/nagios/libraries/custom_option.rb +36 -0
- data/cookbooks/nagios/libraries/data_bag_helper.rb +23 -0
- data/cookbooks/nagios/libraries/default.rb +90 -0
- data/cookbooks/nagios/libraries/host.rb +412 -0
- data/cookbooks/nagios/libraries/hostdependency.rb +181 -0
- data/cookbooks/nagios/libraries/hostescalation.rb +173 -0
- data/cookbooks/nagios/libraries/hostgroup.rb +119 -0
- data/cookbooks/nagios/libraries/nagios.rb +282 -0
- data/cookbooks/nagios/libraries/resource.rb +59 -0
- data/cookbooks/nagios/libraries/service.rb +455 -0
- data/cookbooks/nagios/libraries/servicedependency.rb +215 -0
- data/cookbooks/nagios/libraries/serviceescalation.rb +195 -0
- data/cookbooks/nagios/libraries/servicegroup.rb +144 -0
- data/cookbooks/nagios/libraries/timeperiod.rb +160 -0
- data/cookbooks/nagios/libraries/users_helper.rb +54 -0
- data/cookbooks/nagios/metadata.rb +25 -0
- data/cookbooks/nagios/recipes/_load_databag_config.rb +153 -0
- data/cookbooks/nagios/recipes/_load_default_config.rb +241 -0
- data/cookbooks/nagios/recipes/apache.rb +48 -0
- data/cookbooks/nagios/recipes/default.rb +204 -0
- data/cookbooks/nagios/recipes/nginx.rb +82 -0
- data/cookbooks/nagios/recipes/pagerduty.rb +143 -0
- data/cookbooks/nagios/recipes/server_package.rb +40 -0
- data/cookbooks/nagios/recipes/server_source.rb +164 -0
- data/cookbooks/nagios/templates/default/apache2.conf.erb +96 -0
- data/cookbooks/nagios/templates/default/cgi.cfg.erb +266 -0
- data/cookbooks/nagios/templates/default/commands.cfg.erb +13 -0
- data/cookbooks/nagios/templates/default/contacts.cfg.erb +37 -0
- data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +25 -0
- data/cookbooks/nagios/templates/default/hosts.cfg.erb +15 -0
- data/cookbooks/nagios/templates/default/htpasswd.users.erb +6 -0
- data/cookbooks/nagios/templates/default/nagios.cfg.erb +22 -0
- data/cookbooks/nagios/templates/default/nginx.conf.erb +62 -0
- data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +185 -0
- data/cookbooks/nagios/templates/default/resource.cfg.erb +27 -0
- data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +15 -0
- data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +14 -0
- data/cookbooks/nagios/templates/default/services.cfg.erb +14 -0
- data/cookbooks/nagios/templates/default/templates.cfg.erb +31 -0
- data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +13 -0
- data/cookbooks/s3fs/CHANGELOG.md +13 -0
- data/cookbooks/s3fs/LICENSE +37 -0
- data/cookbooks/s3fs/README.md +6 -0
- data/cookbooks/s3fs/attributes/default.rb +15 -0
- data/cookbooks/s3fs/files/default/fuse-2.9.3.zip +0 -0
- data/cookbooks/s3fs/metadata.rb +16 -0
- data/cookbooks/s3fs/recipes/default.rb +91 -0
- data/data_bags/demo/app.json +7 -0
- data/data_bags/nagios_services/chef.json +6 -0
- data/data_bags/nagios_services/linux_diskspace.json +5 -0
- data/data_bags/nagios_services/momma_cat.json +6 -0
- data/data_bags/nagios_services/mu-master-memory.json +5 -0
- data/data_bags/nagios_services/nagios_ui.json +6 -0
- data/data_bags/nagios_services/node_ssh.json +6 -0
- data/data_bags/nagios_services/ssh.json +6 -0
- data/demo/lambda_test.yaml +29 -0
- data/environments/DEV.json +8 -0
- data/environments/PROD.json +8 -0
- data/environments/dev.json +8 -0
- data/environments/development.json +8 -0
- data/environments/prod.json +8 -0
- data/extras/README.md +1 -0
- data/extras/admin-role-binding.yaml +16 -0
- data/extras/admin-user.yaml +6 -0
- data/extras/aws-auth-cm.yaml.erb +12 -0
- data/extras/clean-stock-amis +48 -0
- data/extras/git-fix-permissions-hook +12 -0
- data/extras/gitlab-eks-helper.sh.erb +20 -0
- data/extras/image-generators/README.md +2 -0
- data/extras/image-generators/aws/centos6.yaml +18 -0
- data/extras/image-generators/aws/centos7-govcloud.yaml +24 -0
- data/extras/image-generators/aws/centos7.yaml +17 -0
- data/extras/image-generators/aws/rhel7.yaml +17 -0
- data/extras/image-generators/aws/win2k12.yaml +16 -0
- data/extras/image-generators/aws/win2k16.yaml +16 -0
- data/extras/image-generators/aws/windows.yaml +18 -0
- data/extras/image-generators/gcp/centos6.yaml +17 -0
- data/extras/lambda_waf_domain_blacklist.py +103 -0
- data/extras/platform_berksfile_base +50 -0
- data/extras/ruby_rpm/build.sh +17 -0
- data/extras/ruby_rpm/muby.spec +44 -0
- data/extras/vault_tools/README.md +6 -0
- data/extras/vault_tools/export_vaults.sh +3 -0
- data/extras/vault_tools/recreate_vaults.sh +5 -0
- data/extras/vault_tools/test_vaults.sh +5 -0
- data/install/README.md +8 -0
- data/install/cfn_create_mu_master.json +1034 -0
- data/install/chef-server.rb.erb +19 -0
- data/install/deprecated-bash-library.sh +1891 -0
- data/install/images/Usage.png +0 -0
- data/install/installer +71 -0
- data/install/jenkinskeys.rb +8 -0
- data/install/user-dot-murc.erb +14 -0
- data/modules/html.erb +19 -0
- data/modules/mommacat.ru +426 -0
- data/modules/mu/cleanup.rb +339 -0
- data/modules/mu/cloud.rb +1446 -0
- data/modules/mu/clouds/README.md +201 -0
- data/modules/mu/clouds/aws/alarm.rb +319 -0
- data/modules/mu/clouds/aws/cache_cluster.rb +1010 -0
- data/modules/mu/clouds/aws/collection.rb +373 -0
- data/modules/mu/clouds/aws/container_cluster.rb +667 -0
- data/modules/mu/clouds/aws/database.rb +1836 -0
- data/modules/mu/clouds/aws/dnszone.rb +911 -0
- data/modules/mu/clouds/aws/firewall_rule.rb +641 -0
- data/modules/mu/clouds/aws/folder.rb +92 -0
- data/modules/mu/clouds/aws/function.rb +349 -0
- data/modules/mu/clouds/aws/group.rb +251 -0
- data/modules/mu/clouds/aws/loadbalancer.rb +888 -0
- data/modules/mu/clouds/aws/log.rb +363 -0
- data/modules/mu/clouds/aws/msg_queue.rb +480 -0
- data/modules/mu/clouds/aws/notification.rb +139 -0
- data/modules/mu/clouds/aws/role.rb +656 -0
- data/modules/mu/clouds/aws/search_domain.rb +646 -0
- data/modules/mu/clouds/aws/server.rb +2294 -0
- data/modules/mu/clouds/aws/server_pool.rb +1388 -0
- data/modules/mu/clouds/aws/storage_pool.rb +495 -0
- data/modules/mu/clouds/aws/user.rb +382 -0
- data/modules/mu/clouds/aws/userdata/README.md +4 -0
- data/modules/mu/clouds/aws/userdata/linux.erb +179 -0
- data/modules/mu/clouds/aws/userdata/windows.erb +278 -0
- data/modules/mu/clouds/aws/vpc.rb +1943 -0
- data/modules/mu/clouds/aws.rb +1009 -0
- data/modules/mu/clouds/cloudformation/alarm.rb +146 -0
- data/modules/mu/clouds/cloudformation/cache_cluster.rb +167 -0
- data/modules/mu/clouds/cloudformation/collection.rb +117 -0
- data/modules/mu/clouds/cloudformation/database.rb +278 -0
- data/modules/mu/clouds/cloudformation/dnszone.rb +274 -0
- data/modules/mu/clouds/cloudformation/firewall_rule.rb +308 -0
- data/modules/mu/clouds/cloudformation/loadbalancer.rb +193 -0
- data/modules/mu/clouds/cloudformation/log.rb +170 -0
- data/modules/mu/clouds/cloudformation/server.rb +370 -0
- data/modules/mu/clouds/cloudformation/server_pool.rb +279 -0
- data/modules/mu/clouds/cloudformation/vpc.rb +322 -0
- data/modules/mu/clouds/cloudformation.rb +733 -0
- data/modules/mu/clouds/docker.rb +30 -0
- data/modules/mu/clouds/google/container_cluster.rb +290 -0
- data/modules/mu/clouds/google/database.rb +152 -0
- data/modules/mu/clouds/google/firewall_rule.rb +267 -0
- data/modules/mu/clouds/google/group.rb +164 -0
- data/modules/mu/clouds/google/loadbalancer.rb +479 -0
- data/modules/mu/clouds/google/server.rb +1510 -0
- data/modules/mu/clouds/google/server_pool.rb +274 -0
- data/modules/mu/clouds/google/user.rb +266 -0
- data/modules/mu/clouds/google/userdata/README.md +4 -0
- data/modules/mu/clouds/google/userdata/linux.erb +137 -0
- data/modules/mu/clouds/google/userdata/windows.erb +275 -0
- data/modules/mu/clouds/google/vpc.rb +890 -0
- data/modules/mu/clouds/google.rb +811 -0
- data/modules/mu/config/README.md +11 -0
- data/modules/mu/config/alarm.rb +271 -0
- data/modules/mu/config/cache_cluster.rb +172 -0
- data/modules/mu/config/collection.rb +87 -0
- data/modules/mu/config/container_cluster.rb +103 -0
- data/modules/mu/config/container_cluster.yml +36 -0
- data/modules/mu/config/database.rb +458 -0
- data/modules/mu/config/database.yml +26 -0
- data/modules/mu/config/dnszone.rb +327 -0
- data/modules/mu/config/firewall_rule.rb +118 -0
- data/modules/mu/config/folder.rb +70 -0
- data/modules/mu/config/function.rb +140 -0
- data/modules/mu/config/group.rb +64 -0
- data/modules/mu/config/loadbalancer.rb +482 -0
- data/modules/mu/config/log.rb +47 -0
- data/modules/mu/config/log.yml +6 -0
- data/modules/mu/config/msg_queue.rb +47 -0
- data/modules/mu/config/msg_queue.yml +9 -0
- data/modules/mu/config/notification.rb +44 -0
- data/modules/mu/config/project.rb +71 -0
- data/modules/mu/config/role.rb +102 -0
- data/modules/mu/config/search_domain.rb +61 -0
- data/modules/mu/config/search_domain.yml +25 -0
- data/modules/mu/config/server.rb +587 -0
- data/modules/mu/config/server.yml +8 -0
- data/modules/mu/config/server_pool.rb +216 -0
- data/modules/mu/config/server_pool.yml +71 -0
- data/modules/mu/config/storage_pool.rb +145 -0
- data/modules/mu/config/user.rb +78 -0
- data/modules/mu/config/vpc.rb +743 -0
- data/modules/mu/config/vpc.yml +6 -0
- data/modules/mu/config.rb +2000 -0
- data/modules/mu/defaults/README.md +2 -0
- data/modules/mu/defaults/amazon_images.yaml +121 -0
- data/modules/mu/defaults/google_images.yaml +16 -0
- data/modules/mu/deploy.rb +686 -0
- data/modules/mu/groomer.rb +123 -0
- data/modules/mu/groomers/README.md +58 -0
- data/modules/mu/groomers/chef.rb +1024 -0
- data/modules/mu/kittens.rb +11319 -0
- data/modules/mu/logger.rb +208 -0
- data/modules/mu/master/README.md +27 -0
- data/modules/mu/master/chef.rb +471 -0
- data/modules/mu/master/ldap.rb +1005 -0
- data/modules/mu/master.rb +415 -0
- data/modules/mu/mommacat.rb +2703 -0
- data/modules/mu-load-config.rb +1 -0
- data/modules/mu.rb +724 -0
- data/modules/scratchpad.erb +1 -0
- data/modules/tests/super_complex_bok.yml +41 -0
- data/modules/tests/super_simple_bok.yml +40 -0
- data/mu.gemspec +62 -0
- data/roles/demo-dbservice-configure.json +19 -0
- data/roles/demo-portal-configure.json +19 -0
- data/roles/mu-master-jenkins.json +24 -0
- data/roles/mu-master-nagios-only.json +13 -0
- data/roles/mu-master.json +12 -0
- data/roles/mu-node.json +19 -0
- data/roles/mu-splunk-server.json +13 -0
- data/roles/mu-splunk.json +13 -0
- data/test/clean_up.py +25 -0
- data/test/demo-test-profile/README.md +3 -0
- data/test/demo-test-profile/controls/flask.rb +84 -0
- data/test/demo-test-profile/inspec.lock +7 -0
- data/test/demo-test-profile/inspec.yml +11 -0
- data/test/etco-test-profile/README.md +3 -0
- data/test/etco-test-profile/controls/all-in-one.rb +182 -0
- data/test/etco-test-profile/inspec.lock +7 -0
- data/test/etco-test-profile/inspec.yml +11 -0
- data/test/exec_inspec.py +246 -0
- data/test/exec_mu_install.py +241 -0
- data/test/exec_retry.py +44 -0
- data/test/mu-master-test/README.md +3 -0
- data/test/mu-master-test/controls/all_in_one.rb +557 -0
- data/test/mu-master-test/inspec.lock +3 -0
- data/test/mu-master-test/inspec.yml +11 -0
- data/test/mu-tools-test/README.md +3 -0
- data/test/mu-tools-test/controls/base.rb +265 -0
- data/test/mu-tools-test/inspec.lock +3 -0
- data/test/mu-tools-test/inspec.yml +8 -0
- data/test/simple-server-php-test/README.md +3 -0
- data/test/simple-server-php-test/controls/apachephp.rb +25 -0
- data/test/simple-server-php-test/controls/example.rb +19 -0
- data/test/simple-server-php-test/inspec.lock +7 -0
- data/test/simple-server-php-test/inspec.yml +12 -0
- data/test/simple-server-rails-test/README.md +3 -0
- data/test/simple-server-rails-test/controls/rails.rb +188 -0
- data/test/simple-server-rails-test/inspec.lock +7 -0
- data/test/simple-server-rails-test/inspec.yml +11 -0
- data/test/simple-windows-test/README.md +3 -0
- data/test/simple-windows-test/controls/windows.rb +20 -0
- data/test/simple-windows-test/inspec.lock +7 -0
- data/test/simple-windows-test/inspec.yml +11 -0
- data/test/smoke_test.rb +75 -0
- data/test/wordpress-test/README.md +3 -0
- data/test/wordpress-test/controls/wordpress.rb +97 -0
- data/test/wordpress-test/inspec.lock +7 -0
- data/test/wordpress-test/inspec.yml +11 -0
- metadata +979 -0
|
@@ -0,0 +1,1943 @@
|
|
|
1
|
+
# Copyright:: Copyright (c) 2014 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 AWS
|
|
18
|
+
|
|
19
|
+
# Creation of Virtual Private Clouds and associated artifacts (routes, subnets, etc).
|
|
20
|
+
class VPC < MU::Cloud::VPC
|
|
21
|
+
|
|
22
|
+
@deploy = nil
|
|
23
|
+
@config = nil
|
|
24
|
+
attr_reader :mu_name
|
|
25
|
+
attr_reader :cloud_id
|
|
26
|
+
attr_reader :config
|
|
27
|
+
|
|
28
|
+
# @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
|
|
29
|
+
# @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::vpcs}
|
|
30
|
+
def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
|
|
31
|
+
@deploy = mommacat
|
|
32
|
+
@config = MU::Config.manxify(kitten_cfg)
|
|
33
|
+
@subnets = []
|
|
34
|
+
@subnetcachesemaphore = Mutex.new
|
|
35
|
+
@cloud_id = cloud_id
|
|
36
|
+
if !mu_name.nil?
|
|
37
|
+
@mu_name = mu_name
|
|
38
|
+
loadSubnets if !@cloud_id.nil?
|
|
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
|
+
MU.log "Creating VPC #{@mu_name}", details: @config
|
|
49
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_vpc(cidr_block: @config['ip_block']).vpc
|
|
50
|
+
vpc_id = @config['vpc_id'] = resp.vpc_id
|
|
51
|
+
|
|
52
|
+
MU::MommaCat.createStandardTags(vpc_id, region: @config['region'])
|
|
53
|
+
MU::MommaCat.createTag(vpc_id, "Name", @mu_name, region: @config['region'])
|
|
54
|
+
|
|
55
|
+
if @config['tags']
|
|
56
|
+
@config['tags'].each { |tag|
|
|
57
|
+
MU::MommaCat.createTag(vpc_id, tag['key'], tag['value'], region: @config['region'])
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if @config['optional_tags']
|
|
62
|
+
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
63
|
+
MU::MommaCat.createTag(vpc_id, key, value, region: @config['region'])
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if resp.state != "available"
|
|
68
|
+
begin
|
|
69
|
+
MU.log "Waiting for VPC #{@mu_name} (#{vpc_id}) to be available", MU::NOTICE
|
|
70
|
+
sleep 5
|
|
71
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_vpcs(vpc_ids: [vpc_id]).vpcs.first
|
|
72
|
+
end while resp.state != "available"
|
|
73
|
+
# There's a default route table that comes with. Let's tag it.
|
|
74
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
|
|
75
|
+
filters: [
|
|
76
|
+
{
|
|
77
|
+
name: "vpc-id",
|
|
78
|
+
values: [vpc_id]
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
)
|
|
82
|
+
resp.route_tables.each { |rtb|
|
|
83
|
+
MU::MommaCat.createTag(rtb.route_table_id, "Name", @mu_name+"-#DEFAULTPRIV", region: @config['region'])
|
|
84
|
+
if @config['tags']
|
|
85
|
+
@config['tags'].each { |tag|
|
|
86
|
+
MU::MommaCat.createTag(rtb.route_table_id, tag['key'], tag['value'], region: @config['region'])
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
MU::MommaCat.createStandardTags(rtb.route_table_id, region: @config['region'])
|
|
91
|
+
|
|
92
|
+
if @config['optional_tags']
|
|
93
|
+
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
94
|
+
MU::MommaCat.createTag(rtb.route_table_id, key, value, region: @config['region'])
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
}
|
|
98
|
+
end
|
|
99
|
+
@config['vpc_id'] = vpc_id
|
|
100
|
+
@cloud_id = vpc_id
|
|
101
|
+
|
|
102
|
+
if @config['create_internet_gateway']
|
|
103
|
+
MU.log "Creating Internet Gateway #{@mu_name}"
|
|
104
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_internet_gateway
|
|
105
|
+
internet_gateway_id = resp.internet_gateway.internet_gateway_id
|
|
106
|
+
sleep 5
|
|
107
|
+
MU::MommaCat.createStandardTags(internet_gateway_id, region: @config['region'])
|
|
108
|
+
MU::MommaCat.createTag(internet_gateway_id, "Name", @mu_name, region: @config['region'])
|
|
109
|
+
if @config['tags']
|
|
110
|
+
@config['tags'].each { |tag|
|
|
111
|
+
MU::MommaCat.createTag(internet_gateway_id, tag['key'], tag['value'], region: @config['region'])
|
|
112
|
+
}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
if @config['optional_tags']
|
|
116
|
+
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
117
|
+
MU::MommaCat.createTag(internet_gateway_id, key, value, region: @config['region'])
|
|
118
|
+
}
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
MU::Cloud::AWS.ec2(@config['region']).attach_internet_gateway(vpc_id: vpc_id, internet_gateway_id: internet_gateway_id)
|
|
122
|
+
@config['internet_gateway_id'] = internet_gateway_id
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
route_table_ids = []
|
|
126
|
+
if !@config['route_tables'].nil?
|
|
127
|
+
@config['route_tables'].each { |rtb|
|
|
128
|
+
rtb = createRouteTable(rtb)
|
|
129
|
+
route_table_ids << rtb['route_table_id']
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
if @config['endpoint']
|
|
134
|
+
config = {
|
|
135
|
+
:vpc_id => @cloud_id,
|
|
136
|
+
:service_name => @config['endpoint'],
|
|
137
|
+
:route_table_ids => route_table_ids
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if @config['endpoint_policy'] && !@config['endpoint_policy'].empty?
|
|
141
|
+
statement = {:Statement => @config['endpoint_policy']}
|
|
142
|
+
config[:policy_document] = statement.to_json
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_vpc_endpoint(config).vpc_endpoint
|
|
146
|
+
endpoint_id = resp.vpc_endpoint_id
|
|
147
|
+
MU.log "Creating VPC endpoint #{endpoint_id}"
|
|
148
|
+
attempts = 0
|
|
149
|
+
|
|
150
|
+
while resp.state == "pending"
|
|
151
|
+
MU.log "Waiting for VPC endpoint #{endpoint_id} to become available" if attempts % 5 == 0
|
|
152
|
+
sleep 10
|
|
153
|
+
begin
|
|
154
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint_id]).vpc_endpoints.first
|
|
155
|
+
rescue Aws::EmptyStructure, NoMethodError
|
|
156
|
+
sleep 5
|
|
157
|
+
retry
|
|
158
|
+
end
|
|
159
|
+
raise MuError, "Timed out while waiting for VPC endpoint #{endpoint_id}: #{resp}" if attempts > 30
|
|
160
|
+
attempts += 1
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
raise MuError, "VPC endpoint failed #{endpoint_id}: #{resp}" if resp.state == "failed"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
if @config["enable_traffic_logging"]
|
|
167
|
+
loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
|
|
168
|
+
logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
|
|
169
|
+
|
|
170
|
+
MU.log "Enabling traffic logging on VPC #{@mu_name} to log group #{loggroup.mu_name}"
|
|
171
|
+
MU::Cloud::AWS.ec2(@config['region']).create_flow_logs(
|
|
172
|
+
resource_ids: [@cloud_id],
|
|
173
|
+
resource_type: "VPC",
|
|
174
|
+
traffic_type: "ALL",
|
|
175
|
+
log_group_name: loggroup.mu_name,
|
|
176
|
+
deliver_logs_permission_arn: logrole.cloudobj.arn
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
nat_gateways = []
|
|
181
|
+
if !@config['subnets'].nil?
|
|
182
|
+
allocation_ids = []
|
|
183
|
+
subnet_semaphore = Mutex.new
|
|
184
|
+
subnetthreads = Array.new
|
|
185
|
+
parent_thread_id = Thread.current.object_id
|
|
186
|
+
azs = []
|
|
187
|
+
@config['subnets'].each { |subnet|
|
|
188
|
+
subnet_name = @config['name']+"-"+subnet['name']
|
|
189
|
+
MU.log "Creating Subnet #{subnet_name} (#{subnet['ip_block']})", details: subnet
|
|
190
|
+
azs = MU::Cloud::AWS.listAZs if azs.size == 0
|
|
191
|
+
if !subnet['availability_zone'].nil?
|
|
192
|
+
az = subnet['availability_zone']
|
|
193
|
+
else
|
|
194
|
+
az = azs.pop
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
subnetthreads << Thread.new {
|
|
198
|
+
MU.dupGlobals(parent_thread_id)
|
|
199
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_subnet(
|
|
200
|
+
vpc_id: vpc_id,
|
|
201
|
+
cidr_block: subnet['ip_block'],
|
|
202
|
+
availability_zone: az
|
|
203
|
+
).subnet
|
|
204
|
+
subnet_id = subnet['subnet_id'] = resp.subnet_id
|
|
205
|
+
MU::MommaCat.createStandardTags(subnet_id, region: @config['region'])
|
|
206
|
+
MU::MommaCat.createTag(subnet_id, "Name", @mu_name+"-"+subnet['name'], region: @config['region'])
|
|
207
|
+
if @config['tags']
|
|
208
|
+
@config['tags'].each { |tag|
|
|
209
|
+
MU::MommaCat.createTag(subnet_id, tag['key'], tag['value'], region: @config['region'])
|
|
210
|
+
}
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
if @config['optional_tags']
|
|
214
|
+
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
215
|
+
MU::MommaCat.createTag(subnet_id, key, value, region: @config['region'])
|
|
216
|
+
}
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
retries = 0
|
|
220
|
+
begin
|
|
221
|
+
if resp.state != "available"
|
|
222
|
+
begin
|
|
223
|
+
MU.log "Waiting for Subnet #{subnet_name} (#{subnet_id}) to be available", MU::NOTICE
|
|
224
|
+
sleep 5
|
|
225
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
|
|
226
|
+
rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
|
|
227
|
+
sleep 10
|
|
228
|
+
retry
|
|
229
|
+
end while resp.state != "available"
|
|
230
|
+
end
|
|
231
|
+
rescue NoMethodError => e
|
|
232
|
+
if retries <= 3
|
|
233
|
+
MU.log "Got bogus Aws::EmptyResponse error on #{subnet_id} (retries used: #{retries}/3)", MU::WARN
|
|
234
|
+
retries = retries + 1
|
|
235
|
+
sleep 5
|
|
236
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
|
|
237
|
+
retry
|
|
238
|
+
else
|
|
239
|
+
raise e
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
if !subnet['route_table'].nil?
|
|
244
|
+
routes = {}
|
|
245
|
+
@config['route_tables'].each { |tbl|
|
|
246
|
+
routes[tbl['name']] = tbl
|
|
247
|
+
}
|
|
248
|
+
if routes.nil? or routes[subnet['route_table']].nil?
|
|
249
|
+
MU.log "Subnet #{subnet_name} references non-existent route #{subnet['route_table']}", MU::ERR, details: @deploy.deployment['vpcs']
|
|
250
|
+
raise MuError, "deploy failure"
|
|
251
|
+
end
|
|
252
|
+
MU.log "Associating Route Table '#{subnet['route_table']}' (#{routes[subnet['route_table']]['route_table_id']}) with #{subnet_name}"
|
|
253
|
+
retries = 0
|
|
254
|
+
begin
|
|
255
|
+
MU::Cloud::AWS.ec2(@config['region']).associate_route_table(
|
|
256
|
+
route_table_id: routes[subnet['route_table']]['route_table_id'],
|
|
257
|
+
subnet_id: subnet_id
|
|
258
|
+
)
|
|
259
|
+
rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound => e
|
|
260
|
+
retries = retries + 1
|
|
261
|
+
if retries < 10
|
|
262
|
+
sleep 10
|
|
263
|
+
retry
|
|
264
|
+
else
|
|
265
|
+
raise MuError, e.inspect
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
retries = 0
|
|
270
|
+
begin
|
|
271
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
|
|
272
|
+
rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
|
|
273
|
+
if retries < 10
|
|
274
|
+
MU.log "Got #{e.inspect}, waiting and retrying", MU::WARN
|
|
275
|
+
sleep 10
|
|
276
|
+
retries = retries + 1
|
|
277
|
+
retry
|
|
278
|
+
end
|
|
279
|
+
raise MuError, e.inspect, e.backtrace
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
if subnet['is_public'] && subnet['create_nat_gateway']
|
|
283
|
+
MU::MommaCat.lock("nat-gateway-eipalloc")
|
|
284
|
+
filters = [{name: "domain", values: ["vpc"]}]
|
|
285
|
+
eips = MU::Cloud::AWS.ec2(@config['region']).describe_addresses(filters: filters).addresses
|
|
286
|
+
allocation_id = nil
|
|
287
|
+
eips.each { |eip|
|
|
288
|
+
next if !eip.association_id.nil? and !eip.association_id.empty?
|
|
289
|
+
if (eip.private_ip_address.nil? || eip.private_ip_address.empty?) and MU::MommaCat.lock(eip.allocation_id, true, true)
|
|
290
|
+
if !allocation_ids.include?(eip.allocation_id)
|
|
291
|
+
allocation_id = eip.allocation_id
|
|
292
|
+
break
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if allocation_id.nil?
|
|
298
|
+
allocation_id = MU::Cloud::AWS.ec2(@config['region']).allocate_address(domain: "vpc").allocation_id
|
|
299
|
+
MU::MommaCat.lock(allocation_id, false, true)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
allocation_ids << allocation_id
|
|
303
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_nat_gateway(
|
|
304
|
+
subnet_id: subnet['subnet_id'],
|
|
305
|
+
allocation_id: allocation_id
|
|
306
|
+
).nat_gateway
|
|
307
|
+
|
|
308
|
+
nat_gateway_id = resp.nat_gateway_id
|
|
309
|
+
attempts = 0
|
|
310
|
+
MU::MommaCat.unlock("nat-gateway-eipalloc")
|
|
311
|
+
while resp.state == "pending"
|
|
312
|
+
MU.log "Waiting for nat gateway #{nat_gateway_id} () to become available (EIP allocation: #{allocation_id})" if attempts % 5 == 0
|
|
313
|
+
sleep 30
|
|
314
|
+
begin
|
|
315
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
|
|
316
|
+
rescue Aws::EmptyStructure, NoMethodError
|
|
317
|
+
sleep 5
|
|
318
|
+
retry
|
|
319
|
+
end
|
|
320
|
+
if attempts > 30
|
|
321
|
+
MU::MommaCat.unlock(allocation_id, true)
|
|
322
|
+
raise MuError, "Timed out while waiting for NAT Gateway #{nat_gateway_id}: #{resp}"
|
|
323
|
+
end
|
|
324
|
+
attempts += 1
|
|
325
|
+
end
|
|
326
|
+
MU::MommaCat.unlock(allocation_id, true)
|
|
327
|
+
|
|
328
|
+
raise MuError, "NAT Gateway failed #{nat_gateway_id}: #{resp}" if resp.state == "failed"
|
|
329
|
+
nat_gateways << {'id' => nat_gateway_id, 'availability_zone' => subnet['availability_zone']}
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
if subnet.has_key?("map_public_ips")
|
|
333
|
+
retries = 0
|
|
334
|
+
begin
|
|
335
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).modify_subnet_attribute(
|
|
336
|
+
subnet_id: subnet_id,
|
|
337
|
+
map_public_ip_on_launch: {
|
|
338
|
+
value: subnet['map_public_ips'],
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
|
|
342
|
+
if retries < 10
|
|
343
|
+
MU.log "Got #{e.inspect} while trying to enable map_public_ips on subnet, waiting and retrying", MU::WARN
|
|
344
|
+
sleep 10
|
|
345
|
+
retries += 1
|
|
346
|
+
retry
|
|
347
|
+
end
|
|
348
|
+
raise MuError, "Got #{e.inspect}, #{e.backtrace} while trying to enable map_public_ips on subnet"
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
if subnet["enable_traffic_logging"]
|
|
353
|
+
loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
|
|
354
|
+
logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
|
|
355
|
+
MU.log "Enabling traffic logging on Subnet #{subnet_name} in VPC #{@mu_name} to log group #{loggroup.mu_name}"
|
|
356
|
+
MU::Cloud::AWS.ec2(@config['region']).create_flow_logs(
|
|
357
|
+
resource_ids: [subnet_id],
|
|
358
|
+
resource_type: "Subnet",
|
|
359
|
+
traffic_type: subnet["traffic_type_to_log"],
|
|
360
|
+
log_group_name: loggroup.mu_name,
|
|
361
|
+
deliver_logs_permission_arn: logrole.cloudobj.arn
|
|
362
|
+
)
|
|
363
|
+
end
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
subnetthreads.each { |t|
|
|
368
|
+
t.join
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
notify
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
if !nat_gateways.empty?
|
|
375
|
+
nat_gateways.each { |gateway|
|
|
376
|
+
@config['subnets'].each { |subnet|
|
|
377
|
+
if subnet['is_public'] == false && subnet['availability_zone'] == gateway['availability_zone']
|
|
378
|
+
@config['route_tables'].each { |rtb|
|
|
379
|
+
if rtb['name'] == subnet['route_table']
|
|
380
|
+
rtb['routes'].each { |route|
|
|
381
|
+
if route['gateway'] == '#NAT'
|
|
382
|
+
route_config = {
|
|
383
|
+
:route_table_id => rtb['route_table_id'],
|
|
384
|
+
:destination_cidr_block => route['destination_network'],
|
|
385
|
+
:nat_gateway_id => gateway['id']
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
MU.log "Creating route for #{route['destination_network']} through NAT gatway #{gateway['id']}", details: route_config
|
|
389
|
+
begin
|
|
390
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_route(route_config)
|
|
391
|
+
rescue Aws::EC2::Errors::RouteAlreadyExists => e
|
|
392
|
+
MU.log "Attempt to create duplicate route to #{route['destination_network']} for #{gateway['id']} in #{rtb['route_table_id']}", MU::WARN
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
}
|
|
396
|
+
end
|
|
397
|
+
}
|
|
398
|
+
end
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
if @config['enable_dns_support']
|
|
404
|
+
MU.log "Enabling DNS support in #{@mu_name}"
|
|
405
|
+
MU::Cloud::AWS.ec2(@config['region']).modify_vpc_attribute(
|
|
406
|
+
vpc_id: vpc_id,
|
|
407
|
+
enable_dns_support: {value: @config['enable_dns_support']}
|
|
408
|
+
)
|
|
409
|
+
end
|
|
410
|
+
if @config['enable_dns_hostnames']
|
|
411
|
+
MU.log "Enabling DNS hostnames in #{@mu_name}"
|
|
412
|
+
MU::Cloud::AWS.ec2(@config['region']).modify_vpc_attribute(
|
|
413
|
+
vpc_id: vpc_id,
|
|
414
|
+
enable_dns_hostnames: {value: @config['enable_dns_hostnames']}
|
|
415
|
+
)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
if @config['dhcp']
|
|
419
|
+
MU.log "Setting custom DHCP options in #{@mu_name}", details: @config['dhcp']
|
|
420
|
+
dhcpopts = []
|
|
421
|
+
|
|
422
|
+
if @config['dhcp']['netbios_type']
|
|
423
|
+
dhcpopts << {key: "netbios-node-type", values: [@config['dhcp']['netbios_type'].to_s]}
|
|
424
|
+
end
|
|
425
|
+
if @config['dhcp']['domains']
|
|
426
|
+
dhcpopts << {key: "domain-name", values: @config['dhcp']['domains']}
|
|
427
|
+
end
|
|
428
|
+
if @config['dhcp']['dns_servers']
|
|
429
|
+
dhcpopts << {key: "domain-name-servers", values: @config['dhcp']['dns_servers']}
|
|
430
|
+
end
|
|
431
|
+
if @config['dhcp']['ntp_servers']
|
|
432
|
+
dhcpopts << {key: "ntp-servers", values: @config['dhcp']['ntp_servers']}
|
|
433
|
+
end
|
|
434
|
+
if @config['dhcp']['netbios_servers']
|
|
435
|
+
dhcpopts << {key: "netbios-name-servers", values: @config['dhcp']['netbios_servers']}
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_dhcp_options(
|
|
439
|
+
dhcp_configurations: dhcpopts
|
|
440
|
+
)
|
|
441
|
+
dhcpopt_id = resp.dhcp_options.dhcp_options_id
|
|
442
|
+
MU::MommaCat.createStandardTags(dhcpopt_id, region: @config['region'])
|
|
443
|
+
MU::MommaCat.createTag(dhcpopt_id, "Name", @mu_name, region: @config['region'])
|
|
444
|
+
|
|
445
|
+
if @config['tags']
|
|
446
|
+
@config['tags'].each { |tag|
|
|
447
|
+
MU::MommaCat.createTag(dhcpopt_id, tag['key'], tag['value'], region: @config['region'])
|
|
448
|
+
}
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
if @config['optional_tags']
|
|
452
|
+
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
453
|
+
MU::MommaCat.createTag(dhcpopt_id, key, value, region: @config['region'])
|
|
454
|
+
}
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
MU::Cloud::AWS.ec2(@config['region']).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: vpc_id)
|
|
458
|
+
end
|
|
459
|
+
notify
|
|
460
|
+
|
|
461
|
+
if !MU::Cloud::AWS.isGovCloud?(@config['region'])
|
|
462
|
+
mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu").values.first
|
|
463
|
+
if !mu_zone.nil?
|
|
464
|
+
MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc_id, region: @config['region'])
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
loadSubnets
|
|
468
|
+
|
|
469
|
+
MU.log "VPC #{@mu_name} created", details: @config
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
# Canonical Amazon Resource Number for this resource
|
|
473
|
+
# @return [String]
|
|
474
|
+
def arn
|
|
475
|
+
"arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU.account_number+":vpc/"+@cloud_id
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# Describe this VPC
|
|
479
|
+
# @return [Hash]
|
|
480
|
+
def notify
|
|
481
|
+
@config
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
# Called automatically by {MU::Deploy#createResources}
|
|
485
|
+
def groom
|
|
486
|
+
vpc_name = @deploy.getResourceName(@config['name'])
|
|
487
|
+
|
|
488
|
+
# Generate peering connections
|
|
489
|
+
if !@config['peers'].nil? and @config['peers'].size > 0
|
|
490
|
+
@config['peers'].each { |peer|
|
|
491
|
+
peer_obj = nil
|
|
492
|
+
begin
|
|
493
|
+
if peer['account'].nil? or peer['account'] == MU.account_number
|
|
494
|
+
tag_key, tag_value = peer['vpc']['tag'].split(/=/, 2) if !peer['vpc']['tag'].nil?
|
|
495
|
+
if peer['vpc']['deploy_id'].nil? and peer['vpc']['vpc_id'].nil? and tag_key.nil?
|
|
496
|
+
peer['vpc']['deploy_id'] = @deploy.deploy_id
|
|
497
|
+
end
|
|
498
|
+
peer_obj = MU::MommaCat.findStray(
|
|
499
|
+
"AWS",
|
|
500
|
+
"vpcs",
|
|
501
|
+
deploy_id: peer['vpc']['deploy_id'],
|
|
502
|
+
cloud_id: peer['vpc']['vpc_id'],
|
|
503
|
+
name: peer['vpc']['vpc_name'],
|
|
504
|
+
tag_key: tag_key,
|
|
505
|
+
tag_value: tag_value,
|
|
506
|
+
dummy_ok: true,
|
|
507
|
+
region: peer['vpc']['region']
|
|
508
|
+
)
|
|
509
|
+
raise MuError, "No result looking for #{@mu_name}'s peer VPCs (#{peer['vpc']})" if peer_obj.nil? or peer_obj.first.nil?
|
|
510
|
+
peer_obj = peer_obj.first
|
|
511
|
+
peer_id = peer_obj.cloud_id
|
|
512
|
+
|
|
513
|
+
MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}"
|
|
514
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_vpc_peering_connection(
|
|
515
|
+
vpc_id: @cloud_id,
|
|
516
|
+
peer_vpc_id: peer_id
|
|
517
|
+
)
|
|
518
|
+
else
|
|
519
|
+
peer_id = peer['vpc']['vpc_id']
|
|
520
|
+
MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} in account #{peer['account']}", MU::INFO, details: peer
|
|
521
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_vpc_peering_connection(
|
|
522
|
+
vpc_id: @cloud_id,
|
|
523
|
+
peer_vpc_id: peer_id,
|
|
524
|
+
peer_owner_id: peer['account']
|
|
525
|
+
)
|
|
526
|
+
end
|
|
527
|
+
rescue Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists => e
|
|
528
|
+
MU.log "Attempt to create duplicate peering connection to #{peer_id} from VPC #{@config['name']}", MU::WARN
|
|
529
|
+
end
|
|
530
|
+
peering_name = @deploy.getResourceName(@config['name']+"-PEER-"+peer_id)
|
|
531
|
+
|
|
532
|
+
peering_id = resp.vpc_peering_connection.vpc_peering_connection_id
|
|
533
|
+
MU::MommaCat.createStandardTags(peering_id, region: @config['region'])
|
|
534
|
+
MU::MommaCat.createTag(peering_id, "Name", peering_name, region: @config['region'])
|
|
535
|
+
|
|
536
|
+
if @config['optional_tags']
|
|
537
|
+
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
538
|
+
MU::MommaCat.createTag(peering_id, key, value, region: @config['region'])
|
|
539
|
+
}
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
if @config['tags']
|
|
543
|
+
@config['tags'].each { |tag|
|
|
544
|
+
MU::MommaCat.createTag(peering_id, tag['key'], tag['value'], region: @config['region'])
|
|
545
|
+
}
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
# Create routes to our new friend.
|
|
549
|
+
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region']).each { |rtb_id|
|
|
550
|
+
my_route_config = {
|
|
551
|
+
:route_table_id => rtb_id,
|
|
552
|
+
:destination_cidr_block => peer_obj.cloud_desc.cidr_block,
|
|
553
|
+
:vpc_peering_connection_id => peering_id
|
|
554
|
+
}
|
|
555
|
+
begin
|
|
556
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_route(my_route_config)
|
|
557
|
+
rescue Aws::EC2::Errors::RouteAlreadyExists => e
|
|
558
|
+
rtbdesc = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
|
|
559
|
+
route_table_ids: [rtb_id]
|
|
560
|
+
).route_tables.first
|
|
561
|
+
rtbdesc.routes.each { |r|
|
|
562
|
+
if r.destination_cidr_block == peer_obj.cloud_desc.cidr_block
|
|
563
|
+
if r.vpc_peering_connection_id != peering_id
|
|
564
|
+
MU.log "Attempt to create duplicate route to #{peer_obj.cloud_desc.cidr_block} from VPC #{@config['name']}", MU::ERR, details: r
|
|
565
|
+
raise MuError, "Can't create route via #{peering_id}, a route to #{peer_obj.cloud_desc.cidr_block} already exists"
|
|
566
|
+
else
|
|
567
|
+
break # this is fine, the route simply already exists
|
|
568
|
+
end
|
|
569
|
+
end
|
|
570
|
+
}
|
|
571
|
+
end
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
begin
|
|
575
|
+
cnxn = MU::Cloud::AWS.ec2(@config['region']).describe_vpc_peering_connections(
|
|
576
|
+
vpc_peering_connection_ids: [peering_id]
|
|
577
|
+
).vpc_peering_connections.first
|
|
578
|
+
|
|
579
|
+
if cnxn.status.code == "pending-acceptance"
|
|
580
|
+
if ((!peer_obj.nil? and !peer_obj.deploydata.nil? and peer_obj.deploydata['auto_accept_peers']) or $MU_CFG['allow_invade_foreign_vpcs'])
|
|
581
|
+
MU.log "Auto-accepting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}", MU::NOTICE
|
|
582
|
+
begin
|
|
583
|
+
MU::Cloud::AWS.ec2(@config['region']).accept_vpc_peering_connection(
|
|
584
|
+
vpc_peering_connection_id: peering_id
|
|
585
|
+
)
|
|
586
|
+
rescue Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists => e
|
|
587
|
+
MU.log "Attempt to create duplicate peering connection to #{peer_id} from VPC #{@config['name']}", MU::WARN
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
# Create routes back from our new friend to us.
|
|
591
|
+
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_id, region: peer['vpc']['region']).each { |rtb_id|
|
|
592
|
+
peer_route_config = {
|
|
593
|
+
:route_table_id => rtb_id,
|
|
594
|
+
:destination_cidr_block => @config['ip_block'],
|
|
595
|
+
:vpc_peering_connection_id => peering_id
|
|
596
|
+
}
|
|
597
|
+
begin
|
|
598
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_route(peer_route_config)
|
|
599
|
+
rescue Aws::EC2::Errors::RouteAlreadyExists => e
|
|
600
|
+
MU.log "Attempt to create duplicate route to #{@config['ip_block']} from VPC #{peer_id}", MU::WARN
|
|
601
|
+
end
|
|
602
|
+
}
|
|
603
|
+
else
|
|
604
|
+
MU.log "VPC #{peer_id} is not managed by this Mu server or is not configured to auto-accept peering requests. You must accept the peering request for '#{@config['name']}' (#{@cloud_id}) by hand.", MU::WARN, details: "In the AWS Console, go to VPC => Peering Connections and look in the Actions drop-down. You can also set 'Invade Foreign VPCs' to 'true' using mu-configure to auto-accept all peering connections within this account, regardless of whether this Mu server owns the VPCs. This setting is per-user."
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
if cnxn.status.code == "failed" or cnxn.status.code == "rejected" or cnxn.status.code == "expired" or cnxn.status.code == "deleted"
|
|
609
|
+
MU.log "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}", MU::ERR
|
|
610
|
+
begin
|
|
611
|
+
MU::Cloud::AWS.ec2(@config['region']).delete_vpc_peering_connection(
|
|
612
|
+
vpc_peering_connection_id: peering_id
|
|
613
|
+
)
|
|
614
|
+
rescue Aws::EC2::Errors::InvalidStateTransition => e
|
|
615
|
+
# XXX apparently this is normal?
|
|
616
|
+
end
|
|
617
|
+
raise MuError, "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}"
|
|
618
|
+
end
|
|
619
|
+
end while cnxn.status.code != "active" and !(cnxn.status.code == "pending-acceptance" and (peer_obj.nil? or peer_obj.deploydata.nil? or !peer_obj.deploydata['auto_accept_peers']))
|
|
620
|
+
|
|
621
|
+
}
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
# Add any routes that reference instances, which would've been created
|
|
625
|
+
# in Server objects' create phases.
|
|
626
|
+
if !@config['route_tables'].nil?
|
|
627
|
+
@config['route_tables'].each { |rtb|
|
|
628
|
+
route_table_id = rtb['route_table_id']
|
|
629
|
+
|
|
630
|
+
rtb['routes'].each { |route|
|
|
631
|
+
if !route['nat_host_id'].nil? or !route['nat_host_name'].nil?
|
|
632
|
+
route_config = {
|
|
633
|
+
:route_table_id => route_table_id,
|
|
634
|
+
:destination_cidr_block => route['destination_network']
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
nat_instance = findBastion(
|
|
638
|
+
nat_name: route["nat_host_name"],
|
|
639
|
+
nat_cloud_id: route["nat_host_id"]
|
|
640
|
+
)
|
|
641
|
+
if nat_instance.nil?
|
|
642
|
+
raise MuError, "VPC #{vpc_name} is configured to use #{route} as a route, but I can't find a matching bastion host!"
|
|
643
|
+
end
|
|
644
|
+
route_config[:instance_id] = nat_instance.cloud_id
|
|
645
|
+
|
|
646
|
+
MU.log "Creating route for #{route['destination_network']} through NAT host #{nat_instance.cloud_id}", details: route_config
|
|
647
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).create_route(route_config)
|
|
648
|
+
end
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
}
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
# Locate an existing VPC or VPCs and return an array containing matching AWS resource descriptors for those that match.
|
|
657
|
+
# @param cloud_id [String]: The cloud provider's identifier for this resource.
|
|
658
|
+
# @param region [String]: The cloud provider region
|
|
659
|
+
# @param tag_key [String]: A tag key to search.
|
|
660
|
+
# @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
|
|
661
|
+
# @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching VPCs
|
|
662
|
+
def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, flags: {})
|
|
663
|
+
|
|
664
|
+
retries = 0
|
|
665
|
+
map = {}
|
|
666
|
+
begin
|
|
667
|
+
sleep 5 if retries < 0
|
|
668
|
+
|
|
669
|
+
if tag_value
|
|
670
|
+
MU.log "Searching for VPC by tag:#{tag_key}=#{tag_value}", MU::DEBUG
|
|
671
|
+
resp = MU::Cloud::AWS.ec2(region).describe_vpcs(
|
|
672
|
+
filters: [
|
|
673
|
+
{name: "tag:#{tag_key}", values: [tag_value]}
|
|
674
|
+
]
|
|
675
|
+
)
|
|
676
|
+
if resp.data.vpcs.nil? or resp.data.vpcs.size == 0
|
|
677
|
+
return nil
|
|
678
|
+
elsif resp.data.vpcs.size >= 1
|
|
679
|
+
resp.data.vpcs.each { |vpc|
|
|
680
|
+
map[vpc.vpc_id] = vpc
|
|
681
|
+
}
|
|
682
|
+
return map
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
if !cloud_id.nil?
|
|
687
|
+
MU.log "Searching for VPC id '#{cloud_id}' in #{region}", MU::DEBUG
|
|
688
|
+
begin
|
|
689
|
+
resp = MU::Cloud::AWS.ec2(region).describe_vpcs(vpc_ids: [cloud_id.to_s])
|
|
690
|
+
resp.vpcs.each { |vpc|
|
|
691
|
+
map[vpc.vpc_id] = vpc
|
|
692
|
+
}
|
|
693
|
+
return map
|
|
694
|
+
rescue Aws::EC2::Errors::InvalidVpcIDNotFound => e
|
|
695
|
+
end
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
retries = retries + 1
|
|
699
|
+
end while retries < 5
|
|
700
|
+
|
|
701
|
+
return map
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
# Return an array of MU::Cloud::AWS::VPC::Subnet objects describe the
|
|
705
|
+
# member subnets of this VPC.
|
|
706
|
+
#
|
|
707
|
+
# @return [Array<MU::Cloud::AWS::VPC::Subnet>]
|
|
708
|
+
def subnets
|
|
709
|
+
if @subnets.nil? or @subnets.size == 0
|
|
710
|
+
return loadSubnets
|
|
711
|
+
end
|
|
712
|
+
return @subnets
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
# Describe subnets associated with this VPC. We'll compose identifying
|
|
716
|
+
# information similar to what MU::Cloud.describe builds for first-class
|
|
717
|
+
# resources.
|
|
718
|
+
# XXX this is weaksauce. Subnets should be objects with their own methods
|
|
719
|
+
# that work like first-class objects. How would we enforce that?
|
|
720
|
+
# @return [Array<Hash>]: A list of cloud provider identifiers of subnets associated with this VPC.
|
|
721
|
+
def loadSubnets
|
|
722
|
+
if @cloud_id
|
|
723
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(
|
|
724
|
+
filters: [
|
|
725
|
+
{ name: "vpc-id", values: [@cloud_id] }
|
|
726
|
+
]
|
|
727
|
+
)
|
|
728
|
+
if resp.nil? or resp.subnets.nil? or resp.subnets.size == 0
|
|
729
|
+
MU.log "Got empty results when trying to list subnets in #{@cloud_id}", MU::WARN
|
|
730
|
+
return []
|
|
731
|
+
end
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
@subnetcachesemaphore.synchronize {
|
|
735
|
+
@subnets ||= []
|
|
736
|
+
ext_ids = @subnets.each.collect { |s| s.cloud_id }
|
|
737
|
+
|
|
738
|
+
# If we're a plain old Mu resource, load our config and deployment
|
|
739
|
+
# metadata. Like ya do.
|
|
740
|
+
if !@config.nil? and @config.has_key?("subnets")
|
|
741
|
+
@config['subnets'].each { |subnet|
|
|
742
|
+
subnet['mu_name'] = @mu_name+"-"+subnet['name'] if !subnet.has_key?("mu_name")
|
|
743
|
+
subnet['region'] = @config['region']
|
|
744
|
+
if !resp.nil? and !resp.data.nil? and !resp.data.subnets.nil?
|
|
745
|
+
resp.data.subnets.each { |desc|
|
|
746
|
+
if desc.cidr_block == subnet["ip_block"]
|
|
747
|
+
subnet["tags"] = MU.structToHash(desc.tags)
|
|
748
|
+
subnet["cloud_id"] = desc.subnet_id
|
|
749
|
+
break
|
|
750
|
+
end
|
|
751
|
+
}
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
if subnet["cloud_id"] and !ext_ids.include?(subnet["cloud_id"])
|
|
755
|
+
@subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
|
|
756
|
+
elsif !subnet["cloud_id"]
|
|
757
|
+
resp.data.subnets.each { |desc|
|
|
758
|
+
if desc.cidr_block == subnet["ip_block"]
|
|
759
|
+
subnet['cloud_id'] = desc.subnet_id
|
|
760
|
+
@subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
|
|
761
|
+
end
|
|
762
|
+
}
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
}
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
# Of course we might be loading up a dummy subnet object from a
|
|
769
|
+
# foreign or non-Mu-created VPC and subnet. So make something up.
|
|
770
|
+
if !resp.nil? and @subnets.empty?
|
|
771
|
+
resp.data.subnets.each { |desc|
|
|
772
|
+
subnet = {}
|
|
773
|
+
subnet["ip_block"] = desc.cidr_block
|
|
774
|
+
subnet["name"] = subnet["ip_block"].gsub(/[\.\/]/, "_")
|
|
775
|
+
subnet['mu_name'] = @mu_name+"-"+subnet['name']
|
|
776
|
+
subnet["tags"] = MU.structToHash(desc.tags)
|
|
777
|
+
subnet["cloud_id"] = desc.subnet_id
|
|
778
|
+
subnet['region'] = @config['region']
|
|
779
|
+
if !ext_ids.include?(desc.subnet_id)
|
|
780
|
+
@subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
|
|
781
|
+
end
|
|
782
|
+
}
|
|
783
|
+
end
|
|
784
|
+
return @subnets
|
|
785
|
+
}
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
# Given some search criteria try locating a NAT Gaateway in this VPC.
|
|
789
|
+
# @param nat_cloud_id [String]: The cloud provider's identifier for this NAT.
|
|
790
|
+
# @param nat_filter_key [String]: A cloud provider filter to help identify the resource, used in conjunction with nat_filter_value.
|
|
791
|
+
# @param nat_filter_value [String]: A cloud provider filter to help identify the resource, used in conjunction with nat_filter_key.
|
|
792
|
+
# @param region [String]: The cloud provider region of the target instance.
|
|
793
|
+
def findNat(nat_cloud_id: nil, nat_filter_key: nil, nat_filter_value: nil, region: MU.curRegion)
|
|
794
|
+
# Discard the nat_cloud_id if it's an AWS instance ID
|
|
795
|
+
nat_cloud_id = nil if nat_cloud_id && nat_cloud_id.start_with?("i-")
|
|
796
|
+
|
|
797
|
+
if @gateways.nil?
|
|
798
|
+
@gateways =
|
|
799
|
+
if nat_cloud_id
|
|
800
|
+
MU::Cloud::AWS.ec2(region).describe_nat_gateways(nat_gateway_ids: [nat_cloud_id])
|
|
801
|
+
elsif nat_filter_key && nat_filter_value
|
|
802
|
+
MU::Cloud::AWS.ec2(region).describe_nat_gateways(
|
|
803
|
+
filter: [
|
|
804
|
+
{
|
|
805
|
+
name: nat_filter_key,
|
|
806
|
+
values: [nat_filter_value]
|
|
807
|
+
}
|
|
808
|
+
]
|
|
809
|
+
).nat_gateways
|
|
810
|
+
end
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
@gateways ? @gateways.first : nil
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
# Given some search criteria for a {MU::Cloud::Server}, see if we can
|
|
817
|
+
# locate a NAT host in this VPC.
|
|
818
|
+
# @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.
|
|
819
|
+
# @param nat_cloud_id [String]: The cloud provider's identifier for this NAT.
|
|
820
|
+
# @param nat_tag_key [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_value.
|
|
821
|
+
# @param nat_tag_value [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_key.
|
|
822
|
+
# @param nat_ip [String]: An IP address associated with the NAT instance.
|
|
823
|
+
def findBastion(nat_name: nil, nat_cloud_id: nil, nat_tag_key: nil, nat_tag_value: nil, nat_ip: nil)
|
|
824
|
+
nat = nil
|
|
825
|
+
deploy_id = nil
|
|
826
|
+
nat_name = nat_name.to_s if !nat_name.nil? and nat_name.class.to_s == "MU::Config::Tail"
|
|
827
|
+
nat_ip = nat_ip.to_s if !nat_ip.nil? and nat_ip.class.to_s == "MU::Config::Tail"
|
|
828
|
+
nat_cloud_id = nat_cloud_id.to_s if !nat_cloud_id.nil? and nat_cloud_id.class.to_s == "MU::Config::Tail"
|
|
829
|
+
nat_tag_key = nat_tag_key.to_s if !nat_tag_key.nil? and nat_tag_key.class.to_s == "MU::Config::Tail"
|
|
830
|
+
nat_tag_value = nat_tag_value.to_s if !nat_tag_value.nil? and nat_tag_value.class.to_s == "MU::Config::Tail"
|
|
831
|
+
|
|
832
|
+
# If we're searching by name, assume it's part of this here deploy.
|
|
833
|
+
if nat_cloud_id.nil? and !@deploy.nil?
|
|
834
|
+
deploy_id = @deploy.deploy_id
|
|
835
|
+
end
|
|
836
|
+
found = MU::MommaCat.findStray(
|
|
837
|
+
@config['cloud'],
|
|
838
|
+
"server",
|
|
839
|
+
name: nat_name,
|
|
840
|
+
region: @config['region'],
|
|
841
|
+
cloud_id: nat_cloud_id,
|
|
842
|
+
deploy_id: deploy_id,
|
|
843
|
+
tag_key: nat_tag_key,
|
|
844
|
+
tag_value: nat_tag_value,
|
|
845
|
+
allow_multi: true,
|
|
846
|
+
dummy_ok: true,
|
|
847
|
+
calling_deploy: @deploy
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
return nil if found.nil? || found.empty?
|
|
851
|
+
if found.size > 1
|
|
852
|
+
found.each { |nat|
|
|
853
|
+
# Try some AWS-specific criteria
|
|
854
|
+
cloud_desc = nat.cloud_desc
|
|
855
|
+
if !nat_host_ip.nil? and
|
|
856
|
+
(cloud_desc.private_ip_address == nat_host_ip or cloud_desc.public_ip_address == nat_host_ip)
|
|
857
|
+
return nat
|
|
858
|
+
elsif cloud_desc.vpc_id == @cloud_id
|
|
859
|
+
# XXX Strictly speaking we could have different NATs in different
|
|
860
|
+
# subnets, so this can be wrong in corner cases. Why you'd
|
|
861
|
+
# architect something that obnoxiously, I have no idea.
|
|
862
|
+
return nat
|
|
863
|
+
end
|
|
864
|
+
}
|
|
865
|
+
elsif found.size == 1
|
|
866
|
+
return found.first
|
|
867
|
+
end
|
|
868
|
+
return nil
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
# Check for a subnet in this VPC matching one or more of the specified
|
|
872
|
+
# criteria, and return it if found.
|
|
873
|
+
def getSubnet(cloud_id: nil, name: nil, tag_key: nil, tag_value: nil, ip_block: nil)
|
|
874
|
+
if !cloud_id and !name and !tag_key and !tag_value and !ip_block
|
|
875
|
+
raise MuError, "getSubnet called with no non-nil arguments"
|
|
876
|
+
end
|
|
877
|
+
subnets
|
|
878
|
+
|
|
879
|
+
@subnets.each { |subnet|
|
|
880
|
+
if !cloud_id.nil? and !subnet.cloud_id.nil? and subnet.cloud_id.to_s == cloud_id.to_s
|
|
881
|
+
return subnet
|
|
882
|
+
elsif !name.nil? and !subnet.name.nil? and subnet.name.to_s == name.to_s
|
|
883
|
+
return subnet
|
|
884
|
+
elsif !ip_block.nil? and !subnet.ip_block.nil? and subnet.ip_block.to_s == ip_block.to_s
|
|
885
|
+
return subnet
|
|
886
|
+
end
|
|
887
|
+
}
|
|
888
|
+
return nil
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
# Get the subnets associated with an instance.
|
|
892
|
+
# @param instance_id [String]: The cloud identifier of the instance
|
|
893
|
+
# @param instance [String]: A cloud descriptor for the instance, to save us an API call if we already have it
|
|
894
|
+
# @param region [String]: The cloud provider region of the target instance
|
|
895
|
+
# @return [Array<String>]
|
|
896
|
+
def self.getInstanceSubnets(instance_id: nil, instance: nil, region: MU.curRegion)
|
|
897
|
+
return [] if instance_id.nil? and instance.nil?
|
|
898
|
+
my_subnets = []
|
|
899
|
+
|
|
900
|
+
if instance.nil?
|
|
901
|
+
begin
|
|
902
|
+
instance = MU::Cloud::AWS.ec2(region).describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
|
|
903
|
+
rescue NoMethodError, Aws::EC2::Errors::InvalidInstanceIDNotFound => e
|
|
904
|
+
MU.log "Failed to identify instance #{instance_id} in MU::Cloud::AWS::VPC.getInstanceSubnets", MU::WARN
|
|
905
|
+
return []
|
|
906
|
+
end
|
|
907
|
+
end
|
|
908
|
+
my_subnets << instance.subnet_id if !instance.subnet_id.nil?
|
|
909
|
+
if !instance.network_interfaces.nil?
|
|
910
|
+
instance.network_interfaces.each { |iface|
|
|
911
|
+
my_subnets << iface.subnet_id if !iface.subnet_id.nil?
|
|
912
|
+
}
|
|
913
|
+
end
|
|
914
|
+
return my_subnets.uniq.sort
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
@route_cache = {}
|
|
918
|
+
@rtb_cache = {}
|
|
919
|
+
@rtb_cache_semaphore = Mutex.new
|
|
920
|
+
# Check whether we (the Mu Master) have a direct route to a particular
|
|
921
|
+
# subnet. Useful for skipping hops through bastion hosts to get directly
|
|
922
|
+
# at child nodes in peered VPCs and the like.
|
|
923
|
+
# @param target_instance [OpenStruct]: The cloud descriptor of the instance to check.
|
|
924
|
+
# @param region [String]: The cloud provider region of the target subnet.
|
|
925
|
+
# @return [Boolean]
|
|
926
|
+
def self.haveRouteToInstance?(target_instance, region: MU.curRegion)
|
|
927
|
+
return false if target_instance.nil?
|
|
928
|
+
return false if MU.myCloud != "AWS"
|
|
929
|
+
instance_id = target_instance.instance_id
|
|
930
|
+
# XXX check if I'm even in AWS before all this bullshit
|
|
931
|
+
target_vpc_id = target_instance.vpc_id
|
|
932
|
+
my_vpc_id = MU.myCloudDescriptor.vpc_id
|
|
933
|
+
if (target_vpc_id && !target_vpc_id.empty?) && (my_vpc_id && !my_vpc_id.empty?)
|
|
934
|
+
# If the master and the node are in the same vpc then more likely than not there is a route...
|
|
935
|
+
if target_vpc_id == my_vpc_id
|
|
936
|
+
MU.log "I share a VPC with #{instance_id}, I can route to it directly", MU::DEBUG
|
|
937
|
+
@route_cache[instance_id] = true
|
|
938
|
+
return true
|
|
939
|
+
end
|
|
940
|
+
end
|
|
941
|
+
|
|
942
|
+
return @route_cache[instance_id] if @route_cache.has_key?(instance_id) && @route_cache[instance_id]
|
|
943
|
+
my_subnets = MU::Cloud::AWS::VPC.getInstanceSubnets(instance: MU.myCloudDescriptor)
|
|
944
|
+
target_subnets = MU::Cloud::AWS::VPC.getInstanceSubnets(instance: target_instance, region: region)
|
|
945
|
+
# XXX make sure accounts for being in different regions
|
|
946
|
+
|
|
947
|
+
resp = nil
|
|
948
|
+
my_subnets_key = my_subnets.join(",")
|
|
949
|
+
target_subnets_key = target_subnets.join(",")
|
|
950
|
+
MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, region: MU.myRegion)
|
|
951
|
+
MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, region: region)
|
|
952
|
+
|
|
953
|
+
if MU::Cloud::AWS::VPC.have_route_peered_vpc?(my_subnets_key, target_subnets_key, instance_id)
|
|
954
|
+
return true
|
|
955
|
+
else
|
|
956
|
+
# The cache can be out of date at times, check again without it
|
|
957
|
+
MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, use_cache: false, region: MU.myRegion)
|
|
958
|
+
MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, use_cache: false, region: region)
|
|
959
|
+
|
|
960
|
+
return MU::Cloud::AWS::VPC.have_route_peered_vpc?(my_subnets_key, target_subnets_key, instance_id)
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
@route_cache[instance_id] = false
|
|
964
|
+
return false
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
# updates the route table cache (@rtb_cache).
|
|
968
|
+
# @param subnet_key [String]: The subnet/subnets route tables will be extracted from.
|
|
969
|
+
# @param use_cache [Boolean]: If to use the existing cache and add records to cache only if missing, or to also replace exising records in cache.
|
|
970
|
+
# @param region [String]: The cloud provider region of the target subnet.
|
|
971
|
+
def self.update_route_tables_cache(subnet_key, use_cache: true, region: MU.curRegion)
|
|
972
|
+
@rtb_cache_semaphore.synchronize {
|
|
973
|
+
update =
|
|
974
|
+
if !use_cache
|
|
975
|
+
true
|
|
976
|
+
elsif use_cache && !@rtb_cache.has_key?(subnet_key)
|
|
977
|
+
true
|
|
978
|
+
else
|
|
979
|
+
false
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
if update
|
|
983
|
+
route_tables = MU::Cloud::AWS::VPC.get_route_tables(subnet_ids: subnet_key.split(","), region: region)
|
|
984
|
+
|
|
985
|
+
if route_tables.empty? && !subnet_key.empty?
|
|
986
|
+
vpc_id = MU::Cloud::AWS.ec2(region).describe_subnets(subnet_ids: subnet_key.split(",")).subnets.first.vpc_id
|
|
987
|
+
MU.log "No route table associations found for #{subnet_key}, falling back to the default table for #{vpc_id}", MU::NOTICE
|
|
988
|
+
route_tables = MU::Cloud::AWS::VPC.get_route_tables(vpc_ids: [vpc_id], region: region)
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
@rtb_cache[subnet_key] = route_tables
|
|
992
|
+
end
|
|
993
|
+
}
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
# Checks if the MU master has a route to a subnet in a peered VPC. Can be used on any subnets
|
|
997
|
+
# @param source_subnets_key [String]: The subnet/subnets on one side of the peered VPC.
|
|
998
|
+
# @param target_subnets_key [String]: The subnet/subnets on the other side of the peered VPC.
|
|
999
|
+
# @param instance_id [String]: The instance ID in the target subnet/subnets.
|
|
1000
|
+
# @return [Boolean]
|
|
1001
|
+
def self.have_route_peered_vpc?(source_subnets_key, target_subnets_key, instance_id)
|
|
1002
|
+
my_routes = []
|
|
1003
|
+
vpc_peer_mapping = {}
|
|
1004
|
+
|
|
1005
|
+
@rtb_cache[source_subnets_key].each { |route_table|
|
|
1006
|
+
route_table.routes.each { |route|
|
|
1007
|
+
if route.destination_cidr_block != "0.0.0.0/0" and route.state == "active" and !route.destination_cidr_block.nil?
|
|
1008
|
+
my_routes << NetAddr::IPv4Net.parse(route.destination_cidr_block)
|
|
1009
|
+
if !route.vpc_peering_connection_id.nil?
|
|
1010
|
+
vpc_peer_mapping[route.vpc_peering_connection_id] = route.destination_cidr_block
|
|
1011
|
+
end
|
|
1012
|
+
end
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
my_routes.uniq!
|
|
1016
|
+
|
|
1017
|
+
target_routes = []
|
|
1018
|
+
@rtb_cache[target_subnets_key].each { |route_table|
|
|
1019
|
+
route_table.routes.each { |route|
|
|
1020
|
+
next if route.destination_cidr_block == "0.0.0.0/0" or route.state != "active" or route.destination_cidr_block.nil?
|
|
1021
|
+
cidr = NetAddr::IPv4Net.parse(route.destination_cidr_block)
|
|
1022
|
+
shared_ip_space = false
|
|
1023
|
+
my_routes.each { |my_cidr|
|
|
1024
|
+
if my_cidr.contains(NetAddr::IPv4Net.parse(route.destination_cidr_block).nth(2)) or my_cidr.cmp(cidr)
|
|
1025
|
+
shared_ip_space = true
|
|
1026
|
+
break
|
|
1027
|
+
end
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
if shared_ip_space && !route.vpc_peering_connection_id.nil? && vpc_peer_mapping.has_key?(route.vpc_peering_connection_id)
|
|
1031
|
+
MU.log "I share a VPC peering connection (#{route.vpc_peering_connection_id}) with #{instance_id} for #{route.destination_cidr_block}, I can route to it directly", MU::DEBUG
|
|
1032
|
+
@route_cache[instance_id] = true
|
|
1033
|
+
return true
|
|
1034
|
+
end
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
return false
|
|
1039
|
+
end
|
|
1040
|
+
|
|
1041
|
+
# Retrieves the route tables of used by subnets
|
|
1042
|
+
# @param subnet_ids [Array]: The cloud identifier of the subnets to retrieve the route tables for.
|
|
1043
|
+
# @param vpc_ids [Array]: The cloud identifier of the VPCs to retrieve route tables for.
|
|
1044
|
+
# @param region [String]: The cloud provider region of the target subnet.
|
|
1045
|
+
# @return [Array<OpenStruct>]: The cloud provider's complete descriptions of the route tables
|
|
1046
|
+
def self.get_route_tables(subnet_ids: [], vpc_ids: [], region: MU.curRegion)
|
|
1047
|
+
resp = []
|
|
1048
|
+
if !subnet_ids.empty?
|
|
1049
|
+
resp = MU::Cloud::AWS.ec2(region).describe_route_tables(
|
|
1050
|
+
filters: [
|
|
1051
|
+
{
|
|
1052
|
+
name: "association.subnet-id",
|
|
1053
|
+
values: subnet_ids
|
|
1054
|
+
}
|
|
1055
|
+
]
|
|
1056
|
+
).route_tables
|
|
1057
|
+
elsif !vpc_ids.empty?
|
|
1058
|
+
resp = MU::Cloud::AWS.ec2(region).describe_route_tables(
|
|
1059
|
+
filters: [
|
|
1060
|
+
{
|
|
1061
|
+
name: "vpc-id",
|
|
1062
|
+
values: vpc_ids
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
name: "association.main",
|
|
1066
|
+
values: ["true"]
|
|
1067
|
+
},
|
|
1068
|
+
]
|
|
1069
|
+
).route_tables
|
|
1070
|
+
else
|
|
1071
|
+
resp = MU::Cloud::AWS.ec2(region).describe_route_tables.route_tables
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
return resp
|
|
1075
|
+
end
|
|
1076
|
+
|
|
1077
|
+
# Remove all VPC resources associated with the currently loaded deployment.
|
|
1078
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1079
|
+
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
|
1080
|
+
# @param region [String]: The cloud provider region
|
|
1081
|
+
# @return [void]
|
|
1082
|
+
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, flags: {})
|
|
1083
|
+
|
|
1084
|
+
tagfilters = [
|
|
1085
|
+
{name: "tag:MU-ID", values: [MU.deploy_id]}
|
|
1086
|
+
]
|
|
1087
|
+
if !ignoremaster
|
|
1088
|
+
tagfilters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
|
|
1089
|
+
end
|
|
1090
|
+
|
|
1091
|
+
vpcs = []
|
|
1092
|
+
retries = 0
|
|
1093
|
+
begin
|
|
1094
|
+
resp = MU::Cloud::AWS.ec2(region).describe_vpcs(filters: tagfilters).vpcs
|
|
1095
|
+
vpcs = resp if !resp.empty?
|
|
1096
|
+
rescue Aws::EC2::Errors::InvalidVpcIDNotFound => e
|
|
1097
|
+
if retries < 5
|
|
1098
|
+
sleep 5
|
|
1099
|
+
retries += 1
|
|
1100
|
+
retry
|
|
1101
|
+
end
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
if !vpcs.empty?
|
|
1105
|
+
gwthreads = []
|
|
1106
|
+
vpcs.each { |vpc|
|
|
1107
|
+
# NAT gateways don't have any tags, and we can't assign them a name. Lets find them based on a VPC ID
|
|
1108
|
+
gwthreads << Thread.new {
|
|
1109
|
+
purge_nat_gateways(noop, vpc_id: vpc.vpc_id, region: region)
|
|
1110
|
+
purge_endpoints(noop, vpc_id: vpc.vpc_id, region: region)
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
gwthreads.each { |t|
|
|
1114
|
+
t.join
|
|
1115
|
+
}
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1118
|
+
purge_gateways(noop, tagfilters, region: region)
|
|
1119
|
+
purge_routetables(noop, tagfilters, region: region)
|
|
1120
|
+
purge_interfaces(noop, tagfilters, region: region)
|
|
1121
|
+
purge_subnets(noop, tagfilters, region: region)
|
|
1122
|
+
purge_vpcs(noop, tagfilters, region: region)
|
|
1123
|
+
purge_dhcpopts(noop, tagfilters, region: region)
|
|
1124
|
+
|
|
1125
|
+
unless noop
|
|
1126
|
+
MU::Cloud::AWS.iam.list_roles.roles.each{ |role|
|
|
1127
|
+
match_string = "#{MU.deploy_id}.*TRAFFIC-LOG"
|
|
1128
|
+
}
|
|
1129
|
+
end
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
# Cloud-specific configuration properties.
|
|
1133
|
+
# @param config [MU::Config]: The calling MU::Config object
|
|
1134
|
+
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
|
1135
|
+
def self.schema(config)
|
|
1136
|
+
toplevel_required = []
|
|
1137
|
+
# Flow Logs can be declared at the VPC level or the subnet level
|
|
1138
|
+
flowlogs = {
|
|
1139
|
+
"traffic_type_to_log" => {
|
|
1140
|
+
"type" => "string",
|
|
1141
|
+
"description" => "The class of traffic to log - accepted traffic, rejected traffic or all traffic.",
|
|
1142
|
+
"enum" => ["accept", "reject", "all"],
|
|
1143
|
+
"default" => "all"
|
|
1144
|
+
},
|
|
1145
|
+
"log_group_name" => {
|
|
1146
|
+
"type" => "string",
|
|
1147
|
+
"description" => "An existing CloudWachLogs log group the traffic will be logged to. If not provided, a new one will be created"
|
|
1148
|
+
},
|
|
1149
|
+
"enable_traffic_logging" => {
|
|
1150
|
+
"type" => "boolean",
|
|
1151
|
+
"description" => "If traffic logging is enabled or disabled. Will be enabled on all subnets and network interfaces if set to true on a VPC",
|
|
1152
|
+
"default" => false
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
schema = {
|
|
1157
|
+
"subnets" => {
|
|
1158
|
+
"items" => {
|
|
1159
|
+
"properties" => flowlogs
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
schema.merge!(flowlogs)
|
|
1164
|
+
[toplevel_required, schema]
|
|
1165
|
+
end
|
|
1166
|
+
|
|
1167
|
+
# Cloud-specific pre-processing of {MU::Config::BasketofKittens::vpcs}, bare and unvalidated.
|
|
1168
|
+
# @param vpc [Hash]: The resource to process and validate
|
|
1169
|
+
# @param configurator [MU::Config]: The overall deployment config of which this resource is a member
|
|
1170
|
+
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
1171
|
+
def self.validateConfig(vpc, configurator)
|
|
1172
|
+
ok = true
|
|
1173
|
+
|
|
1174
|
+
if (!vpc['route_tables'] or vpc['route_tables'].size == 0) and vpc['create_standard_subnets']
|
|
1175
|
+
vpc['route_tables'] = [
|
|
1176
|
+
{
|
|
1177
|
+
"name" => "internet",
|
|
1178
|
+
"routes" => [ { "destination_network" => "0.0.0.0/0", "gateway" => "#INTERNET" } ]
|
|
1179
|
+
},
|
|
1180
|
+
{
|
|
1181
|
+
"name" => "private",
|
|
1182
|
+
"routes" => [ { "destination_network" => "0.0.0.0/0", "gateway" => "#NAT" } ]
|
|
1183
|
+
}
|
|
1184
|
+
]
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1187
|
+
if vpc["enable_traffic_logging"]
|
|
1188
|
+
logdesc = {
|
|
1189
|
+
"name" => vpc['name']+"loggroup",
|
|
1190
|
+
}
|
|
1191
|
+
logdesc["tags"] = vpc["tags"] if !vpc["tags"].nil?
|
|
1192
|
+
# logdesc["optional_tags"] = vpc["optional_tags"] if !vpc["optional_tags"].nil?
|
|
1193
|
+
configurator.insertKitten(logdesc, "logs")
|
|
1194
|
+
vpc['dependencies'] ||= []
|
|
1195
|
+
vpc['dependencies'] << {
|
|
1196
|
+
"type" => "log",
|
|
1197
|
+
"name" => vpc['name']+"loggroup"
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
roledesc = {
|
|
1201
|
+
"name" => vpc['name']+"logrole",
|
|
1202
|
+
"can_assume" => [
|
|
1203
|
+
{
|
|
1204
|
+
"entity_id" => "vpc-flow-logs.amazonaws.com",
|
|
1205
|
+
"entity_type" => "service"
|
|
1206
|
+
}
|
|
1207
|
+
],
|
|
1208
|
+
"policies" => [
|
|
1209
|
+
{
|
|
1210
|
+
"name" => "FlowLogPerms",
|
|
1211
|
+
"permissions" => [
|
|
1212
|
+
"logs:CreateLogGroup",
|
|
1213
|
+
"logs:CreateLogStream",
|
|
1214
|
+
"logs:DescribeLogGroups",
|
|
1215
|
+
"logs:DescribeLogStreams",
|
|
1216
|
+
"logs:PutLogEvents"
|
|
1217
|
+
],
|
|
1218
|
+
"targets" => [
|
|
1219
|
+
{
|
|
1220
|
+
"type" => "log",
|
|
1221
|
+
"identifier" => vpc['name']+"loggroup"
|
|
1222
|
+
}
|
|
1223
|
+
]
|
|
1224
|
+
}
|
|
1225
|
+
],
|
|
1226
|
+
"dependencies" => [
|
|
1227
|
+
{
|
|
1228
|
+
"type" => "log",
|
|
1229
|
+
"name" => vpc['name']+"loggroup"
|
|
1230
|
+
}
|
|
1231
|
+
]
|
|
1232
|
+
}
|
|
1233
|
+
roledesc["tags"] = vpc["tags"] if !vpc["tags"].nil?
|
|
1234
|
+
roledesc["optional_tags"] = vpc["optional_tags"] if !vpc["optional_tags"].nil?
|
|
1235
|
+
configurator.insertKitten(roledesc, "roles")
|
|
1236
|
+
vpc['dependencies'] ||= []
|
|
1237
|
+
vpc['dependencies'] << {
|
|
1238
|
+
"type" => "role",
|
|
1239
|
+
"name" => vpc['name']+"logrole"
|
|
1240
|
+
}
|
|
1241
|
+
end
|
|
1242
|
+
|
|
1243
|
+
subnet_routes = Hash.new
|
|
1244
|
+
public_routes = Array.new
|
|
1245
|
+
|
|
1246
|
+
if vpc['subnets']
|
|
1247
|
+
vpc['subnets'].each { |subnet|
|
|
1248
|
+
subnet_routes[subnet['route_table']] = Array.new if subnet_routes[subnet['route_table']].nil?
|
|
1249
|
+
subnet_routes[subnet['route_table']] << subnet['name']
|
|
1250
|
+
}
|
|
1251
|
+
end
|
|
1252
|
+
if vpc['endpoint_policy'] && !vpc['endpoint_policy'].empty?
|
|
1253
|
+
if !vpc['endpoint']
|
|
1254
|
+
MU.log "'endpoint_policy' is declared however endpoint is not set", MU::ERR
|
|
1255
|
+
ok = false
|
|
1256
|
+
end
|
|
1257
|
+
|
|
1258
|
+
attributes = %w{Effect Action Resource Principal Sid}
|
|
1259
|
+
vpc['endpoint_policy'].each { |rule|
|
|
1260
|
+
rule.keys.each { |key|
|
|
1261
|
+
if !attributes.include?(key)
|
|
1262
|
+
MU.log "'Attribute #{key} can't be used in 'endpoint_policy'", MU::ERR
|
|
1263
|
+
ok = false
|
|
1264
|
+
end
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
end
|
|
1268
|
+
|
|
1269
|
+
nat_gateway_route_tables = []
|
|
1270
|
+
nat_gateway_added = false
|
|
1271
|
+
public_rtbs = []
|
|
1272
|
+
private_rtbs = []
|
|
1273
|
+
nat_routes = {}
|
|
1274
|
+
vpc['route_tables'].each { |table|
|
|
1275
|
+
routes = []
|
|
1276
|
+
table['routes'].each { |route|
|
|
1277
|
+
if routes.include?(route['destination_network'])
|
|
1278
|
+
MU.log "Duplicate routes to #{route['destination_network']} in route table #{table['name']}", MU::ERR
|
|
1279
|
+
ok = false
|
|
1280
|
+
else
|
|
1281
|
+
routes << route['destination_network']
|
|
1282
|
+
end
|
|
1283
|
+
|
|
1284
|
+
if (route['nat_host_name'] or route['nat_host_id'])
|
|
1285
|
+
private_rtbs << table['name']
|
|
1286
|
+
route.delete("gateway") if route['gateway'] == '#INTERNET'
|
|
1287
|
+
end
|
|
1288
|
+
if !route['nat_host_name'].nil? and configurator.haveLitterMate?(route['nat_host_name'], "server") and !subnet_routes.nil? and !subnet_routes.empty?
|
|
1289
|
+
subnet_routes[table['name']].each { |subnet|
|
|
1290
|
+
nat_routes[subnet] = route['nat_host_name']
|
|
1291
|
+
}
|
|
1292
|
+
vpc['dependencies'] << {
|
|
1293
|
+
"type" => "server",
|
|
1294
|
+
"name" => route['nat_host_name']
|
|
1295
|
+
}
|
|
1296
|
+
elsif route['gateway'] == '#NAT'
|
|
1297
|
+
private_rtbs << table['name']
|
|
1298
|
+
elsif route['gateway'] == '#INTERNET'
|
|
1299
|
+
public_rtbs << table['name']
|
|
1300
|
+
end
|
|
1301
|
+
next if !vpc['subnets']
|
|
1302
|
+
|
|
1303
|
+
vpc['subnets'].each { |subnet|
|
|
1304
|
+
if route['gateway'] == '#INTERNET'
|
|
1305
|
+
if table['name'] == subnet['route_table']
|
|
1306
|
+
subnet['is_public'] = true
|
|
1307
|
+
if vpc['create_nat_gateway']
|
|
1308
|
+
if vpc['nat_gateway_multi_az']
|
|
1309
|
+
subnet['create_nat_gateway'] = true
|
|
1310
|
+
else
|
|
1311
|
+
if nat_gateway_added
|
|
1312
|
+
subnet['create_nat_gateway'] = false
|
|
1313
|
+
else
|
|
1314
|
+
subnet['create_nat_gateway'] = true
|
|
1315
|
+
nat_gateway_added = true
|
|
1316
|
+
end
|
|
1317
|
+
end
|
|
1318
|
+
end
|
|
1319
|
+
else
|
|
1320
|
+
subnet['is_public'] = false
|
|
1321
|
+
end
|
|
1322
|
+
if !nat_routes[subnet['name']].nil?
|
|
1323
|
+
subnet['nat_host_name'] = nat_routes[subnet['name']]
|
|
1324
|
+
end
|
|
1325
|
+
elsif route['gateway'] == '#NAT'
|
|
1326
|
+
if table['name'] == subnet['route_table']
|
|
1327
|
+
if route['nat_host_name'] or route['nat_host_id']
|
|
1328
|
+
MU.log "You can either use a NAT gateway or a NAT server, not both.", MU::ERR
|
|
1329
|
+
ok = false
|
|
1330
|
+
end
|
|
1331
|
+
|
|
1332
|
+
subnet['is_public'] = false
|
|
1333
|
+
nat_gateway_route_tables << table
|
|
1334
|
+
end
|
|
1335
|
+
end
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
if (!vpc['subnets'] or vpc['subnets'].empty?) and vpc['create_standard_subnets']
|
|
1341
|
+
if vpc['availability_zones'].nil? or vpc['availability_zones'].empty?
|
|
1342
|
+
vpc['availability_zones'] = MU::Cloud::AWS.listAZs(vpc['region'])
|
|
1343
|
+
else
|
|
1344
|
+
# turn into a hash so we can use list parameters easily
|
|
1345
|
+
vpc['availability_zones'] = vpc['availability_zones'].map { |val| val['zone'] }
|
|
1346
|
+
end
|
|
1347
|
+
subnets = configurator.divideNetwork(vpc['ip_block'], vpc['availability_zones'].size*vpc['route_tables'].size, 28)
|
|
1348
|
+
|
|
1349
|
+
ok = false if subnets.nil?
|
|
1350
|
+
vpc['subnets'] = []
|
|
1351
|
+
count = 0
|
|
1352
|
+
vpc['availability_zones'].each { |az|
|
|
1353
|
+
addnat = false
|
|
1354
|
+
if vpc['create_nat_gateway'] and (vpc['nat_gateway_multi_az'] or !nat_gateway_added) and public_rtbs.size > 0
|
|
1355
|
+
addnat = true
|
|
1356
|
+
nat_gateway_added = true
|
|
1357
|
+
end
|
|
1358
|
+
vpc['route_tables'].each { |rtb|
|
|
1359
|
+
vpc['subnets'] << {
|
|
1360
|
+
"name" => "Subnet#{count}#{rtb['name'].capitalize}",
|
|
1361
|
+
"availability_zone" => az,
|
|
1362
|
+
"ip_block" => subnets.shift,
|
|
1363
|
+
"route_table" => rtb['name'],
|
|
1364
|
+
|
|
1365
|
+
"map_public_ips" => (public_rtbs and public_rtbs.include?(rtb['name'])),
|
|
1366
|
+
"is_public" => (public_rtbs and public_rtbs.include?(rtb['name'])),
|
|
1367
|
+
"create_nat_gateway" => (addnat and public_rtbs and public_rtbs.include?(rtb['name']))
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
count = count + 1
|
|
1371
|
+
}
|
|
1372
|
+
end
|
|
1373
|
+
|
|
1374
|
+
nat_gateway_route_tables.uniq!
|
|
1375
|
+
if nat_gateway_route_tables.size < 2 && vpc['nat_gateway_multi_az']
|
|
1376
|
+
MU.log "'nat_gateway_multi_az' is enabled but only one route table exists. For multi-az support create one private route table per AZ", MU::ERR
|
|
1377
|
+
ok = false
|
|
1378
|
+
end
|
|
1379
|
+
|
|
1380
|
+
if nat_gateway_route_tables.size > 0 && !vpc['create_nat_gateway']
|
|
1381
|
+
MU.log "There are route tables with a NAT gateway route, but create_nat_gateway is set to false. Setting to true", MU::NOTICE
|
|
1382
|
+
vpc['create_nat_gateway'] = true
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
ok
|
|
1386
|
+
end
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
private
|
|
1390
|
+
|
|
1391
|
+
|
|
1392
|
+
# List the route tables for each subnet in the given VPC
|
|
1393
|
+
def self.listAllSubnetRouteTables(vpc_id, region: MU.curRegion)
|
|
1394
|
+
resp = MU::Cloud::AWS.ec2(region).describe_subnets(
|
|
1395
|
+
filters: [
|
|
1396
|
+
{
|
|
1397
|
+
name: "vpc-id",
|
|
1398
|
+
values: [vpc_id]
|
|
1399
|
+
}
|
|
1400
|
+
]
|
|
1401
|
+
)
|
|
1402
|
+
|
|
1403
|
+
subnets = resp.subnets.map { |subnet| subnet.subnet_id }
|
|
1404
|
+
|
|
1405
|
+
tables = MU::Cloud::AWS.ec2(region).describe_route_tables(
|
|
1406
|
+
filters: [
|
|
1407
|
+
{
|
|
1408
|
+
name: "vpc-id",
|
|
1409
|
+
values: [vpc_id]
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
name: "association.subnet-id",
|
|
1413
|
+
values: subnets
|
|
1414
|
+
}
|
|
1415
|
+
]
|
|
1416
|
+
)
|
|
1417
|
+
|
|
1418
|
+
if tables.nil? or tables.route_tables.size == 0
|
|
1419
|
+
MU.log "No route table associations found for #{subnets}, falling back to the default table for #{vpc_id}", MU::NOTICE
|
|
1420
|
+
tables = MU::Cloud::AWS.ec2(MU.myRegion).describe_route_tables(
|
|
1421
|
+
filters: [
|
|
1422
|
+
{name: "vpc-id", values: [vpc_id]},
|
|
1423
|
+
{name: "association.main", values: ["true"]},
|
|
1424
|
+
]
|
|
1425
|
+
)
|
|
1426
|
+
end
|
|
1427
|
+
|
|
1428
|
+
table_ids = []
|
|
1429
|
+
tables.route_tables.each { |rtb|
|
|
1430
|
+
table_ids << rtb.route_table_id
|
|
1431
|
+
}
|
|
1432
|
+
return table_ids.uniq
|
|
1433
|
+
end
|
|
1434
|
+
|
|
1435
|
+
# Helper method for manufacturing route tables. Expect to be called from
|
|
1436
|
+
# {MU::Cloud::AWS::VPC#create} or {MU::Cloud::AWS::VPC#groom}.
|
|
1437
|
+
# @param rtb [Hash]: A route table description parsed through {MU::Config::BasketofKittens::vpcs::route_tables}.
|
|
1438
|
+
# @return [Hash]: The modified configuration that was originally passed in.
|
|
1439
|
+
def createRouteTable(rtb)
|
|
1440
|
+
vpc_id = @cloud_id
|
|
1441
|
+
vpc_name = @config['name']
|
|
1442
|
+
MU.setVar("curRegion", @config['region']) if !@config['region'].nil?
|
|
1443
|
+
resp = MU::Cloud::AWS.ec2.create_route_table(vpc_id: vpc_id).route_table
|
|
1444
|
+
route_table_id = rtb['route_table_id'] = resp.route_table_id
|
|
1445
|
+
sleep 5
|
|
1446
|
+
MU::MommaCat.createTag(route_table_id, "Name", vpc_name+"-"+rtb['name'].upcase)
|
|
1447
|
+
|
|
1448
|
+
if @config['tags']
|
|
1449
|
+
@config['tags'].each { |tag|
|
|
1450
|
+
MU::MommaCat.createTag(route_table_id, tag['key'], tag['value'])
|
|
1451
|
+
}
|
|
1452
|
+
end
|
|
1453
|
+
|
|
1454
|
+
if @config['optional_tags']
|
|
1455
|
+
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
1456
|
+
MU::MommaCat.createTag(route_table_id, key, value, region: @config['region'])
|
|
1457
|
+
}
|
|
1458
|
+
end
|
|
1459
|
+
|
|
1460
|
+
MU::MommaCat.createStandardTags(route_table_id)
|
|
1461
|
+
rtb['routes'].each { |route|
|
|
1462
|
+
if route['nat_host_id'].nil? and route['nat_host_name'].nil?
|
|
1463
|
+
route_config = {
|
|
1464
|
+
:route_table_id => route_table_id,
|
|
1465
|
+
:destination_cidr_block => route['destination_network']
|
|
1466
|
+
}
|
|
1467
|
+
if !route['peer_id'].nil?
|
|
1468
|
+
route_config[:vpc_peering_connection_id] = route['peer_id']
|
|
1469
|
+
else
|
|
1470
|
+
route_config[:gateway_id] = @config['internet_gateway_id']
|
|
1471
|
+
end
|
|
1472
|
+
# XXX how do the network interfaces work with this?
|
|
1473
|
+
unless route['gateway'] == '#NAT'
|
|
1474
|
+
# Need to change the order of how things are created to create the route here
|
|
1475
|
+
MU.log "Creating route for #{route['destination_network']}", details: route_config
|
|
1476
|
+
resp = MU::Cloud::AWS.ec2.create_route(route_config)
|
|
1477
|
+
end
|
|
1478
|
+
end
|
|
1479
|
+
}
|
|
1480
|
+
return rtb
|
|
1481
|
+
end
|
|
1482
|
+
|
|
1483
|
+
|
|
1484
|
+
# Remove all network gateways associated with the currently loaded deployment.
|
|
1485
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1486
|
+
# @param region [String]: The cloud provider region
|
|
1487
|
+
# @return [void]
|
|
1488
|
+
def self.purge_gateways(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
|
|
1489
|
+
resp = MU::Cloud::AWS.ec2(region).describe_internet_gateways(
|
|
1490
|
+
filters: tagfilters
|
|
1491
|
+
)
|
|
1492
|
+
gateways = resp.data.internet_gateways
|
|
1493
|
+
|
|
1494
|
+
gateways.each { |gateway|
|
|
1495
|
+
gateway.attachments.each { |attachment|
|
|
1496
|
+
MU.log "Detaching Internet Gateway #{gateway.internet_gateway_id} from #{attachment.vpc_id}"
|
|
1497
|
+
begin
|
|
1498
|
+
MU::Cloud::AWS.ec2(region).detach_internet_gateway(
|
|
1499
|
+
internet_gateway_id: gateway.internet_gateway_id,
|
|
1500
|
+
vpc_id: attachment.vpc_id
|
|
1501
|
+
) if !noop
|
|
1502
|
+
rescue Aws::EC2::Errors::GatewayNotAttached => e
|
|
1503
|
+
MU.log "Gateway #{gateway.internet_gateway_id} was already detached", MU::WARN
|
|
1504
|
+
end
|
|
1505
|
+
}
|
|
1506
|
+
MU.log "Deleting Internet Gateway #{gateway.internet_gateway_id}"
|
|
1507
|
+
begin
|
|
1508
|
+
MU::Cloud::AWS.ec2(region).delete_internet_gateway(internet_gateway_id: gateway.internet_gateway_id) if !noop
|
|
1509
|
+
rescue Aws::EC2::Errors::InvalidInternetGatewayIDNotFound
|
|
1510
|
+
MU.log "Gateway #{gateway.internet_gateway_id} was already destroyed by the time I got to it", MU::WARN
|
|
1511
|
+
end
|
|
1512
|
+
}
|
|
1513
|
+
return nil
|
|
1514
|
+
end
|
|
1515
|
+
|
|
1516
|
+
# Remove all NAT gateways associated with the VPC of the currently loaded deployment.
|
|
1517
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1518
|
+
# @param vpc_id [String]: The cloud provider's unique VPC identifier
|
|
1519
|
+
# @param region [String]: The cloud provider region
|
|
1520
|
+
# @return [void]
|
|
1521
|
+
def self.purge_nat_gateways(noop = false, vpc_id: nil, region: MU.curRegion)
|
|
1522
|
+
gateways = MU::Cloud::AWS.ec2(region).describe_nat_gateways(
|
|
1523
|
+
filter: [
|
|
1524
|
+
{
|
|
1525
|
+
name: "vpc-id",
|
|
1526
|
+
values: [vpc_id],
|
|
1527
|
+
}
|
|
1528
|
+
]
|
|
1529
|
+
).nat_gateways
|
|
1530
|
+
|
|
1531
|
+
threads = []
|
|
1532
|
+
parent_thread_id = Thread.current.object_id
|
|
1533
|
+
if !gateways.empty?
|
|
1534
|
+
gateways.each { |gateway|
|
|
1535
|
+
threads << Thread.new {
|
|
1536
|
+
MU.dupGlobals(parent_thread_id)
|
|
1537
|
+
MU.log "Deleting NAT Gateway #{gateway.nat_gateway_id}"
|
|
1538
|
+
if !noop
|
|
1539
|
+
begin
|
|
1540
|
+
MU::Cloud::AWS.ec2(region).delete_nat_gateway(nat_gateway_id: gateway.nat_gateway_id)
|
|
1541
|
+
resp = MU::Cloud::AWS.ec2(region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
|
|
1542
|
+
|
|
1543
|
+
attempts = 0
|
|
1544
|
+
while resp.state != "deleted" and resp.state != "failed"
|
|
1545
|
+
MU.log "Waiting for nat gateway #{gateway.nat_gateway_id} to delete" if attempts % 2 == 0
|
|
1546
|
+
sleep 30
|
|
1547
|
+
begin
|
|
1548
|
+
resp = MU::Cloud::AWS.ec2(region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
|
|
1549
|
+
rescue Aws::EmptyStructure, NoMethodError
|
|
1550
|
+
sleep 5
|
|
1551
|
+
retry
|
|
1552
|
+
rescue Aws::EC2::Errors::NatGatewayNotFound
|
|
1553
|
+
MU.log "NAT gateway #{gateway.nat_gateway_id} already deleted", MU::NOTICE
|
|
1554
|
+
end
|
|
1555
|
+
MU.log "Timed out while waiting for NAT Gateway to delete #{gateway.nat_gateway_id}: #{resp}", MU::WARN if attempts > 50
|
|
1556
|
+
attempts += 1
|
|
1557
|
+
end
|
|
1558
|
+
rescue Aws::EC2::Errors::NatGatewayMalformed
|
|
1559
|
+
MU.log "NAT Gateway #{gateway.nat_gateway_id} was already deleted", MU::NOTICE
|
|
1560
|
+
end
|
|
1561
|
+
end
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
end
|
|
1565
|
+
|
|
1566
|
+
threads.each { |t|
|
|
1567
|
+
t.join
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
return nil
|
|
1571
|
+
end
|
|
1572
|
+
|
|
1573
|
+
# Remove all VPC endpoints associated with the VPC of the currently loaded deployment.
|
|
1574
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1575
|
+
# @param vpc_id [String]: The cloud provider's unique VPC identifier
|
|
1576
|
+
# @param region [String]: The cloud provider region
|
|
1577
|
+
# @return [void]
|
|
1578
|
+
def self.purge_endpoints(noop = false, vpc_id: nil, region: MU.curRegion)
|
|
1579
|
+
vpc_endpoints = MU::Cloud::AWS.ec2(region).describe_vpc_endpoints(
|
|
1580
|
+
filters: [
|
|
1581
|
+
{
|
|
1582
|
+
name:"vpc-id",
|
|
1583
|
+
values: [vpc_id],
|
|
1584
|
+
}
|
|
1585
|
+
]
|
|
1586
|
+
).vpc_endpoints
|
|
1587
|
+
|
|
1588
|
+
threads = []
|
|
1589
|
+
parent_thread_id = Thread.current.object_id
|
|
1590
|
+
if !vpc_endpoints.empty?
|
|
1591
|
+
vpc_endpoints.each { |endpoint|
|
|
1592
|
+
threads << Thread.new {
|
|
1593
|
+
MU.dupGlobals(parent_thread_id)
|
|
1594
|
+
MU.log "Deleting VPC endpoint #{endpoint.vpc_endpoint_id}"
|
|
1595
|
+
if !noop
|
|
1596
|
+
begin
|
|
1597
|
+
MU::Cloud::AWS.ec2(region).delete_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id])
|
|
1598
|
+
resp = MU::Cloud::AWS.ec2(region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
|
|
1599
|
+
|
|
1600
|
+
attempts = 0
|
|
1601
|
+
while resp.state != "deleted"
|
|
1602
|
+
MU.log "Waiting for VPC endpoint #{endpoint.vpc_endpoint_id} to delete" if attempts % 5 == 0
|
|
1603
|
+
sleep 30
|
|
1604
|
+
begin
|
|
1605
|
+
resp = MU::Cloud::AWS.ec2(region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
|
|
1606
|
+
rescue Aws::EmptyStructure, NoMethodError
|
|
1607
|
+
sleep 5
|
|
1608
|
+
retry
|
|
1609
|
+
rescue Aws::EC2::Errors::InvalidVpcEndpointIdNotFound
|
|
1610
|
+
MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} already deleted", MU::NOTICE
|
|
1611
|
+
end
|
|
1612
|
+
MU.log "Timed out while waiting for VPC endpoint to delete #{endpoint.vpc_endpoint_id}: #{resp}", MU::WARN if attempts > 50
|
|
1613
|
+
attempts += 1
|
|
1614
|
+
end
|
|
1615
|
+
rescue Aws::EC2::Errors::VpcEndpointIdMalformed
|
|
1616
|
+
MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} was already deleted", MU::NOTICE
|
|
1617
|
+
rescue Aws::EC2::Errors::InvalidVpcEndpointIdNotFound
|
|
1618
|
+
MU.log "VPC endpoint #{endpoint.vpc_endpoint_id} already deleted", MU::NOTICE
|
|
1619
|
+
end
|
|
1620
|
+
end
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
end
|
|
1624
|
+
|
|
1625
|
+
threads.each { |t|
|
|
1626
|
+
t.join
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
return nil
|
|
1630
|
+
end
|
|
1631
|
+
|
|
1632
|
+
# Remove all route tables associated with the currently loaded deployment.
|
|
1633
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1634
|
+
# @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
|
|
1635
|
+
# @param region [String]: The cloud provider region
|
|
1636
|
+
# @return [void]
|
|
1637
|
+
def self.purge_routetables(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
|
|
1638
|
+
resp = MU::Cloud::AWS.ec2(region).describe_route_tables(
|
|
1639
|
+
filters: tagfilters
|
|
1640
|
+
)
|
|
1641
|
+
route_tables = resp.data.route_tables
|
|
1642
|
+
|
|
1643
|
+
return if route_tables.nil? or route_tables.size == 0
|
|
1644
|
+
|
|
1645
|
+
route_tables.each { |table|
|
|
1646
|
+
table.routes.each { |route|
|
|
1647
|
+
if !route.network_interface_id.nil?
|
|
1648
|
+
MU.log "Deleting Network Interface #{route.network_interface_id}"
|
|
1649
|
+
begin
|
|
1650
|
+
MU::Cloud::AWS.ec2(region).delete_network_interface(network_interface_id: route.network_interface_id) if !noop
|
|
1651
|
+
rescue Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound => e
|
|
1652
|
+
MU.log "Network Interface #{route.network_interface_id} has already been deleted", MU::WARN
|
|
1653
|
+
end
|
|
1654
|
+
end
|
|
1655
|
+
if route.gateway_id != "local"
|
|
1656
|
+
MU.log "Deleting #{table.route_table_id}'s route for #{route.destination_cidr_block}"
|
|
1657
|
+
begin
|
|
1658
|
+
MU::Cloud::AWS.ec2(region).delete_route(
|
|
1659
|
+
route_table_id: table.route_table_id,
|
|
1660
|
+
destination_cidr_block: route.destination_cidr_block
|
|
1661
|
+
) if !noop
|
|
1662
|
+
rescue Aws::EC2::Errors::InvalidRouteNotFound
|
|
1663
|
+
MU.log "Route #{table.route_table_id} has already been deleted", MU::WARN
|
|
1664
|
+
end
|
|
1665
|
+
end
|
|
1666
|
+
}
|
|
1667
|
+
can_delete = true
|
|
1668
|
+
table.associations.each { |assoc|
|
|
1669
|
+
begin
|
|
1670
|
+
MU::Cloud::AWS.ec2(region).disassociate_route_table(association_id: assoc.route_table_association_id) if !noop
|
|
1671
|
+
rescue Aws::EC2::Errors::InvalidAssociationIDNotFound => e
|
|
1672
|
+
MU.log "Route table association #{assoc.route_table_association_id} already removed", MU::WARN
|
|
1673
|
+
rescue Aws::EC2::Errors::InvalidParameterValue => e
|
|
1674
|
+
# normal and ignorable with the default route table
|
|
1675
|
+
can_delete = false
|
|
1676
|
+
next
|
|
1677
|
+
end
|
|
1678
|
+
}
|
|
1679
|
+
next if !can_delete
|
|
1680
|
+
MU.log "Deleting Route Table #{table.route_table_id}"
|
|
1681
|
+
begin
|
|
1682
|
+
MU::Cloud::AWS.ec2(region).delete_route_table(route_table_id: table.route_table_id) if !noop
|
|
1683
|
+
rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound
|
|
1684
|
+
MU.log "Route table #{table.route_table_id} already removed", MU::WARN
|
|
1685
|
+
end
|
|
1686
|
+
}
|
|
1687
|
+
return nil
|
|
1688
|
+
end
|
|
1689
|
+
|
|
1690
|
+
|
|
1691
|
+
# Remove all network interfaces associated with the currently loaded deployment.
|
|
1692
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1693
|
+
# @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
|
|
1694
|
+
# @param region [String]: The cloud provider region
|
|
1695
|
+
# @return [void]
|
|
1696
|
+
def self.purge_interfaces(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
|
|
1697
|
+
resp = MU::Cloud::AWS.ec2(region).describe_network_interfaces(
|
|
1698
|
+
filters: tagfilters
|
|
1699
|
+
)
|
|
1700
|
+
ifaces = resp.data.network_interfaces
|
|
1701
|
+
|
|
1702
|
+
return if ifaces.nil? or ifaces.size == 0
|
|
1703
|
+
|
|
1704
|
+
ifaces.each { |iface|
|
|
1705
|
+
MU.log "Deleting Network Interface #{iface.network_interface_id}"
|
|
1706
|
+
MU::Cloud::AWS.ec2(region).delete_network_interface(network_interface_id: iface.network_interface_id)
|
|
1707
|
+
}
|
|
1708
|
+
end
|
|
1709
|
+
|
|
1710
|
+
# Remove all subnets associated with the currently loaded deployment.
|
|
1711
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1712
|
+
# @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
|
|
1713
|
+
# @param region [String]: The cloud provider region
|
|
1714
|
+
# @return [void]
|
|
1715
|
+
def self.purge_subnets(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
|
|
1716
|
+
resp = MU::Cloud::AWS.ec2(region).describe_subnets(
|
|
1717
|
+
filters: tagfilters
|
|
1718
|
+
)
|
|
1719
|
+
subnets = resp.data.subnets
|
|
1720
|
+
|
|
1721
|
+
return if subnets.nil? or subnets.size == 0
|
|
1722
|
+
|
|
1723
|
+
retries = 0
|
|
1724
|
+
subnets.each { |subnet|
|
|
1725
|
+
begin
|
|
1726
|
+
if subnet.state != "available"
|
|
1727
|
+
MU.log "Waiting for #{subnet.subnet_id} to be in a removable state...", MU::NOTICE
|
|
1728
|
+
sleep 30
|
|
1729
|
+
else
|
|
1730
|
+
MU.log "Deleting Subnet #{subnet.subnet_id}"
|
|
1731
|
+
MU::Cloud::AWS.ec2(region).delete_subnet(subnet_id: subnet.subnet_id) if !noop
|
|
1732
|
+
end
|
|
1733
|
+
rescue Aws::EC2::Errors::DependencyViolation => e
|
|
1734
|
+
if retries < 7
|
|
1735
|
+
MU.log "#{e.inspect}, retrying in 10s", MU::WARN
|
|
1736
|
+
sleep 10
|
|
1737
|
+
retries = retries + 1
|
|
1738
|
+
retry
|
|
1739
|
+
else
|
|
1740
|
+
raise e
|
|
1741
|
+
end
|
|
1742
|
+
rescue Aws::EC2::Errors::InvalidSubnetIDNotFound
|
|
1743
|
+
MU.log "Subnet #{subnet.subnet_id} disappeared before I could remove it", MU::WARN
|
|
1744
|
+
next
|
|
1745
|
+
end while subnet.state != "available"
|
|
1746
|
+
}
|
|
1747
|
+
end
|
|
1748
|
+
|
|
1749
|
+
# Remove all DHCP options sets associated with the currently loaded
|
|
1750
|
+
# deployment.
|
|
1751
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1752
|
+
# @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
|
|
1753
|
+
# @param region [String]: The cloud provider region
|
|
1754
|
+
# @return [void]
|
|
1755
|
+
def self.purge_dhcpopts(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
|
|
1756
|
+
resp = MU::Cloud::AWS.ec2(region).describe_dhcp_options(
|
|
1757
|
+
filters: tagfilters
|
|
1758
|
+
)
|
|
1759
|
+
sets = resp.data.dhcp_options
|
|
1760
|
+
|
|
1761
|
+
return if sets.nil? or sets.size == 0
|
|
1762
|
+
|
|
1763
|
+
sets.each { |optset|
|
|
1764
|
+
begin
|
|
1765
|
+
MU.log "Deleting DHCP Option Set #{optset.dhcp_options_id}"
|
|
1766
|
+
MU::Cloud::AWS.ec2(region).delete_dhcp_options(dhcp_options_id: optset.dhcp_options_id)
|
|
1767
|
+
rescue Aws::EC2::Errors::DependencyViolation => e
|
|
1768
|
+
MU.log e.inspect, MU::ERR
|
|
1769
|
+
# rescue Aws::EC2::Errors::InvalidSubnetIDNotFound
|
|
1770
|
+
# MU.log "Subnet #{subnet.subnet_id} disappeared before I could remove it", MU::WARN
|
|
1771
|
+
# next
|
|
1772
|
+
end
|
|
1773
|
+
}
|
|
1774
|
+
end
|
|
1775
|
+
|
|
1776
|
+
# Remove all VPCs associated with the currently loaded deployment.
|
|
1777
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1778
|
+
# @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
|
|
1779
|
+
# @param region [String]: The cloud provider region
|
|
1780
|
+
# @return [void]
|
|
1781
|
+
def self.purge_vpcs(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
|
|
1782
|
+
resp = MU::Cloud::AWS.ec2(region).describe_vpcs(
|
|
1783
|
+
filters: tagfilters
|
|
1784
|
+
)
|
|
1785
|
+
|
|
1786
|
+
vpcs = resp.data.vpcs
|
|
1787
|
+
return if vpcs.nil? or vpcs.size == 0
|
|
1788
|
+
|
|
1789
|
+
vpcs.each { |vpc|
|
|
1790
|
+
my_peer_conns = MU::Cloud::AWS.ec2(region).describe_vpc_peering_connections(
|
|
1791
|
+
filters: [
|
|
1792
|
+
{
|
|
1793
|
+
name: "requester-vpc-info.vpc-id",
|
|
1794
|
+
values: [vpc.vpc_id]
|
|
1795
|
+
}
|
|
1796
|
+
]
|
|
1797
|
+
).vpc_peering_connections
|
|
1798
|
+
my_peer_conns.concat(MU::Cloud::AWS.ec2(region).describe_vpc_peering_connections(
|
|
1799
|
+
filters: [
|
|
1800
|
+
{
|
|
1801
|
+
name: "accepter-vpc-info.vpc-id",
|
|
1802
|
+
values: [vpc.vpc_id]
|
|
1803
|
+
}
|
|
1804
|
+
]
|
|
1805
|
+
).vpc_peering_connections)
|
|
1806
|
+
my_peer_conns.each { |cnxn|
|
|
1807
|
+
|
|
1808
|
+
[cnxn.accepter_vpc_info.vpc_id, cnxn.requester_vpc_info.vpc_id].each { |peer_vpc|
|
|
1809
|
+
MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_vpc, region: region).each { |rtb_id|
|
|
1810
|
+
resp = MU::Cloud::AWS.ec2(region).describe_route_tables(
|
|
1811
|
+
route_table_ids: [rtb_id]
|
|
1812
|
+
)
|
|
1813
|
+
resp.route_tables.each { |rtb|
|
|
1814
|
+
rtb.routes.each { |route|
|
|
1815
|
+
if route.vpc_peering_connection_id == cnxn.vpc_peering_connection_id
|
|
1816
|
+
MU.log "Removing route #{route.destination_cidr_block} from route table #{rtb_id} in VPC #{peer_vpc}"
|
|
1817
|
+
MU::Cloud::AWS.ec2(region).delete_route(
|
|
1818
|
+
route_table_id: rtb_id,
|
|
1819
|
+
destination_cidr_block: route.destination_cidr_block
|
|
1820
|
+
) if !noop
|
|
1821
|
+
end
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
MU.log "Deleting VPC peering connection #{cnxn.vpc_peering_connection_id}"
|
|
1827
|
+
begin
|
|
1828
|
+
MU::Cloud::AWS.ec2(region).delete_vpc_peering_connection(
|
|
1829
|
+
vpc_peering_connection_id: cnxn.vpc_peering_connection_id
|
|
1830
|
+
) if !noop
|
|
1831
|
+
rescue Aws::EC2::Errors::InvalidStateTransition => e
|
|
1832
|
+
MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} not in removable (state #{cnxn.status.code})", MU::WARN
|
|
1833
|
+
end
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
MU.log "Deleting VPC #{vpc.vpc_id}"
|
|
1837
|
+
retries = 0
|
|
1838
|
+
begin
|
|
1839
|
+
MU::Cloud::AWS.ec2(region).delete_vpc(vpc_id: vpc.vpc_id) if !noop
|
|
1840
|
+
rescue Aws::EC2::Errors::InvalidVpcIDNotFound
|
|
1841
|
+
MU.log "VPC #{vpc.vpc_id} has already been deleted", MU::WARN
|
|
1842
|
+
rescue Aws::EC2::Errors::DependencyViolation => e
|
|
1843
|
+
MU.log "Couldn't delete VPC #{vpc.vpc_id} from #{region}: #{e.inspect}", MU::ERR#, details: caller
|
|
1844
|
+
if retries < 5
|
|
1845
|
+
retries += 1
|
|
1846
|
+
sleep 10
|
|
1847
|
+
retry
|
|
1848
|
+
else
|
|
1849
|
+
next
|
|
1850
|
+
end
|
|
1851
|
+
end
|
|
1852
|
+
|
|
1853
|
+
if !MU::Cloud::AWS.isGovCloud?(region)
|
|
1854
|
+
mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", region: region).values.first
|
|
1855
|
+
if !mu_zone.nil?
|
|
1856
|
+
MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc.vpc_id, remove: true)
|
|
1857
|
+
end
|
|
1858
|
+
end
|
|
1859
|
+
}
|
|
1860
|
+
end
|
|
1861
|
+
|
|
1862
|
+
protected
|
|
1863
|
+
|
|
1864
|
+
# Subnets are almost a first-class resource. So let's kinda sorta treat
|
|
1865
|
+
# them like one. This should only be invoked on objects that already
|
|
1866
|
+
# exists in the cloud layer.
|
|
1867
|
+
class Subnet < MU::Cloud::AWS::VPC
|
|
1868
|
+
|
|
1869
|
+
attr_reader :cloud_id
|
|
1870
|
+
attr_reader :ip_block
|
|
1871
|
+
attr_reader :mu_name
|
|
1872
|
+
attr_reader :name
|
|
1873
|
+
attr_reader :az
|
|
1874
|
+
attr_reader :cloud_desc
|
|
1875
|
+
|
|
1876
|
+
# @param parent [MU::Cloud::AWS::VPC]: The parent VPC of this subnet.
|
|
1877
|
+
# @param config [Hash<String>]:
|
|
1878
|
+
def initialize(parent, config)
|
|
1879
|
+
@parent = parent
|
|
1880
|
+
@config = MU::Config.manxify(config)
|
|
1881
|
+
@cloud_id = config['cloud_id']
|
|
1882
|
+
@mu_name = config['mu_name']
|
|
1883
|
+
@name = config['name']
|
|
1884
|
+
@deploydata = config # This is a dummy for the sake of describe()
|
|
1885
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
|
|
1886
|
+
@az = resp.availability_zone
|
|
1887
|
+
@ip_block = resp.cidr_block
|
|
1888
|
+
@cloud_desc = resp
|
|
1889
|
+
|
|
1890
|
+
end
|
|
1891
|
+
|
|
1892
|
+
# Return the cloud identifier for the default route of this subnet.
|
|
1893
|
+
def defaultRoute
|
|
1894
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
|
|
1895
|
+
filters: [{name: "association.subnet-id", values: [@cloud_id]}]
|
|
1896
|
+
)
|
|
1897
|
+
if resp.route_tables.size == 0 # use default route table for the VPC
|
|
1898
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
|
|
1899
|
+
filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
|
|
1900
|
+
)
|
|
1901
|
+
end
|
|
1902
|
+
resp.route_tables.each { |route_table|
|
|
1903
|
+
route_table.routes.each { |route|
|
|
1904
|
+
if route.destination_cidr_block =="0.0.0.0/0" and route.state != "blackhole"
|
|
1905
|
+
return route.instance_id if !route.instance_id.nil?
|
|
1906
|
+
return route.gateway_id if !route.gateway_id.nil?
|
|
1907
|
+
return route.vpc_peering_connection_id if !route.vpc_peering_connection_id.nil?
|
|
1908
|
+
return route.network_interface_id if !route.network_interface_id.nil?
|
|
1909
|
+
end
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
return nil
|
|
1913
|
+
end
|
|
1914
|
+
|
|
1915
|
+
# Is this subnet privately-routable only, or public?
|
|
1916
|
+
# @return [Boolean]
|
|
1917
|
+
def private?
|
|
1918
|
+
return false if @cloud_id.nil?
|
|
1919
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
|
|
1920
|
+
filters: [{name: "association.subnet-id", values: [@cloud_id]}]
|
|
1921
|
+
)
|
|
1922
|
+
if resp.route_tables.size == 0 # use default route table for the VPC
|
|
1923
|
+
resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
|
|
1924
|
+
filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
|
|
1925
|
+
)
|
|
1926
|
+
end
|
|
1927
|
+
resp.route_tables.each { |route_table|
|
|
1928
|
+
route_table.routes.each { |route|
|
|
1929
|
+
return false if !route.gateway_id.nil? and route.gateway_id != "local" # you can have an IgW and route it to a subset of IPs instead of 0.0.0.0/0
|
|
1930
|
+
if route.destination_cidr_block == "0.0.0.0/0"
|
|
1931
|
+
return true if !route.instance_id.nil?
|
|
1932
|
+
return true if route.nat_gateway_id
|
|
1933
|
+
end
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
return true
|
|
1937
|
+
end
|
|
1938
|
+
end
|
|
1939
|
+
|
|
1940
|
+
end #class
|
|
1941
|
+
end #class
|
|
1942
|
+
end
|
|
1943
|
+
end #module
|