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,1510 @@
|
|
|
1
|
+
# Copyright:: Copyright (c) 2017 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
|
+
require 'net/ssh'
|
|
16
|
+
require 'net/ssh/multi'
|
|
17
|
+
require 'net/ssh/proxy/command'
|
|
18
|
+
autoload :OpenStruct, "ostruct"
|
|
19
|
+
autoload :Timeout, "timeout"
|
|
20
|
+
autoload :ERB, "erb"
|
|
21
|
+
autoload :Base64, "base64"
|
|
22
|
+
require 'open-uri'
|
|
23
|
+
|
|
24
|
+
module MU
|
|
25
|
+
class Cloud
|
|
26
|
+
class Google
|
|
27
|
+
# A server as configured in {MU::Config::BasketofKittens::servers}. In
|
|
28
|
+
# Google Cloud, this amounts to a single Instance in an Unmanaged
|
|
29
|
+
# Instance Group.
|
|
30
|
+
class Server < MU::Cloud::Server
|
|
31
|
+
|
|
32
|
+
attr_reader :mu_name
|
|
33
|
+
attr_reader :config
|
|
34
|
+
attr_reader :deploy
|
|
35
|
+
attr_reader :cloud_id
|
|
36
|
+
attr_reader :cloud_desc
|
|
37
|
+
attr_reader :groomer
|
|
38
|
+
attr_accessor :mu_windows_name
|
|
39
|
+
|
|
40
|
+
# @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
|
|
41
|
+
# @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::servers}
|
|
42
|
+
def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
|
|
43
|
+
@deploy = mommacat
|
|
44
|
+
@config = MU::Config.manxify(kitten_cfg)
|
|
45
|
+
@cloud_id = cloud_id
|
|
46
|
+
|
|
47
|
+
if @deploy
|
|
48
|
+
@userdata = MU::Cloud.fetchUserdata(
|
|
49
|
+
platform: @config["platform"],
|
|
50
|
+
cloud: "google",
|
|
51
|
+
template_variables: {
|
|
52
|
+
"deployKey" => Base64.urlsafe_encode64(@deploy.public_key),
|
|
53
|
+
"deploySSHKey" => @deploy.ssh_public_key,
|
|
54
|
+
"muID" => MU.deploy_id,
|
|
55
|
+
"muUser" => MU.mu_user,
|
|
56
|
+
"publicIP" => MU.mu_public_ip,
|
|
57
|
+
"skipApplyUpdates" => @config['skipinitialupdates'],
|
|
58
|
+
"windowsAdminName" => @config['windows_admin_username'],
|
|
59
|
+
"resourceName" => @config["name"],
|
|
60
|
+
"resourceType" => "server",
|
|
61
|
+
"platform" => @config["platform"]
|
|
62
|
+
},
|
|
63
|
+
custom_append: @config['userdata_script']
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if !mu_name.nil?
|
|
68
|
+
@mu_name = mu_name
|
|
69
|
+
@config['mu_name'] = @mu_name
|
|
70
|
+
# describe
|
|
71
|
+
@mu_windows_name = @deploydata['mu_windows_name'] if @mu_windows_name.nil? and @deploydata
|
|
72
|
+
else
|
|
73
|
+
if kitten_cfg.has_key?("basis")
|
|
74
|
+
@mu_name = @deploy.getResourceName(@config['name'], need_unique_string: true)
|
|
75
|
+
else
|
|
76
|
+
@mu_name = @deploy.getResourceName(@config['name'])
|
|
77
|
+
end
|
|
78
|
+
@config['mu_name'] = @mu_name
|
|
79
|
+
|
|
80
|
+
@config['instance_secret'] = Password.random(50)
|
|
81
|
+
end
|
|
82
|
+
@config['ssh_user'] ||= "mu"
|
|
83
|
+
@groomer = MU::Groomer.new(self)
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Generate a server-class specific service account, used to grant
|
|
88
|
+
# permission to do various API things to a node.
|
|
89
|
+
# @param rolename [String]:
|
|
90
|
+
# @param project [String]:
|
|
91
|
+
# @param scopes [Array<String>]: https://developers.google.com/identity/protocols/googlescopes
|
|
92
|
+
def self.createServiceAccount(rolename, project: MU::Cloud::Google.defaultProject, scopes: ["https://www.googleapis.com/auth/compute.readonly", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/cloud-platform"])
|
|
93
|
+
#https://www.googleapis.com/auth/devstorage.read_only ?
|
|
94
|
+
name = MU::Cloud::Google.nameStr(rolename)
|
|
95
|
+
|
|
96
|
+
saobj = MU::Cloud::Google.iam(:CreateServiceAccountRequest).new(
|
|
97
|
+
account_id: rolename.gsub(/[^a-z]/, ""), # XXX this mangling isn't required in the console, so why is it here?
|
|
98
|
+
service_account: MU::Cloud::Google.iam(:ServiceAccount).new(
|
|
99
|
+
display_name: rolename,
|
|
100
|
+
# do NOT specify project_id or name, we know that much
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
resp = MU::Cloud::Google.iam.create_service_account(
|
|
104
|
+
"projects/#{project}",
|
|
105
|
+
saobj
|
|
106
|
+
)
|
|
107
|
+
MU::Cloud::Google.compute(:ServiceAccount).new(
|
|
108
|
+
email: resp.email,
|
|
109
|
+
scopes: scopes
|
|
110
|
+
)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Retrieve the cloud descriptor for this machine image, which can be
|
|
114
|
+
# a whole or partial URL. Will follow deprecation notices and retrieve
|
|
115
|
+
# the latest version, if applicable.
|
|
116
|
+
# @param image_id [String]: URL to a Google disk image
|
|
117
|
+
# @return [Google::Apis::ComputeBeta::Image]
|
|
118
|
+
def self.fetchImage(image_id)
|
|
119
|
+
img_proj = img_name = nil
|
|
120
|
+
begin
|
|
121
|
+
img_proj = image_id.gsub(/.*?\/?projects\/([^\/]+)\/.*/, '\1')
|
|
122
|
+
img_name = image_id.gsub(/.*?([^\/]+)$/, '\1')
|
|
123
|
+
img = MU::Cloud::Google.compute.get_image(img_proj, img_name)
|
|
124
|
+
if !img.deprecated.nil? and !img.deprecated.replacement.nil?
|
|
125
|
+
image_id = img.deprecated.replacement
|
|
126
|
+
end
|
|
127
|
+
end while !img.deprecated.nil? and img.deprecated.state == "DEPRECATED" and !img.deprecated.replacement.nil?
|
|
128
|
+
MU::Cloud::Google.compute.get_image(img_proj, img_name)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Generator for disk configuration parameters for a Compute instance
|
|
132
|
+
# @param config [Hash]: The MU::Cloud::Server config hash for whom we're configuring disks
|
|
133
|
+
# @param create [Boolean]: Actually create extra (non-root) disks, or just the one declared as the root disk of the image
|
|
134
|
+
# @param disk_as_url [Boolean]: Whether to declare the disk type as a short string or full URL, which can vary depending on the calling resource
|
|
135
|
+
# @return [Array]: The Compute :AttachedDisk objects describing disks that've been created
|
|
136
|
+
def self.diskConfig(config, create = true, disk_as_url = true)
|
|
137
|
+
disks = []
|
|
138
|
+
puts config['image_id']
|
|
139
|
+
puts config['basis']
|
|
140
|
+
|
|
141
|
+
img = fetchImage(config['image_id'] || config['basis']['launch_config']['image_id'])
|
|
142
|
+
|
|
143
|
+
# XXX slurp settings from /dev/sda or w/e by convention?
|
|
144
|
+
disktype = "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-standard"
|
|
145
|
+
disktype = "pd-standard" if !disk_as_url
|
|
146
|
+
# disk_type: projects/project/zones/#{config['availability_zone']}/diskTypes/pd-standard Other values include pd-ssd and local-ssd
|
|
147
|
+
imageobj = MU::Cloud::Google.compute(:AttachedDiskInitializeParams).new(
|
|
148
|
+
source_image: img.self_link,
|
|
149
|
+
disk_size_gb: 10, # this is binary? 2gb, that says
|
|
150
|
+
disk_type: disktype,
|
|
151
|
+
)
|
|
152
|
+
disks << MU::Cloud::Google.compute(:AttachedDisk).new(
|
|
153
|
+
auto_delete: true,
|
|
154
|
+
boot: true,
|
|
155
|
+
mode: "READ_WRITE",
|
|
156
|
+
type: "PERSISTENT",
|
|
157
|
+
initialize_params: imageobj
|
|
158
|
+
)
|
|
159
|
+
if config["storage"]
|
|
160
|
+
config["storage"].each { |vol|
|
|
161
|
+
devicename = vol['device'].gsub(/[^\w\-\.]/, "-").sub(/^[^\w]/, "")
|
|
162
|
+
disk_desc = {
|
|
163
|
+
:auto_delete => true,
|
|
164
|
+
:device_name => devicename, # XXX empty string is also legit
|
|
165
|
+
:mode => "READ_WRITE",
|
|
166
|
+
:type => "PERSISTENT" # SCRATCH is equivalent of ephemeral? cheap virtual memory disk? maybe ship a standard set
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if vol['snapshot_id']
|
|
170
|
+
disk_desc[:source_snapshot] = vol['snapshot_id']
|
|
171
|
+
# XXX check existence in in validateConfig
|
|
172
|
+
elsif vol['somekindofidforaloosevolume']
|
|
173
|
+
disk_desc[:source] = vol['somekindofidforaloosevolume']
|
|
174
|
+
# XXX check existence in in validateConfig
|
|
175
|
+
end
|
|
176
|
+
# XXX I don't know how to do this in managed instance groups
|
|
177
|
+
#next
|
|
178
|
+
next if !create
|
|
179
|
+
diskname = MU::Cloud::Google.nameStr(config['mu_name']+"-"+devicename)
|
|
180
|
+
newdiskobj = MU::Cloud::Google.compute(:Disk).new(
|
|
181
|
+
size_gb: vol['size'],
|
|
182
|
+
description: MU.deploy_id,
|
|
183
|
+
zone: config['availability_zone'],
|
|
184
|
+
# type: "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-ssd",
|
|
185
|
+
type: "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-standard",
|
|
186
|
+
source_snapshot: vol['snapshot_id'],
|
|
187
|
+
# type: projects/project/zones/#{config['availability_zone']}/diskTypes/pd-standard Other values include pd-ssd and local-ssd
|
|
188
|
+
name: diskname
|
|
189
|
+
)
|
|
190
|
+
MU.log "Creating disk #{diskname}", details: newdiskobj
|
|
191
|
+
|
|
192
|
+
newdisk = MU::Cloud::Google.compute.insert_disk(
|
|
193
|
+
config['project'],
|
|
194
|
+
config['availability_zone'],
|
|
195
|
+
newdiskobj
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
disk_desc[:source] = newdisk.self_link
|
|
199
|
+
|
|
200
|
+
disks << MU::Cloud::Google.compute(:AttachedDisk).new(disk_desc)
|
|
201
|
+
}
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
disks
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Generator for disk configuration parameters for a Compute instance
|
|
208
|
+
# @param config [Hash]: The MU::Cloud::Server config hash for whom we're configuring network interfaces
|
|
209
|
+
# @param vpc [MU::Cloud::Google::VPC]: The VPC in which this interface should reside
|
|
210
|
+
# @return [Array]: Configuration objects for network interfaces, suitable for passing to the Compute API
|
|
211
|
+
def self.interfaceConfig(config, vpc)
|
|
212
|
+
subnet_cfg = config['vpc']
|
|
213
|
+
if config['vpc']['subnets'] and
|
|
214
|
+
!subnet_cfg['subnet_name'] and !subnet_cfg['subnet_id']
|
|
215
|
+
subnet_cfg = config['vpc']['subnets'].sample
|
|
216
|
+
|
|
217
|
+
end
|
|
218
|
+
subnet = vpc.getSubnet(name: subnet_cfg['subnet_name'], cloud_id: subnet_cfg['subnet_id'])
|
|
219
|
+
if subnet.nil?
|
|
220
|
+
raise MuError, "Couldn't find subnet details while configuring Server #{config['name']} (VPC: #{vpc.mu_name})"
|
|
221
|
+
end
|
|
222
|
+
base_iface_obj = {
|
|
223
|
+
:network => vpc.url,
|
|
224
|
+
:subnetwork => subnet.url
|
|
225
|
+
}
|
|
226
|
+
if config['associate_public_ip']
|
|
227
|
+
base_iface_obj[:access_configs] = [
|
|
228
|
+
MU::Cloud::Google.compute(:AccessConfig).new
|
|
229
|
+
]
|
|
230
|
+
end
|
|
231
|
+
interfaces = [base_iface_obj]
|
|
232
|
+
# XXX add more if they asked for it (e.g. config['private_ip'])
|
|
233
|
+
|
|
234
|
+
interfaces
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Called automatically by {MU::Deploy#createResources}
|
|
238
|
+
def create
|
|
239
|
+
|
|
240
|
+
service_acct = MU::Cloud::Google::Server.createServiceAccount(
|
|
241
|
+
@mu_name.downcase,
|
|
242
|
+
project: @config['project']
|
|
243
|
+
)
|
|
244
|
+
MU::Cloud::Google.grantDeploySecretAccess(service_acct.email)
|
|
245
|
+
|
|
246
|
+
begin
|
|
247
|
+
disks = MU::Cloud::Google::Server.diskConfig(@config)
|
|
248
|
+
interfaces = MU::Cloud::Google::Server.interfaceConfig(@config, @vpc)
|
|
249
|
+
|
|
250
|
+
if @config['routes']
|
|
251
|
+
@config['routes'].each { |route|
|
|
252
|
+
@vpc.cloudobj.createRouteForInstance(route, self)
|
|
253
|
+
}
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
desc = {
|
|
257
|
+
:name => MU::Cloud::Google.nameStr(@mu_name),
|
|
258
|
+
:can_ip_forward => !@config['src_dst_check'],
|
|
259
|
+
:description => @deploy.deploy_id,
|
|
260
|
+
:service_accounts => [service_acct],
|
|
261
|
+
:network_interfaces => interfaces,
|
|
262
|
+
:machine_type => "zones/"+@config['availability_zone']+"/machineTypes/"+@config['size'],
|
|
263
|
+
:metadata => {
|
|
264
|
+
:items => [
|
|
265
|
+
{
|
|
266
|
+
:key => "ssh-keys",
|
|
267
|
+
:value => @config['ssh_user']+":"+@deploy.ssh_public_key
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
:key => "startup-script",
|
|
271
|
+
:value => @userdata
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
},
|
|
275
|
+
:tags => MU::Cloud::Google.compute(:Tags).new(items: [MU::Cloud::Google.nameStr(@mu_name)])
|
|
276
|
+
}
|
|
277
|
+
desc[:disks] = disks if disks.size > 0
|
|
278
|
+
|
|
279
|
+
# Tags in GCP means something other than what we think of;
|
|
280
|
+
# labels are the thing you think you mean
|
|
281
|
+
desc[:labels] = {}
|
|
282
|
+
MU::MommaCat.listStandardTags.each_pair { |name, value|
|
|
283
|
+
if !value.nil?
|
|
284
|
+
desc[:labels][name.downcase] = value.downcase.gsub(/[^a-z0-9\-\_]/i, "_")
|
|
285
|
+
end
|
|
286
|
+
}
|
|
287
|
+
desc[:labels]["name"] = @mu_name.downcase
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
instanceobj = MU::Cloud::Google.compute(:Instance).new(desc)
|
|
291
|
+
|
|
292
|
+
MU.log "Creating instance #{@mu_name}"
|
|
293
|
+
begin
|
|
294
|
+
instance = MU::Cloud::Google.compute.insert_instance(
|
|
295
|
+
@config['project'],
|
|
296
|
+
@config['availability_zone'],
|
|
297
|
+
instanceobj
|
|
298
|
+
)
|
|
299
|
+
rescue ::Google::Apis::ClientError => e
|
|
300
|
+
MU.log e.message, MU::ERR
|
|
301
|
+
raise e
|
|
302
|
+
end
|
|
303
|
+
@cloud_id = instance.name # XXX or instance.target_link... pick a convention, would you?
|
|
304
|
+
|
|
305
|
+
if !@config['async_groom']
|
|
306
|
+
sleep 5
|
|
307
|
+
MU::MommaCat.lock(@cloud_id+"-create")
|
|
308
|
+
if !postBoot
|
|
309
|
+
MU.log "#{@config['name']} is already being groomed, skipping", MU::NOTICE
|
|
310
|
+
else
|
|
311
|
+
MU.log "Node creation complete for #{@config['name']}"
|
|
312
|
+
end
|
|
313
|
+
MU::MommaCat.unlock(@cloud_id+"-create")
|
|
314
|
+
end
|
|
315
|
+
done = false
|
|
316
|
+
|
|
317
|
+
@deploy.saveNodeSecret(@cloud_id, @config['instance_secret'], "instance_secret")
|
|
318
|
+
@config.delete("instance_secret")
|
|
319
|
+
|
|
320
|
+
if cloud_desc.nil? or cloud_desc.status != "RUNNING"
|
|
321
|
+
raiseert MuError, "#{@cloud_id} appears to have gone sideways mid-bootstrap #{cloud_desc.status if cloud_desc.nil?}"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
notify
|
|
325
|
+
|
|
326
|
+
rescue Exception => e
|
|
327
|
+
if !cloud_desc.nil? and !done
|
|
328
|
+
MU.log "Aborted before I could finish setting up #{@config['name']}, cleaning it up. Stack trace will print once cleanup is complete.", MU::WARN if !@deploy.nocleanup
|
|
329
|
+
MU::MommaCat.unlockAll
|
|
330
|
+
if !@deploy.nocleanup
|
|
331
|
+
parent_thread_id = Thread.current.object_id
|
|
332
|
+
Thread.new {
|
|
333
|
+
MU.dupGlobals(parent_thread_id)
|
|
334
|
+
MU::Cloud::Google::Server.cleanup(noop: false, ignoremaster: false, skipsnapshots: true)
|
|
335
|
+
}
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
raise e
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
return @config
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Return a BoK-style config hash describing a NAT instance. We use this
|
|
345
|
+
# to approximate Amazon's NAT gateway functionality with a plain
|
|
346
|
+
# instance.
|
|
347
|
+
# @return [Hash]
|
|
348
|
+
def self.genericNAT
|
|
349
|
+
return {
|
|
350
|
+
"cloud" => "Google",
|
|
351
|
+
"size" => "g1-small",
|
|
352
|
+
"run_list" => [ "mu-utility::nat" ],
|
|
353
|
+
"platform" => "centos7",
|
|
354
|
+
"ssh_user" => "centos",
|
|
355
|
+
"associate_public_ip" => true,
|
|
356
|
+
"static_ip" => { "assign_ip" => true },
|
|
357
|
+
"routes" => [ {
|
|
358
|
+
"gateway" => "#INTERNET",
|
|
359
|
+
"priority" => 50,
|
|
360
|
+
"destination_network" => "0.0.0.0/0"
|
|
361
|
+
} ]
|
|
362
|
+
}
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# Ask the Google API to stop this node
|
|
366
|
+
def stop
|
|
367
|
+
MU.log "Stopping #{@cloud_id}"
|
|
368
|
+
MU::Cloud::Google.compute.stop_instance(
|
|
369
|
+
@config['project'],
|
|
370
|
+
@config['availability_zone'],
|
|
371
|
+
@cloud_id
|
|
372
|
+
)
|
|
373
|
+
begin
|
|
374
|
+
sleep 5
|
|
375
|
+
end while cloud_desc.status != "TERMINATED" # means STOPPED
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
# Ask the Google API to start this node
|
|
379
|
+
def start
|
|
380
|
+
MU.log "Starting #{@cloud_id}"
|
|
381
|
+
MU::Cloud::Google.compute.start_instance(
|
|
382
|
+
@config['project'],
|
|
383
|
+
@config['availability_zone'],
|
|
384
|
+
@cloud_id
|
|
385
|
+
)
|
|
386
|
+
begin
|
|
387
|
+
sleep 5
|
|
388
|
+
end while cloud_desc.status != "RUNNING"
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Ask the Google API to restart this node
|
|
392
|
+
def reboot(hard = false)
|
|
393
|
+
return if @cloud_id.nil?
|
|
394
|
+
|
|
395
|
+
if hard
|
|
396
|
+
groupname = nil
|
|
397
|
+
if !@config['basis'].nil?
|
|
398
|
+
resp = MU::Cloud::AWS.autoscale(@config['region']).describe_auto_scaling_instances(
|
|
399
|
+
instance_ids: [@cloud_id]
|
|
400
|
+
)
|
|
401
|
+
groupname = resp.auto_scaling_instances.first.auto_scaling_group_name
|
|
402
|
+
MU.log "Pausing Autoscale processes in #{groupname}", MU::NOTICE
|
|
403
|
+
MU::Cloud::AWS.autoscale(@config['region']).suspend_processes(
|
|
404
|
+
auto_scaling_group_name: groupname
|
|
405
|
+
)
|
|
406
|
+
end
|
|
407
|
+
begin
|
|
408
|
+
MU.log "Stopping #{@mu_name} (#{@cloud_id})", MU::NOTICE
|
|
409
|
+
MU::Cloud::AWS.ec2(@config['region']).stop_instances(
|
|
410
|
+
instance_ids: [@cloud_id]
|
|
411
|
+
)
|
|
412
|
+
MU::Cloud::AWS.ec2(@config['region']).wait_until(:instance_stopped, instance_ids: [@cloud_id]) do |waiter|
|
|
413
|
+
waiter.before_attempt do |attempts|
|
|
414
|
+
MU.log "Waiting for #{@mu_name} to stop for hard reboot"
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
MU.log "Starting #{@mu_name} (#{@cloud_id})"
|
|
418
|
+
MU::Cloud::AWS.ec2(@config['region']).start_instances(
|
|
419
|
+
instance_ids: [@cloud_id]
|
|
420
|
+
)
|
|
421
|
+
ensure
|
|
422
|
+
if !groupname.nil?
|
|
423
|
+
MU.log "Resuming Autoscale processes in #{groupname}", MU::NOTICE
|
|
424
|
+
MU::Cloud::AWS.autoscale(@config['region']).resume_processes(
|
|
425
|
+
auto_scaling_group_name: groupname
|
|
426
|
+
)
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
else
|
|
430
|
+
MU.log "Rebooting #{@mu_name} (#{@cloud_id})"
|
|
431
|
+
MU::Cloud::AWS.ec2(@config['region']).reboot_instances(
|
|
432
|
+
instance_ids: [@cloud_id]
|
|
433
|
+
)
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
# Figure out what's needed to SSH into this server.
|
|
438
|
+
# @return [Array<String>]: nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name, alternate_names
|
|
439
|
+
def getSSHConfig
|
|
440
|
+
node, config, deploydata = describe(cloud_id: @cloud_id)
|
|
441
|
+
# XXX add some awesome alternate names from metadata and make sure they end
|
|
442
|
+
# up in MU::MommaCat's ssh config wangling
|
|
443
|
+
ssh_keydir = Etc.getpwuid(Process.uid).dir+"/.ssh"
|
|
444
|
+
return nil if @config.nil? or @deploy.nil?
|
|
445
|
+
|
|
446
|
+
nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
|
|
447
|
+
if !@config["vpc"].nil? and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
|
|
448
|
+
|
|
449
|
+
if !@nat.nil?
|
|
450
|
+
if @nat.cloud_desc.nil?
|
|
451
|
+
MU.log "NAT was missing cloud descriptor when called in #{@mu_name}'s getSSHConfig", MU::ERR
|
|
452
|
+
return nil
|
|
453
|
+
end
|
|
454
|
+
foo, bar, baz, nat_ssh_host, nat_ssh_user, nat_ssh_key = @nat.getSSHConfig
|
|
455
|
+
if nat_ssh_user.nil? and !nat_ssh_host.nil?
|
|
456
|
+
MU.log "#{@config["name"]} (#{MU.deploy_id}) is configured to use #{@config['vpc']} NAT #{nat_ssh_host}, but username isn't specified. Guessing root.", MU::ERR, details: caller
|
|
457
|
+
nat_ssh_user = "root"
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
if @config['ssh_user'].nil?
|
|
463
|
+
if windows?
|
|
464
|
+
@config['ssh_user'] = "Administrator"
|
|
465
|
+
else
|
|
466
|
+
@config['ssh_user'] = "root"
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
return [nat_ssh_key, nat_ssh_user, nat_ssh_host, canonicalIP, @config['ssh_user'], @deploy.ssh_key_name]
|
|
471
|
+
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
# Apply tags, bootstrap our configuration management, and other
|
|
475
|
+
# administravia for a new instance.
|
|
476
|
+
def postBoot(instance_id = nil)
|
|
477
|
+
if !instance_id.nil?
|
|
478
|
+
@cloud_id = instance_id
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
instance = cloud_desc
|
|
482
|
+
|
|
483
|
+
node, config, deploydata = describe(cloud_id: @cloud_id)
|
|
484
|
+
instance = cloud_desc
|
|
485
|
+
raise MuError, "Couldn't find instance of #{@mu_name} (#{@cloud_id})" if !instance
|
|
486
|
+
return false if !MU::MommaCat.lock(@cloud_id+"-orchestrate", true)
|
|
487
|
+
return false if !MU::MommaCat.lock(@cloud_id+"-groom", true)
|
|
488
|
+
|
|
489
|
+
# MU::MommaCat.createStandardTags(@cloud_id, region: @config['region'])
|
|
490
|
+
# MU::MommaCat.createTag(@cloud_id, "Name", node, region: @config['region'])
|
|
491
|
+
#
|
|
492
|
+
# if @config['optional_tags']
|
|
493
|
+
# MU::MommaCat.listOptionalTags.each { |key, value|
|
|
494
|
+
# MU::MommaCat.createTag(@cloud_id, key, value, region: @config['region'])
|
|
495
|
+
# }
|
|
496
|
+
# end
|
|
497
|
+
#
|
|
498
|
+
# if !@config['tags'].nil?
|
|
499
|
+
# @config['tags'].each { |tag|
|
|
500
|
+
# MU::MommaCat.createTag(@cloud_id, tag['key'], tag['value'], region: @config['region'])
|
|
501
|
+
# }
|
|
502
|
+
# end
|
|
503
|
+
# MU.log "Tagged #{node} (#{@cloud_id}) with MU-ID=#{MU.deploy_id}", MU::DEBUG
|
|
504
|
+
#
|
|
505
|
+
# Make double sure we don't lose a cached mu_windows_name value.
|
|
506
|
+
if windows? or !@config['active_directory'].nil?
|
|
507
|
+
if @mu_windows_name.nil?
|
|
508
|
+
@mu_windows_name = deploydata['mu_windows_name']
|
|
509
|
+
end
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
# punchAdminNAT
|
|
513
|
+
#
|
|
514
|
+
#
|
|
515
|
+
# # If we came up via AutoScale, the Alarm module won't have had our
|
|
516
|
+
# # instance ID to associate us with itself. So invoke that here.
|
|
517
|
+
# if !@config['basis'].nil? and @config["alarms"] and !@config["alarms"].empty?
|
|
518
|
+
# @config["alarms"].each { |alarm|
|
|
519
|
+
# alarm_obj = MU::MommaCat.findStray(
|
|
520
|
+
# "AWS",
|
|
521
|
+
# "alarms",
|
|
522
|
+
# region: @config["region"],
|
|
523
|
+
# deploy_id: @deploy.deploy_id,
|
|
524
|
+
# name: alarm['name']
|
|
525
|
+
# ).first
|
|
526
|
+
# alarm["dimensions"] = [{:name => "InstanceId", :value => @cloud_id}]
|
|
527
|
+
#
|
|
528
|
+
# if alarm["enable_notifications"]
|
|
529
|
+
# topic_arn = MU::Cloud::AWS::Notification.createTopic(alarm["notification_group"], region: @config["region"])
|
|
530
|
+
# MU::Cloud::AWS::Notification.subscribe(arn: topic_arn, protocol: alarm["notification_type"], endpoint: alarm["notification_endpoint"], region: @config["region"])
|
|
531
|
+
# alarm["alarm_actions"] = [topic_arn]
|
|
532
|
+
# alarm["ok_actions"] = [topic_arn]
|
|
533
|
+
# end
|
|
534
|
+
#
|
|
535
|
+
# alarm_name = alarm_obj ? alarm_obj.cloud_id : "#{node}-#{alarm['name']}".upcase
|
|
536
|
+
#
|
|
537
|
+
# MU::Cloud::AWS::Alarm.setAlarm(
|
|
538
|
+
# name: alarm_name,
|
|
539
|
+
# ok_actions: alarm["ok_actions"],
|
|
540
|
+
# alarm_actions: alarm["alarm_actions"],
|
|
541
|
+
# insufficient_data_actions: alarm["no_data_actions"],
|
|
542
|
+
# metric_name: alarm["metric_name"],
|
|
543
|
+
# namespace: alarm["namespace"],
|
|
544
|
+
# statistic: alarm["statistic"],
|
|
545
|
+
# dimensions: alarm["dimensions"],
|
|
546
|
+
# period: alarm["period"],
|
|
547
|
+
# unit: alarm["unit"],
|
|
548
|
+
# evaluation_periods: alarm["evaluation_periods"],
|
|
549
|
+
# threshold: alarm["threshold"],
|
|
550
|
+
# comparison_operator: alarm["comparison_operator"],
|
|
551
|
+
# region: @config["region"]
|
|
552
|
+
# )
|
|
553
|
+
# }
|
|
554
|
+
# end
|
|
555
|
+
#
|
|
556
|
+
# # We have issues sometimes where our dns_records are pointing at the wrong node name and IP address.
|
|
557
|
+
# # Make sure that doesn't happen. Happens with server pools only
|
|
558
|
+
# if @config['dns_records'] && !@config['dns_records'].empty?
|
|
559
|
+
# @config['dns_records'].each { |dnsrec|
|
|
560
|
+
# if dnsrec.has_key?("name")
|
|
561
|
+
# if dnsrec['name'].start_with?(MU.deploy_id.downcase) && !dnsrec['name'].start_with?(node.downcase)
|
|
562
|
+
# MU.log "DNS records for #{node} seem to be wrong, deleting from current config", MU::WARN, details: dnsrec
|
|
563
|
+
# dnsrec.delete('name')
|
|
564
|
+
# dnsrec.delete('target')
|
|
565
|
+
# end
|
|
566
|
+
# end
|
|
567
|
+
# }
|
|
568
|
+
# end
|
|
569
|
+
|
|
570
|
+
# Unless we're planning on associating a different IP later, set up a
|
|
571
|
+
# DNS entry for this thing and let it sync in the background. We'll
|
|
572
|
+
# come back to it later.
|
|
573
|
+
if @config['static_ip'].nil? && !@named
|
|
574
|
+
MU::MommaCat.nameKitten(self)
|
|
575
|
+
@named = true
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
|
|
579
|
+
if !nat_ssh_host and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
|
|
580
|
+
# XXX check if canonical_ip is in the private ranges
|
|
581
|
+
# raise MuError, "#{node} has no NAT host configured, and I have no other route to it"
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# # Set console termination protection. Autoscale nodes won't set this
|
|
585
|
+
# # by default.
|
|
586
|
+
# MU::Cloud::AWS.ec2(@config['region']).modify_instance_attribute(
|
|
587
|
+
# instance_id: @cloud_id,
|
|
588
|
+
# disable_api_termination: {:value => true}
|
|
589
|
+
# )
|
|
590
|
+
|
|
591
|
+
#MU.log "Let's deal with addressing", MU::WARN, details: cloud_desc
|
|
592
|
+
# If we asked for a public IP address, make sure we get one
|
|
593
|
+
# addrobj = MU::Cloud::Google.compute(:Address).new(
|
|
594
|
+
# name: @mu_name+"-public-ip",
|
|
595
|
+
# description: @deploy.deploy_id
|
|
596
|
+
# )
|
|
597
|
+
# addr_insert = MU::Cloud::Google.compute.insert_global_address(
|
|
598
|
+
# @config['project'],
|
|
599
|
+
## @config['region'],
|
|
600
|
+
# addrobj
|
|
601
|
+
# )
|
|
602
|
+
# pp addr_insert
|
|
603
|
+
# raise "BOOP"
|
|
604
|
+
# has_elastic_ip = false
|
|
605
|
+
# if !instance.public_ip_address.nil?
|
|
606
|
+
# begin
|
|
607
|
+
# resp = MU::Cloud::AWS.ec2((@config['region'])).describe_addresses(public_ips: [instance.public_ip_address])
|
|
608
|
+
# if resp.addresses.size > 0 and resp.addresses.first.instance_id == @cloud_id
|
|
609
|
+
# has_elastic_ip = true
|
|
610
|
+
# end
|
|
611
|
+
# rescue Aws::EC2::Errors::InvalidAddressNotFound => e
|
|
612
|
+
# # XXX this is ok to ignore, it means the public IP isn't Elastic
|
|
613
|
+
# end
|
|
614
|
+
# end
|
|
615
|
+
|
|
616
|
+
# win_admin_password = nil
|
|
617
|
+
# ec2config_password = nil
|
|
618
|
+
# sshd_password = nil
|
|
619
|
+
# if windows?
|
|
620
|
+
# ssh_keydir = "#{Etc.getpwuid(Process.uid).dir}/.ssh"
|
|
621
|
+
# ssh_key_name = @deploy.ssh_key_name
|
|
622
|
+
#
|
|
623
|
+
# if @config['use_cloud_provider_windows_password']
|
|
624
|
+
# win_admin_password = getWindowsAdminPassword
|
|
625
|
+
# elsif @config['windows_auth_vault'] && !@config['windows_auth_vault'].empty?
|
|
626
|
+
# if @config["windows_auth_vault"].has_key?("password_field")
|
|
627
|
+
# win_admin_password = @groomer.getSecret(
|
|
628
|
+
# vault: @config['windows_auth_vault']['vault'],
|
|
629
|
+
# item: @config['windows_auth_vault']['item'],
|
|
630
|
+
# field: @config["windows_auth_vault"]["password_field"]
|
|
631
|
+
# )
|
|
632
|
+
# else
|
|
633
|
+
# win_admin_password = getWindowsAdminPassword
|
|
634
|
+
# end
|
|
635
|
+
#
|
|
636
|
+
# if @config["windows_auth_vault"].has_key?("ec2config_password_field")
|
|
637
|
+
# ec2config_password = @groomer.getSecret(
|
|
638
|
+
# vault: @config['windows_auth_vault']['vault'],
|
|
639
|
+
# item: @config['windows_auth_vault']['item'],
|
|
640
|
+
# field: @config["windows_auth_vault"]["ec2config_password_field"]
|
|
641
|
+
# )
|
|
642
|
+
# end
|
|
643
|
+
#
|
|
644
|
+
# if @config["windows_auth_vault"].has_key?("sshd_password_field")
|
|
645
|
+
# sshd_password = @groomer.getSecret(
|
|
646
|
+
# vault: @config['windows_auth_vault']['vault'],
|
|
647
|
+
# item: @config['windows_auth_vault']['item'],
|
|
648
|
+
# field: @config["windows_auth_vault"]["sshd_password_field"]
|
|
649
|
+
# )
|
|
650
|
+
# end
|
|
651
|
+
# end
|
|
652
|
+
#
|
|
653
|
+
# win_admin_password = MU.generateWindowsPassword if win_admin_password.nil?
|
|
654
|
+
# ec2config_password = MU.generateWindowsPassword if ec2config_password.nil?
|
|
655
|
+
# sshd_password = MU.generateWindowsPassword if sshd_password.nil?
|
|
656
|
+
#
|
|
657
|
+
# # We're creating the vault here so when we run
|
|
658
|
+
# # MU::Cloud::Server.initialSSHTasks and we need to set the Windows
|
|
659
|
+
# # Admin password we can grab it from said vault.
|
|
660
|
+
# creds = {
|
|
661
|
+
# "username" => @config['windows_admin_username'],
|
|
662
|
+
# "password" => win_admin_password,
|
|
663
|
+
# "ec2config_username" => "ec2config",
|
|
664
|
+
# "ec2config_password" => ec2config_password,
|
|
665
|
+
# "sshd_username" => "sshd_service",
|
|
666
|
+
# "sshd_password" => sshd_password
|
|
667
|
+
# }
|
|
668
|
+
# @groomer.saveSecret(vault: @mu_name, item: "windows_credentials", data: creds, permissions: "name:#{@mu_name}")
|
|
669
|
+
# end
|
|
670
|
+
#
|
|
671
|
+
#
|
|
672
|
+
#
|
|
673
|
+
# # If we've asked for additional subnets (and this @config is not a
|
|
674
|
+
# # member of a Server Pool, which has different semantics), create
|
|
675
|
+
# # extra interfaces to accomodate.
|
|
676
|
+
# if !@config['vpc']['subnets'].nil? and @config['basis'].nil?
|
|
677
|
+
# device_index = 1
|
|
678
|
+
# @vpc.subnets { |subnet|
|
|
679
|
+
# subnet_id = subnet.cloud_id
|
|
680
|
+
# MU.log "Adding network interface on subnet #{subnet_id} for #{node}"
|
|
681
|
+
# iface = MU::Cloud::AWS.ec2(@config['region']).create_network_interface(subnet_id: subnet_id).network_interface
|
|
682
|
+
# MU::MommaCat.createStandardTags(iface.network_interface_id, region: @config['region'])
|
|
683
|
+
# MU::MommaCat.createTag(iface.network_interface_id, "Name", node+"-ETH"+device_index.to_s, region: @config['region'])
|
|
684
|
+
#
|
|
685
|
+
# if @config['optional_tags']
|
|
686
|
+
# MU::MommaCat.listOptionalTags.each { |key, value|
|
|
687
|
+
# MU::MommaCat.createTag(iface.network_interface_id, key, value, region: @config['region'])
|
|
688
|
+
# }
|
|
689
|
+
# end
|
|
690
|
+
#
|
|
691
|
+
# if !@config['tags'].nil?
|
|
692
|
+
# @config['tags'].each { |tag|
|
|
693
|
+
# MU::MommaCat.createTag(iface.network_interface_id, tag['key'], tag['value'], region: @config['region'])
|
|
694
|
+
# }
|
|
695
|
+
# end
|
|
696
|
+
#
|
|
697
|
+
# MU::Cloud::AWS.ec2(@config['region']).attach_network_interface(
|
|
698
|
+
# network_interface_id: iface.network_interface_id,
|
|
699
|
+
# instance_id: @cloud_id,
|
|
700
|
+
# device_index: device_index
|
|
701
|
+
# )
|
|
702
|
+
# device_index = device_index + 1
|
|
703
|
+
# }
|
|
704
|
+
# end
|
|
705
|
+
# elsif !@config['static_ip'].nil?
|
|
706
|
+
# if !@config['static_ip']['ip'].nil?
|
|
707
|
+
# public_ip = MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: true, ip: @config['static_ip']['ip'])
|
|
708
|
+
# elsif !has_elastic_ip
|
|
709
|
+
# public_ip = MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: true)
|
|
710
|
+
# end
|
|
711
|
+
# end
|
|
712
|
+
#
|
|
713
|
+
#
|
|
714
|
+
# if !@config['image_then_destroy']
|
|
715
|
+
# notify
|
|
716
|
+
# end
|
|
717
|
+
#
|
|
718
|
+
# MU.log "EC2 instance #{node} has id #{@cloud_id}", MU::DEBUG
|
|
719
|
+
#
|
|
720
|
+
# @config["private_dns_name"] = instance.private_dns_name
|
|
721
|
+
# @config["public_dns_name"] = instance.public_dns_name
|
|
722
|
+
# @config["private_ip_address"] = instance.private_ip_address
|
|
723
|
+
# @config["public_ip_address"] = instance.public_ip_address
|
|
724
|
+
#
|
|
725
|
+
# ext_mappings = MU.structToHash(instance.block_device_mappings)
|
|
726
|
+
#
|
|
727
|
+
# # Root disk on standard CentOS AMI
|
|
728
|
+
# # tagVolumes(@cloud_id, "/dev/sda", "Name", "ROOT-"+MU.deploy_id+"-"+@config["name"].upcase)
|
|
729
|
+
# # Root disk on standard Ubuntu AMI
|
|
730
|
+
# # tagVolumes(@cloud_id, "/dev/sda1", "Name", "ROOT-"+MU.deploy_id+"-"+@config["name"].upcase)
|
|
731
|
+
#
|
|
732
|
+
# # Generic deploy ID tag
|
|
733
|
+
# # tagVolumes(@cloud_id)
|
|
734
|
+
#
|
|
735
|
+
# # Tag volumes with all our standard tags.
|
|
736
|
+
# # Maybe replace tagVolumes with this? There is one more place tagVolumes is called from
|
|
737
|
+
# volumes = MU::Cloud::AWS.ec2(@config['region']).describe_volumes(filters: [name: "attachment.instance-id", values: [@cloud_id]])
|
|
738
|
+
# volumes.each { |vol|
|
|
739
|
+
# vol.volumes.each { |volume|
|
|
740
|
+
# volume.attachments.each { |attachment|
|
|
741
|
+
# MU::MommaCat.listStandardTags.each_pair { |key, value|
|
|
742
|
+
# MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
|
|
743
|
+
#
|
|
744
|
+
# if attachment.device == "/dev/sda" or attachment.device == "/dev/sda1"
|
|
745
|
+
# MU::MommaCat.createTag(attachment.volume_id, "Name", "ROOT-#{MU.deploy_id}-#{@config["name"].upcase}", region: @config['region'])
|
|
746
|
+
# else
|
|
747
|
+
# MU::MommaCat.createTag(attachment.volume_id, "Name", "#{MU.deploy_id}-#{@config["name"].upcase}-#{attachment.device.upcase}", region: @config['region'])
|
|
748
|
+
# end
|
|
749
|
+
# }
|
|
750
|
+
#
|
|
751
|
+
# if @config['optional_tags']
|
|
752
|
+
# MU::MommaCat.listOptionalTags.each { |key, value|
|
|
753
|
+
# MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
|
|
754
|
+
# }
|
|
755
|
+
# end
|
|
756
|
+
#
|
|
757
|
+
# if @config['tags']
|
|
758
|
+
# @config['tags'].each { |tag|
|
|
759
|
+
# MU::MommaCat.createTag(attachment.volume_id, tag['key'], tag['value'], region: @config['region'])
|
|
760
|
+
# }
|
|
761
|
+
# end
|
|
762
|
+
# }
|
|
763
|
+
# }
|
|
764
|
+
# }
|
|
765
|
+
#
|
|
766
|
+
# canonical_name = instance.public_dns_name
|
|
767
|
+
# canonical_name = instance.private_dns_name if !canonical_name or nat_ssh_host != nil
|
|
768
|
+
# @config['canonical_name'] = canonical_name
|
|
769
|
+
#
|
|
770
|
+
# if !@config['add_private_ips'].nil?
|
|
771
|
+
# instance.network_interfaces.each { |int|
|
|
772
|
+
# if int.private_ip_address == instance.private_ip_address and int.private_ip_addresses.size < (@config['add_private_ips'] + 1)
|
|
773
|
+
# MU.log "Adding #{@config['add_private_ips']} extra private IP addresses to #{@cloud_id}"
|
|
774
|
+
# MU::Cloud::AWS.ec2(@config['region']).assign_private_ip_addresses(
|
|
775
|
+
# network_interface_id: int.network_interface_id,
|
|
776
|
+
# secondary_private_ip_address_count: @config['add_private_ips'],
|
|
777
|
+
# allow_reassignment: false
|
|
778
|
+
# )
|
|
779
|
+
# end
|
|
780
|
+
# }
|
|
781
|
+
# notify
|
|
782
|
+
# end
|
|
783
|
+
#
|
|
784
|
+
# windows? ? ssh_wait = 60 : ssh_wait = 30
|
|
785
|
+
# windows? ? max_retries = 50 : max_retries = 35
|
|
786
|
+
# begin
|
|
787
|
+
# session = getSSHSession(max_retries, ssh_wait)
|
|
788
|
+
# initialSSHTasks(session)
|
|
789
|
+
# rescue BootstrapTempFail
|
|
790
|
+
# sleep ssh_wait
|
|
791
|
+
# retry
|
|
792
|
+
# ensure
|
|
793
|
+
# session.close if !session.nil?
|
|
794
|
+
# end
|
|
795
|
+
#
|
|
796
|
+
# if @config["existing_deploys"] && !@config["existing_deploys"].empty?
|
|
797
|
+
# @config["existing_deploys"].each { |ext_deploy|
|
|
798
|
+
# if ext_deploy["cloud_id"]
|
|
799
|
+
# found = MU::MommaCat.findStray(
|
|
800
|
+
# @config['cloud'],
|
|
801
|
+
# ext_deploy["cloud_type"],
|
|
802
|
+
# cloud_id: ext_deploy["cloud_id"],
|
|
803
|
+
# region: @config['region'],
|
|
804
|
+
# dummy_ok: false
|
|
805
|
+
# ).first
|
|
806
|
+
#
|
|
807
|
+
# MU.log "Couldn't find existing resource #{ext_deploy["cloud_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
|
|
808
|
+
# @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: found.mu_name, triggering_node: @mu_name)
|
|
809
|
+
# elsif ext_deploy["mu_name"] && ext_deploy["deploy_id"]
|
|
810
|
+
# MU.log "#{ext_deploy["mu_name"]} / #{ext_deploy["deploy_id"]}"
|
|
811
|
+
# found = MU::MommaCat.findStray(
|
|
812
|
+
# @config['cloud'],
|
|
813
|
+
# ext_deploy["cloud_type"],
|
|
814
|
+
# deploy_id: ext_deploy["deploy_id"],
|
|
815
|
+
# mu_name: ext_deploy["mu_name"],
|
|
816
|
+
# region: @config['region'],
|
|
817
|
+
# dummy_ok: false
|
|
818
|
+
# ).first
|
|
819
|
+
#
|
|
820
|
+
# MU.log "Couldn't find existing resource #{ext_deploy["mu_name"]}/#{ext_deploy["deploy_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
|
|
821
|
+
# @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: ext_deploy["mu_name"], triggering_node: @mu_name)
|
|
822
|
+
# else
|
|
823
|
+
# MU.log "Trying to find existing deploy, but either the cloud_id is not valid or no mu_name and deploy_id where provided", MU::ERR
|
|
824
|
+
# end
|
|
825
|
+
# }
|
|
826
|
+
# end
|
|
827
|
+
|
|
828
|
+
# See if this node already exists in our config management. If it does,
|
|
829
|
+
# we're done.
|
|
830
|
+
if @groomer.haveBootstrapped?
|
|
831
|
+
MU.log "Node #{node} has already been bootstrapped, skipping groomer setup.", MU::NOTICE
|
|
832
|
+
@groomer.saveDeployData
|
|
833
|
+
MU::MommaCat.unlock(@cloud_id+"-orchestrate")
|
|
834
|
+
MU::MommaCat.unlock(@cloud_id+"-groom")
|
|
835
|
+
return true
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
@groomer.bootstrap
|
|
839
|
+
|
|
840
|
+
# Make sure we got our name written everywhere applicable
|
|
841
|
+
if !@named
|
|
842
|
+
MU::MommaCat.nameKitten(self)
|
|
843
|
+
@named = true
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
MU::MommaCat.unlock(@cloud_id+"-groom")
|
|
847
|
+
MU::MommaCat.unlock(@cloud_id+"-orchestrate")
|
|
848
|
+
return true
|
|
849
|
+
end #postBoot
|
|
850
|
+
|
|
851
|
+
# Locate an existing instance or instances and return an array containing matching AWS resource descriptors for those that match.
|
|
852
|
+
# @param cloud_id [String]: The cloud provider's identifier for this resource.
|
|
853
|
+
# @param region [String]: The cloud provider region
|
|
854
|
+
# @param tag_key [String]: A tag key to search.
|
|
855
|
+
# @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
|
|
856
|
+
# @param ip [String]: An IP address associated with the instance
|
|
857
|
+
# @param flags [Hash]: Optional flags
|
|
858
|
+
# @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching instances
|
|
859
|
+
def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, ip: nil, flags: {})
|
|
860
|
+
# XXX put that 'ip' value into flags
|
|
861
|
+
instance = nil
|
|
862
|
+
flags["project"] ||= MU::Cloud::Google.defaultProject
|
|
863
|
+
if !region.nil? and MU::Cloud::Google.listRegions.include?(region)
|
|
864
|
+
regions = [region]
|
|
865
|
+
else
|
|
866
|
+
regions = MU::Cloud::Google.listRegions
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
found_instances = {}
|
|
870
|
+
search_semaphore = Mutex.new
|
|
871
|
+
search_threads = []
|
|
872
|
+
|
|
873
|
+
# If we got an instance id, go get it
|
|
874
|
+
if !cloud_id.nil? and !cloud_id.empty?
|
|
875
|
+
parent_thread_id = Thread.current.object_id
|
|
876
|
+
regions.each { |region|
|
|
877
|
+
search_threads << Thread.new {
|
|
878
|
+
Thread.abort_on_exception = false
|
|
879
|
+
MU.dupGlobals(parent_thread_id)
|
|
880
|
+
MU.log "Hunting for instance with cloud id '#{cloud_id}' in #{region}", MU::DEBUG
|
|
881
|
+
MU::Cloud::Google.listAZs(region).each { |az|
|
|
882
|
+
resp = nil
|
|
883
|
+
begin
|
|
884
|
+
resp = MU::Cloud::Google.compute.get_instance(
|
|
885
|
+
flags["project"],
|
|
886
|
+
az,
|
|
887
|
+
cloud_id
|
|
888
|
+
)
|
|
889
|
+
rescue ::Google::Apis::ClientError => e
|
|
890
|
+
raise e if !e.message.match(/^notFound: /)
|
|
891
|
+
end
|
|
892
|
+
found_instances[cloud_id] = resp if !resp.nil?
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
done_threads = []
|
|
897
|
+
begin
|
|
898
|
+
search_threads.each { |t|
|
|
899
|
+
joined = t.join(2)
|
|
900
|
+
done_threads << joined if !joined.nil?
|
|
901
|
+
}
|
|
902
|
+
end while found_instances.size < 1 and done_threads.size != search_threads.size
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
if found_instances.size > 0
|
|
906
|
+
return found_instances
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
# Ok, well, let's try looking it up by IP then
|
|
910
|
+
if instance.nil? and !ip.nil?
|
|
911
|
+
MU.log "Hunting for instance by IP '#{ip}'", MU::DEBUG
|
|
912
|
+
end
|
|
913
|
+
|
|
914
|
+
if !instance.nil?
|
|
915
|
+
return {instance.name => instance} if !instance.nil?
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
# Fine, let's try it by tag.
|
|
919
|
+
if !tag_value.nil?
|
|
920
|
+
MU.log "Searching for instance by tag '#{tag_key}=#{tag_value}'", MU::DEBUG
|
|
921
|
+
end
|
|
922
|
+
|
|
923
|
+
return found_instances
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
# Return a description of this resource appropriate for deployment
|
|
927
|
+
# metadata. Arguments reflect the return values of the MU::Cloud::[Resource].describe method
|
|
928
|
+
def notify
|
|
929
|
+
node, config, deploydata = describe(cloud_id: @cloud_id, update_cache: true)
|
|
930
|
+
deploydata = {} if deploydata.nil?
|
|
931
|
+
|
|
932
|
+
if cloud_desc.nil?
|
|
933
|
+
raise MuError, "Failed to load instance metadata for #{@config['mu_name']}/#{@cloud_id}"
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
interfaces = []
|
|
937
|
+
private_ips = []
|
|
938
|
+
public_ips = []
|
|
939
|
+
|
|
940
|
+
cloud_desc.network_interfaces.each { |iface|
|
|
941
|
+
private_ips << iface.network_ip
|
|
942
|
+
if iface.access_configs
|
|
943
|
+
iface.access_configs.each { |acfg|
|
|
944
|
+
public_ips << acfg.nat_ip if acfg.nat_ip
|
|
945
|
+
}
|
|
946
|
+
end
|
|
947
|
+
interfaces << {
|
|
948
|
+
"network_interface_id" => iface.name,
|
|
949
|
+
"subnet_id" => iface.subnetwork,
|
|
950
|
+
"vpc_id" => iface.network
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
deploydata = {
|
|
955
|
+
"nodename" => @mu_name,
|
|
956
|
+
"run_list" => @config['run_list'],
|
|
957
|
+
"image_created" => @config['image_created'],
|
|
958
|
+
# "iam_role" => @config['iam_role'],
|
|
959
|
+
"cloud_desc_id" => @cloud_id,
|
|
960
|
+
"private_ip_address" => private_ips.first,
|
|
961
|
+
"public_ip_address" => public_ips.first,
|
|
962
|
+
"private_ip_list" => private_ips,
|
|
963
|
+
# "key_name" => cloud_desc.key_name,
|
|
964
|
+
# "subnet_id" => cloud_desc.subnet_id,
|
|
965
|
+
# "cloud_desc_type" => cloud_desc.instance_type #,
|
|
966
|
+
# "network_interfaces" => interfaces,
|
|
967
|
+
# "config" => server
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
if !@mu_windows_name.nil?
|
|
971
|
+
deploydata["mu_windows_name"] = @mu_windows_name
|
|
972
|
+
end
|
|
973
|
+
if !@config['chef_data'].nil?
|
|
974
|
+
deploydata.merge!(@config['chef_data'])
|
|
975
|
+
end
|
|
976
|
+
deploydata["region"] = @config['region'] if !@config['region'].nil?
|
|
977
|
+
if !@named
|
|
978
|
+
MU::MommaCat.nameKitten(self)
|
|
979
|
+
@named = true
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
return deploydata
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
# Called automatically by {MU::Deploy#createResources}
|
|
986
|
+
def groom
|
|
987
|
+
|
|
988
|
+
MU::MommaCat.lock(@cloud_id+"-groom")
|
|
989
|
+
|
|
990
|
+
node, config, deploydata = describe(cloud_id: @cloud_id)
|
|
991
|
+
|
|
992
|
+
if node.nil? or node.empty?
|
|
993
|
+
raise MuError, "MU::Cloud::Google::Server.groom was called without a mu_name"
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
# Make double sure we don't lose a cached mu_windows_name value.
|
|
997
|
+
if windows? or !@config['active_directory'].nil?
|
|
998
|
+
if @mu_windows_name.nil?
|
|
999
|
+
@mu_windows_name = deploydata['mu_windows_name']
|
|
1000
|
+
end
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
# punchAdminNAT
|
|
1004
|
+
|
|
1005
|
+
# MU::Cloud::AWS::Server.tagVolumes(@cloud_id)
|
|
1006
|
+
|
|
1007
|
+
# If we have a loadbalancer configured, attach us to it
|
|
1008
|
+
# if !@config['loadbalancers'].nil?
|
|
1009
|
+
# if @loadbalancers.nil?
|
|
1010
|
+
# raise MuError, "#{@mu_name} is configured to use LoadBalancers, but none have been loaded by dependencies()"
|
|
1011
|
+
# end
|
|
1012
|
+
# @loadbalancers.each { |lb|
|
|
1013
|
+
# lb.registerNode(@cloud_id)
|
|
1014
|
+
# }
|
|
1015
|
+
# end
|
|
1016
|
+
|
|
1017
|
+
# Let us into any databases we depend on.
|
|
1018
|
+
# This is probelmtic with autscaling - old ips are not removed, and access to the database can easily be given at the BoK level
|
|
1019
|
+
# if @dependencies.has_key?("database")
|
|
1020
|
+
# @dependencies['database'].values.each { |db|
|
|
1021
|
+
# db.allowHost(@deploydata["private_ip_address"]+"/32")
|
|
1022
|
+
# if @deploydata["public_ip_address"]
|
|
1023
|
+
# db.allowHost(@deploydata["public_ip_address"]+"/32")
|
|
1024
|
+
# end
|
|
1025
|
+
# }
|
|
1026
|
+
# end
|
|
1027
|
+
|
|
1028
|
+
@groomer.saveDeployData
|
|
1029
|
+
|
|
1030
|
+
begin
|
|
1031
|
+
@groomer.run(purpose: "Full Initial Run", max_retries: 15)
|
|
1032
|
+
rescue MU::Groomer::RunError
|
|
1033
|
+
MU.log "Proceeding after failed initial Groomer run, but #{node} may not behave as expected!", MU::WARN
|
|
1034
|
+
end
|
|
1035
|
+
|
|
1036
|
+
if !@config['create_image'].nil? and !@config['image_created']
|
|
1037
|
+
img_cfg = @config['create_image']
|
|
1038
|
+
# Scrub things that don't belong on an AMI
|
|
1039
|
+
session = getSSHSession
|
|
1040
|
+
sudo = purgecmd = ""
|
|
1041
|
+
sudo = "sudo" if @config['ssh_user'] != "root"
|
|
1042
|
+
if windows?
|
|
1043
|
+
purgecmd = "rm -rf /cygdrive/c/mu_installed_chef"
|
|
1044
|
+
else
|
|
1045
|
+
purgecmd = "rm -rf /opt/mu_installed_chef"
|
|
1046
|
+
end
|
|
1047
|
+
if img_cfg['image_then_destroy']
|
|
1048
|
+
if windows?
|
|
1049
|
+
purgecmd = "rm -rf /cygdrive/c/chef/ /home/#{@config['windows_admin_username']}/.ssh/authorized_keys /home/Administrator/.ssh/authorized_keys /cygdrive/c/mu-installer-ran-updates /cygdrive/c/mu_installed_chef"
|
|
1050
|
+
# session.exec!("powershell -Command \"& {(Get-WmiObject -Class Win32_Product -Filter \"Name='UniversalForwarder'\").Uninstall()}\"")
|
|
1051
|
+
else
|
|
1052
|
+
purgecmd = "#{sudo} rm -rf /root/.ssh/authorized_keys /etc/ssh/ssh_host_*key* /etc/chef /etc/opscode/* /.mu-installer-ran-updates /var/chef /opt/mu_installed_chef /opt/chef ; #{sudo} sed -i 's/^HOSTNAME=.*//' /etc/sysconfig/network"
|
|
1053
|
+
end
|
|
1054
|
+
end
|
|
1055
|
+
session.exec!(purgecmd)
|
|
1056
|
+
session.close
|
|
1057
|
+
stop
|
|
1058
|
+
image_id = MU::Cloud::Google::Server.createImage(
|
|
1059
|
+
name: MU::Cloud::Google.nameStr(@mu_name),
|
|
1060
|
+
instance_id: @cloud_id,
|
|
1061
|
+
region: @config['region'],
|
|
1062
|
+
storage: @config['storage'],
|
|
1063
|
+
family: ("mu-"+@config['platform']+"-"+MU.environment).downcase,
|
|
1064
|
+
project: @config['project'],
|
|
1065
|
+
exclude_storage: img_cfg['image_exclude_storage'],
|
|
1066
|
+
make_public: img_cfg['public'],
|
|
1067
|
+
tags: @config['tags'],
|
|
1068
|
+
zone: @config['availability_zone']
|
|
1069
|
+
)
|
|
1070
|
+
@deploy.notify("images", @config['name'], {"image_id" => image_id})
|
|
1071
|
+
@config['image_created'] = true
|
|
1072
|
+
if img_cfg['image_then_destroy']
|
|
1073
|
+
MU.log "Image #{image_id} ready, removing source node #{node}"
|
|
1074
|
+
MU::Cloud::Google.compute.delete_instance(
|
|
1075
|
+
@config['project'],
|
|
1076
|
+
@config['availability_zone'],
|
|
1077
|
+
@cloud_id
|
|
1078
|
+
)
|
|
1079
|
+
destroy
|
|
1080
|
+
else
|
|
1081
|
+
start
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
MU::MommaCat.unlock(@cloud_id+"-groom")
|
|
1086
|
+
end
|
|
1087
|
+
|
|
1088
|
+
# Create an image out of a running server. Requires either the name of a MU resource in the current deployment, or the cloud provider id of a running instance.
|
|
1089
|
+
# @param name [String]: The MU resource name of the server to use as the basis for this image.
|
|
1090
|
+
# @param instance_id [String]: The cloud provider resource identifier of the server to use as the basis for this image.
|
|
1091
|
+
# @param storage [Hash]: The storage devices to include in this image.
|
|
1092
|
+
# @param exclude_storage [Boolean]: Do not include the storage device profile of the running instance when creating this image.
|
|
1093
|
+
# @param region [String]: The cloud provider region
|
|
1094
|
+
# @param tags [Array<String>]: Extra/override tags to apply to the image.
|
|
1095
|
+
# @return [String]: The cloud provider identifier of the new machine image.
|
|
1096
|
+
def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, project: MU::Cloud::Google.defaultProject, make_public: false, tags: [], region: nil, family: "mu", zone: MU::Cloud::Google.listAZs.sample)
|
|
1097
|
+
instance = MU::Cloud::Server.find(cloud_id: instance_id, region: region)
|
|
1098
|
+
if instance.nil?
|
|
1099
|
+
raise MuError, "Failed to find instance '#{instance_id}' in createImage"
|
|
1100
|
+
end
|
|
1101
|
+
|
|
1102
|
+
labels = {}
|
|
1103
|
+
MU::MommaCat.listStandardTags.each_pair { |key, value|
|
|
1104
|
+
if !value.nil?
|
|
1105
|
+
labels[key.downcase] = value.downcase.gsub(/[^a-z0-9\-\_]/i, "_")
|
|
1106
|
+
end
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
bootdisk = nil
|
|
1110
|
+
threads = []
|
|
1111
|
+
parent_thread_id = Thread.current.object_id
|
|
1112
|
+
instance[instance_id].disks.each { |disk|
|
|
1113
|
+
threads << Thread.new {
|
|
1114
|
+
Thread.abort_on_exception = false
|
|
1115
|
+
MU.dupGlobals(parent_thread_id)
|
|
1116
|
+
if disk.boot
|
|
1117
|
+
bootdisk = disk.source
|
|
1118
|
+
else
|
|
1119
|
+
snapobj = MU::Cloud::Google.compute(:Snapshot).new(
|
|
1120
|
+
name: name+"-"+disk.device_name,
|
|
1121
|
+
description: "Mu image created from #{name} (#{disk.device_name})"
|
|
1122
|
+
)
|
|
1123
|
+
diskname = disk.source.gsub(/.*?\//, "")
|
|
1124
|
+
MU.log "Creating snapshot of #{diskname} in #{zone}", MU::NOTICE, details: snapobj
|
|
1125
|
+
snap = MU::Cloud::Google.compute.create_disk_snapshot(
|
|
1126
|
+
project,
|
|
1127
|
+
zone,
|
|
1128
|
+
diskname,
|
|
1129
|
+
snapobj
|
|
1130
|
+
)
|
|
1131
|
+
MU::Cloud::Google.compute.set_snapshot_labels(
|
|
1132
|
+
project,
|
|
1133
|
+
snap.name,
|
|
1134
|
+
MU::Cloud::Google.compute(:GlobalSetLabelsRequest).new(
|
|
1135
|
+
label_fingerprint: snap.label_fingerprint,
|
|
1136
|
+
labels: labels.merge({
|
|
1137
|
+
"mu-device-name" => disk.device_name,
|
|
1138
|
+
"mu-parent-image" => name,
|
|
1139
|
+
"mu-orig-zone" => zone
|
|
1140
|
+
})
|
|
1141
|
+
)
|
|
1142
|
+
)
|
|
1143
|
+
end
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
threads.each do |t|
|
|
1147
|
+
t.join
|
|
1148
|
+
end
|
|
1149
|
+
|
|
1150
|
+
labels["name"] = instance_id.downcase
|
|
1151
|
+
imageobj = MU::Cloud::Google.compute(:Image).new(
|
|
1152
|
+
name: name,
|
|
1153
|
+
source_disk: bootdisk,
|
|
1154
|
+
description: "Mu image created from #{name}",
|
|
1155
|
+
labels: labels,
|
|
1156
|
+
family: family
|
|
1157
|
+
)
|
|
1158
|
+
|
|
1159
|
+
newimage = MU::Cloud::Google.compute.insert_image(
|
|
1160
|
+
project,
|
|
1161
|
+
imageobj
|
|
1162
|
+
)
|
|
1163
|
+
newimage.name
|
|
1164
|
+
end
|
|
1165
|
+
|
|
1166
|
+
def cloud_desc
|
|
1167
|
+
max_retries = 5
|
|
1168
|
+
retries = 0
|
|
1169
|
+
if !@cloud_id.nil?
|
|
1170
|
+
begin
|
|
1171
|
+
return MU::Cloud::Google.compute.get_instance(
|
|
1172
|
+
@config['project'],
|
|
1173
|
+
@config['availability_zone'],
|
|
1174
|
+
@cloud_id
|
|
1175
|
+
)
|
|
1176
|
+
rescue ::Google::Apis::ClientError => e
|
|
1177
|
+
if e.message.match(/^notFound: /)
|
|
1178
|
+
return nil
|
|
1179
|
+
else
|
|
1180
|
+
raise e
|
|
1181
|
+
end
|
|
1182
|
+
end
|
|
1183
|
+
end
|
|
1184
|
+
nil
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1187
|
+
def cloud_desc
|
|
1188
|
+
MU::Cloud::Google::Server.find(cloud_id: @cloud_id).values.first
|
|
1189
|
+
end
|
|
1190
|
+
|
|
1191
|
+
# Return the IP address that we, the Mu server, should be using to access
|
|
1192
|
+
# this host via the network. Note that this does not factor in SSH
|
|
1193
|
+
# bastion hosts that may be in the path, see getSSHConfig if that's what
|
|
1194
|
+
# you need.
|
|
1195
|
+
def canonicalIP
|
|
1196
|
+
mu_name, config, deploydata = describe(cloud_id: @cloud_id)
|
|
1197
|
+
|
|
1198
|
+
if !cloud_desc
|
|
1199
|
+
raise MuError, "Couldn't retrieve cloud descriptor for server #{self}"
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
private_ips = []
|
|
1203
|
+
public_ips = []
|
|
1204
|
+
|
|
1205
|
+
cloud_desc.network_interfaces.each { |iface|
|
|
1206
|
+
private_ips << iface.network_ip
|
|
1207
|
+
if iface.access_configs
|
|
1208
|
+
iface.access_configs.each { |acfg|
|
|
1209
|
+
public_ips << acfg.nat_ip if acfg.nat_ip
|
|
1210
|
+
}
|
|
1211
|
+
end
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
# Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
|
|
1215
|
+
# which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
|
|
1216
|
+
# The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
|
|
1217
|
+
if MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc) or public_ips.size == 0
|
|
1218
|
+
@config['canonical_ip'] = private_ips.first
|
|
1219
|
+
return private_ips.first
|
|
1220
|
+
else
|
|
1221
|
+
@config['canonical_ip'] = public_ips.first
|
|
1222
|
+
return public_ips.first
|
|
1223
|
+
end
|
|
1224
|
+
end
|
|
1225
|
+
|
|
1226
|
+
# Retrieves the Cloud provider's randomly generated Windows password
|
|
1227
|
+
# Will only work on stock Amazon Windows AMIs or custom AMIs that where created with Administrator Password set to random in EC2Config
|
|
1228
|
+
# return [String]: A password string.
|
|
1229
|
+
def getWindowsAdminPassword
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1232
|
+
# Add a volume to this instance
|
|
1233
|
+
# @param dev [String]: Device name to use when attaching to instance
|
|
1234
|
+
# @param size [String]: Size (in gb) of the new volume
|
|
1235
|
+
# @param type [String]: Cloud storage type of the volume, if applicable
|
|
1236
|
+
def addVolume(dev, size, type: "pd-standard")
|
|
1237
|
+
devname = dev.gsub(/.*?\/([^\/]+)$/, '\1')
|
|
1238
|
+
resname = MU::Cloud::Google.nameStr(@mu_name+"-"+devname)
|
|
1239
|
+
MU.log "Creating disk #{resname}"
|
|
1240
|
+
|
|
1241
|
+
description = @deploy ? @deploy.deploy_id : @mu_name+"-"+devname
|
|
1242
|
+
|
|
1243
|
+
newdiskobj = MU::Cloud::Google.compute(:Disk).new(
|
|
1244
|
+
size_gb: size,
|
|
1245
|
+
description: description,
|
|
1246
|
+
zone: @config['availability_zone'],
|
|
1247
|
+
# type: "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-ssd",
|
|
1248
|
+
type: "projects/#{@config['project']}/zones/#{@config['availability_zone']}/diskTypes/pd-standard",
|
|
1249
|
+
# Other values include pd-ssd and local-ssd
|
|
1250
|
+
name: resname
|
|
1251
|
+
)
|
|
1252
|
+
|
|
1253
|
+
begin
|
|
1254
|
+
newdisk = MU::Cloud::Google.compute.insert_disk(
|
|
1255
|
+
@config['project'],
|
|
1256
|
+
@config['availability_zone'],
|
|
1257
|
+
newdiskobj
|
|
1258
|
+
)
|
|
1259
|
+
rescue ::Google::Apis::ClientError => e
|
|
1260
|
+
if e.message.match(/^alreadyExists: /)
|
|
1261
|
+
MU.log "Disk #{resname} already exists, ignoring request to create", MU::WARN
|
|
1262
|
+
return
|
|
1263
|
+
else
|
|
1264
|
+
raise e
|
|
1265
|
+
end
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
attachobj = MU::Cloud::Google.compute(:AttachedDisk).new(
|
|
1269
|
+
auto_delete: true,
|
|
1270
|
+
device_name: devname,
|
|
1271
|
+
source: newdisk.self_link,
|
|
1272
|
+
type: "PERSISTENT"
|
|
1273
|
+
)
|
|
1274
|
+
attachment = MU::Cloud::Google.compute.attach_disk(
|
|
1275
|
+
@config['project'],
|
|
1276
|
+
@config['availability_zone'],
|
|
1277
|
+
@cloud_id,
|
|
1278
|
+
attachobj
|
|
1279
|
+
)
|
|
1280
|
+
|
|
1281
|
+
end
|
|
1282
|
+
|
|
1283
|
+
# Determine whether the node in question exists at the Cloud provider
|
|
1284
|
+
# layer.
|
|
1285
|
+
# @return [Boolean]
|
|
1286
|
+
def active?
|
|
1287
|
+
true
|
|
1288
|
+
end
|
|
1289
|
+
|
|
1290
|
+
# Remove all instances associated with the currently loaded deployment. Also cleans up associated volumes, droppings in the MU master's /etc/hosts and ~/.ssh, and in whatever Groomer was used.
|
|
1291
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
|
1292
|
+
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
|
1293
|
+
# @param region [String]: The cloud provider region
|
|
1294
|
+
# @return [void]
|
|
1295
|
+
def self.cleanup(noop: false, ignoremaster: false, region: $MU_CFG['google']['region'], skipsnapshots: false, onlycloud: false, flags: {})
|
|
1296
|
+
flags["project"] ||= MU::Cloud::Google.defaultProject
|
|
1297
|
+
# XXX make damn sure MU.deploy_id is set
|
|
1298
|
+
|
|
1299
|
+
MU::Cloud::Google.listAZs(region).each { |az|
|
|
1300
|
+
disks = []
|
|
1301
|
+
resp = MU::Cloud::Google.compute.list_instances(
|
|
1302
|
+
flags["project"],
|
|
1303
|
+
az,
|
|
1304
|
+
filter: "description eq #{MU.deploy_id}"
|
|
1305
|
+
)
|
|
1306
|
+
if !resp.items.nil? and resp.items.size > 0
|
|
1307
|
+
resp.items.each { |instance|
|
|
1308
|
+
saname = instance.tags.items.first.gsub(/[^a-z]/, "") # XXX this nonsense again
|
|
1309
|
+
MU.log "Terminating instance #{instance.name}"
|
|
1310
|
+
if !instance.disks.nil? and instance.disks.size > 0
|
|
1311
|
+
instance.disks.each { |disk|
|
|
1312
|
+
disks << disk if !disk.auto_delete
|
|
1313
|
+
}
|
|
1314
|
+
end
|
|
1315
|
+
deletia = MU::Cloud::Google.compute.delete_instance(
|
|
1316
|
+
flags["project"],
|
|
1317
|
+
az,
|
|
1318
|
+
instance.name
|
|
1319
|
+
) if !noop
|
|
1320
|
+
MU.log "Removing service account #{saname}"
|
|
1321
|
+
begin
|
|
1322
|
+
MU::Cloud::Google.iam.delete_project_service_account(
|
|
1323
|
+
"projects/#{flags["project"]}/serviceAccounts/#{saname}@#{flags["project"]}.iam.gserviceaccount.com"
|
|
1324
|
+
) if !noop
|
|
1325
|
+
rescue ::Google::Apis::ClientError => e
|
|
1326
|
+
raise e if !e.message.match(/^notFound: /)
|
|
1327
|
+
end
|
|
1328
|
+
# XXX wait-loop on pending?
|
|
1329
|
+
# pp deletia
|
|
1330
|
+
}
|
|
1331
|
+
end
|
|
1332
|
+
|
|
1333
|
+
if disks.size > 0
|
|
1334
|
+
# XXX make sure we don't miss anything that got created with dumb flags
|
|
1335
|
+
end
|
|
1336
|
+
# XXX honor snapshotting
|
|
1337
|
+
MU::Cloud::Google.compute.delete(
|
|
1338
|
+
"disk",
|
|
1339
|
+
flags["project"],
|
|
1340
|
+
az,
|
|
1341
|
+
noop
|
|
1342
|
+
) if !noop
|
|
1343
|
+
}
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1346
|
+
# Cloud-specific configuration properties.
|
|
1347
|
+
# @param config [MU::Config]: The calling MU::Config object
|
|
1348
|
+
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
|
1349
|
+
def self.schema(config)
|
|
1350
|
+
toplevel_required = []
|
|
1351
|
+
schema = {
|
|
1352
|
+
"image_id" => {
|
|
1353
|
+
"type" => "string",
|
|
1354
|
+
"description" => "The Google Cloud Platform Image on which to base this instance. Will use the default appropriate for the platform, if not specified."
|
|
1355
|
+
},
|
|
1356
|
+
"routes" => {
|
|
1357
|
+
"type" => "array",
|
|
1358
|
+
"items" => MU::Config::VPC.routeschema
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
[toplevel_required, schema]
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
# Confirm that the given instance size is valid for the given region.
|
|
1365
|
+
# If someone accidentally specified an equivalent size from some other cloud provider, return something that makes sense. If nothing makes sense, return nil.
|
|
1366
|
+
# @param size [String]: Instance type to check
|
|
1367
|
+
# @param region [String]: Region to check against
|
|
1368
|
+
# @return [String,nil]
|
|
1369
|
+
def self.validateInstanceType(size, region)
|
|
1370
|
+
types = (MU::Cloud::Google.listInstanceTypes(region))[region]
|
|
1371
|
+
if types and (size.nil? or !types.has_key?(size))
|
|
1372
|
+
# See if it's a type we can approximate from one of the other clouds
|
|
1373
|
+
atypes = (MU::Cloud::AWS.listInstanceTypes)[MU::Cloud::AWS.myRegion]
|
|
1374
|
+
foundmatch = false
|
|
1375
|
+
if atypes and atypes.size > 0 and atypes.has_key?(size)
|
|
1376
|
+
vcpu = atypes[size]["vcpu"]
|
|
1377
|
+
mem = atypes[size]["memory"]
|
|
1378
|
+
ecu = atypes[size]["ecu"]
|
|
1379
|
+
types.keys.sort.reverse.each { |type|
|
|
1380
|
+
features = types[type]
|
|
1381
|
+
next if ecu == "Variable" and ecu != features["ecu"]
|
|
1382
|
+
next if features["vcpu"] != vcpu
|
|
1383
|
+
if (features["memory"] - mem.to_f).abs < 0.10*mem
|
|
1384
|
+
foundmatch = true
|
|
1385
|
+
MU.log "You specified an Amazon instance type '#{size}.' Approximating with Google Compute type '#{type}.'", MU::WARN
|
|
1386
|
+
size = type
|
|
1387
|
+
break
|
|
1388
|
+
end
|
|
1389
|
+
}
|
|
1390
|
+
end
|
|
1391
|
+
if !foundmatch
|
|
1392
|
+
MU.log "Invalid size '#{size}' for Google Compute instance in #{region}. Supported types:", MU::ERR, details: types.keys.sort.join(", ")
|
|
1393
|
+
return nil
|
|
1394
|
+
end
|
|
1395
|
+
end
|
|
1396
|
+
size
|
|
1397
|
+
end
|
|
1398
|
+
|
|
1399
|
+
|
|
1400
|
+
# Cloud-specific pre-processing of {MU::Config::BasketofKittens::servers}, bare and unvalidated.
|
|
1401
|
+
# @param server [Hash]: The resource to process and validate
|
|
1402
|
+
# @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
1403
|
+
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
1404
|
+
def self.validateConfig(server, configurator)
|
|
1405
|
+
ok = true
|
|
1406
|
+
|
|
1407
|
+
server['size'] = validateInstanceType(server["size"], server["region"])
|
|
1408
|
+
ok = false if server['size'].nil?
|
|
1409
|
+
|
|
1410
|
+
# If we're not targeting an availability zone, pick one randomly
|
|
1411
|
+
if !server['availability_zone']
|
|
1412
|
+
server['availability_zone'] = MU::Cloud::Google.listAZs(server['region']).sample
|
|
1413
|
+
end
|
|
1414
|
+
|
|
1415
|
+
subnets = nil
|
|
1416
|
+
if !server['vpc']
|
|
1417
|
+
vpcs = MU::Cloud::Google::VPC.find
|
|
1418
|
+
if vpcs["default"]
|
|
1419
|
+
server["vpc"] ||= {}
|
|
1420
|
+
server["vpc"]["vpc_id"] = vpcs["default"].self_link
|
|
1421
|
+
subnets = vpcs["default"].subnetworks
|
|
1422
|
+
MU.log "No VPC specified for Server #{server['name']}, using default VPC for project #{server['project']}", MU::NOTICE
|
|
1423
|
+
else
|
|
1424
|
+
ok = false
|
|
1425
|
+
MU.log "You must specify a target VPC when creating a Server", MU::ERR
|
|
1426
|
+
end
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
if !server['vpc']['subnet_id'] and server['vpc']['subnet_name'].nil?
|
|
1430
|
+
if !subnets
|
|
1431
|
+
if server["vpc"]["vpc_id"]
|
|
1432
|
+
vpcs = MU::Cloud::Google::VPC.find(cloud_id: server["vpc"]["vpc_id"])
|
|
1433
|
+
subnets = vpcs["default"].subnetworks.sample
|
|
1434
|
+
end
|
|
1435
|
+
end
|
|
1436
|
+
|
|
1437
|
+
if subnets
|
|
1438
|
+
server['vpc']['subnet_id'] = subnets.delete_if { |subnet|
|
|
1439
|
+
!subnet.match(/regions\/#{Regexp.quote(server['region'])}\/subnetworks/)
|
|
1440
|
+
}.sample
|
|
1441
|
+
end
|
|
1442
|
+
if server['vpc']['subnet_id'].nil?
|
|
1443
|
+
ok = false
|
|
1444
|
+
MU.log "Failed to identify a subnet in my region (#{server['region']})", MU::ERR, details: server["vpc"]["vpc_id"]
|
|
1445
|
+
end
|
|
1446
|
+
end
|
|
1447
|
+
|
|
1448
|
+
if server['image_id'].nil?
|
|
1449
|
+
if MU::Config.google_images.has_key?(server['platform'])
|
|
1450
|
+
server['image_id'] = configurator.getTail("server"+server['name']+"Image", value: MU::Config.google_images[server['platform']], prettyname: "server"+server['name']+"Image", cloudtype: "Google::::Apis::ComputeBeta::Image")
|
|
1451
|
+
else
|
|
1452
|
+
MU.log "No image specified for #{server['name']} and no default available for platform #{server['platform']}", MU::ERR, details: server
|
|
1453
|
+
ok = false
|
|
1454
|
+
end
|
|
1455
|
+
end
|
|
1456
|
+
|
|
1457
|
+
real_image = nil
|
|
1458
|
+
begin
|
|
1459
|
+
real_image = MU::Cloud::Google::Server.fetchImage(server['image_id'].to_s)
|
|
1460
|
+
rescue ::Google::Apis::ClientError => e
|
|
1461
|
+
MU.log e.inspect, MU::WARN
|
|
1462
|
+
end
|
|
1463
|
+
|
|
1464
|
+
if real_image.nil?
|
|
1465
|
+
MU.log "Image #{server['image_id']} for server #{server['name']} does not appear to exist", MU::ERR
|
|
1466
|
+
ok = false
|
|
1467
|
+
else
|
|
1468
|
+
server['image_id'] = real_image.self_link
|
|
1469
|
+
server['image_id'].match(/projects\/([^\/]+)\/.*?\/([^\/]+)$/)
|
|
1470
|
+
img_project = Regexp.last_match[1]
|
|
1471
|
+
img_name = Regexp.last_match[2]
|
|
1472
|
+
begin
|
|
1473
|
+
snaps = MU::Cloud::Google.compute.list_snapshots(
|
|
1474
|
+
img_project,
|
|
1475
|
+
filter: "name eq #{img_name}-.*"
|
|
1476
|
+
)
|
|
1477
|
+
server['storage'] ||= []
|
|
1478
|
+
used_devs = server['storage'].map { |disk| disk['device'].gsub(/.*?\//, "") }
|
|
1479
|
+
snaps.items.each { |snap|
|
|
1480
|
+
next if !snap.labels.is_a?(Hash) or !snap.labels["mu-device-name"] or snap.labels["mu-parent-image"] != img_name
|
|
1481
|
+
devname = snap.labels["mu-device-name"]
|
|
1482
|
+
|
|
1483
|
+
if used_devs.include?(devname)
|
|
1484
|
+
MU.log "Device name #{devname} already declared in server #{server['name']} (snapshot #{snap.name} wants the name)", MU::ERR
|
|
1485
|
+
ok = false
|
|
1486
|
+
end
|
|
1487
|
+
server['storage'] << {
|
|
1488
|
+
"snapshot_id" => snap.self_link,
|
|
1489
|
+
"size" => snap.disk_size_gb,
|
|
1490
|
+
"delete_on_termination" => true,
|
|
1491
|
+
"device" => devname
|
|
1492
|
+
}
|
|
1493
|
+
used_devs << devname
|
|
1494
|
+
}
|
|
1495
|
+
rescue ::Google::Apis::ClientError => e
|
|
1496
|
+
# it's ok, sometimes we don't have permission to list snapshots
|
|
1497
|
+
# in other peoples' projects
|
|
1498
|
+
raise e if !e.message.match(/^forbidden: /)
|
|
1499
|
+
end
|
|
1500
|
+
end
|
|
1501
|
+
|
|
1502
|
+
ok
|
|
1503
|
+
end
|
|
1504
|
+
|
|
1505
|
+
private
|
|
1506
|
+
|
|
1507
|
+
end #class
|
|
1508
|
+
end #class
|
|
1509
|
+
end
|
|
1510
|
+
end #module
|