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
data/modules/mu/cloud.rb
ADDED
|
@@ -0,0 +1,1446 @@
|
|
|
1
|
+
# Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the BSD-3 license (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License in the root of the project or at
|
|
6
|
+
#
|
|
7
|
+
# http://egt-labs.com/mu/LICENSE.html
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
autoload :WinRM, "winrm"
|
|
16
|
+
|
|
17
|
+
module MU
|
|
18
|
+
# Plugins under this namespace serve as interfaces to cloud providers and
|
|
19
|
+
# other provisioning layers.
|
|
20
|
+
class Cloud
|
|
21
|
+
# An exception denoting an expected, temporary connection failure to a
|
|
22
|
+
# bootstrapping instance, e.g. for Windows instances that must reboot in
|
|
23
|
+
# mid-installation.
|
|
24
|
+
class BootstrapTempFail < MuNonFatal;
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# An exception we can use with transient Net::SSH errors, which require
|
|
28
|
+
# special handling due to obnoxious asynchronous interrupt behaviors.
|
|
29
|
+
class NetSSHFail < MuNonFatal;
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Exception thrown when a request is made to an unimplemented cloud
|
|
33
|
+
# resource.
|
|
34
|
+
class MuCloudResourceNotImplemented < StandardError;
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Exception thrown when a request is made for an unsupported flag or feature
|
|
38
|
+
# in a cloud resource.
|
|
39
|
+
class MuCloudFlagNotImplemented < StandardError;
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
generic_class_methods = [:find, :cleanup, :validateConfig, :schema]
|
|
43
|
+
generic_instance_methods = [:create, :notify, :mu_name, :cloud_id, :config, :cloud_desc]
|
|
44
|
+
|
|
45
|
+
# Initialize empty classes for each of these. We'll fill them with code
|
|
46
|
+
# later; we're doing this here because otherwise the parser yells about
|
|
47
|
+
# missing classes, even though they're created at runtime.
|
|
48
|
+
|
|
49
|
+
# Stub base class; real implementations generated at runtime
|
|
50
|
+
class Collection;
|
|
51
|
+
end
|
|
52
|
+
# Stub base class; real implementations generated at runtime
|
|
53
|
+
class Database;
|
|
54
|
+
end
|
|
55
|
+
# Stub base class; real implementations generated at runtime
|
|
56
|
+
class DNSZone;
|
|
57
|
+
end
|
|
58
|
+
# Stub base class; real implementations generated at runtime
|
|
59
|
+
class FirewallRule;
|
|
60
|
+
end
|
|
61
|
+
# Stub base class; real implementations generated at runtime
|
|
62
|
+
class LoadBalancer;
|
|
63
|
+
end
|
|
64
|
+
# Stub base class; real implementations generated at runtime
|
|
65
|
+
class Server;
|
|
66
|
+
end
|
|
67
|
+
# Stub base class; real implementations generated at runtime
|
|
68
|
+
class ContainerCluster;
|
|
69
|
+
end
|
|
70
|
+
# Stub base class; real implementations generated at runtime
|
|
71
|
+
class ServerPool;
|
|
72
|
+
end
|
|
73
|
+
# Stub base class; real implementations generated at runtime
|
|
74
|
+
class VPC;
|
|
75
|
+
end
|
|
76
|
+
# Stub base class; real implementations generated at runtime
|
|
77
|
+
class CacheCluster;
|
|
78
|
+
end
|
|
79
|
+
# Stub base class; real implementations generated at runtime
|
|
80
|
+
class Alarm;
|
|
81
|
+
end
|
|
82
|
+
# Stub base class; real implementations generated at runtime
|
|
83
|
+
class Notification;
|
|
84
|
+
end
|
|
85
|
+
# Stub base class; real implementations generated at runtime
|
|
86
|
+
class Log;
|
|
87
|
+
end
|
|
88
|
+
# Stub base class; real implementations generated at runtime
|
|
89
|
+
class StoragePool;
|
|
90
|
+
end
|
|
91
|
+
# Stub base class; real implementations generated at runtime
|
|
92
|
+
class Function;
|
|
93
|
+
end
|
|
94
|
+
# Stub base class; real implementations generated at runtime
|
|
95
|
+
class SearchDomain;
|
|
96
|
+
end
|
|
97
|
+
# Stub base class; real implementations generated at runtime
|
|
98
|
+
class MsgQueue;
|
|
99
|
+
end
|
|
100
|
+
# Stub base class; real implementations generated at runtime
|
|
101
|
+
class Project;
|
|
102
|
+
end
|
|
103
|
+
# Stub base class; real implementations generated at runtime
|
|
104
|
+
class Folder;
|
|
105
|
+
end
|
|
106
|
+
# Stub base class; real implementations generated at runtime
|
|
107
|
+
class User;
|
|
108
|
+
end
|
|
109
|
+
# Stub base class; real implementations generated at runtime
|
|
110
|
+
class Group;
|
|
111
|
+
end
|
|
112
|
+
# Stub base class; real implementations generated at runtime
|
|
113
|
+
class Role;
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The types of cloud resources we can create, as class objects. Include
|
|
117
|
+
# methods a class implementing this resource type must support to be
|
|
118
|
+
# considered valid.
|
|
119
|
+
@@resource_types = {
|
|
120
|
+
:Collection => {
|
|
121
|
+
:has_multiples => false,
|
|
122
|
+
:can_live_in_vpc => false,
|
|
123
|
+
:cfg_name => "collection",
|
|
124
|
+
:cfg_plural => "collections",
|
|
125
|
+
:interface => self.const_get("Collection"),
|
|
126
|
+
:deps_wait_on_my_creation => true,
|
|
127
|
+
:waits_on_parent_completion => false,
|
|
128
|
+
:class => generic_class_methods,
|
|
129
|
+
:instance => generic_instance_methods
|
|
130
|
+
},
|
|
131
|
+
:Database => {
|
|
132
|
+
:has_multiples => true,
|
|
133
|
+
:can_live_in_vpc => true,
|
|
134
|
+
:cfg_name => "database",
|
|
135
|
+
:cfg_plural => "databases",
|
|
136
|
+
:interface => self.const_get("Database"),
|
|
137
|
+
:deps_wait_on_my_creation => true,
|
|
138
|
+
:waits_on_parent_completion => false,
|
|
139
|
+
:class => generic_class_methods,
|
|
140
|
+
:instance => generic_instance_methods + [:groom, :allowHost]
|
|
141
|
+
},
|
|
142
|
+
:DNSZone => {
|
|
143
|
+
:has_multiples => false,
|
|
144
|
+
:can_live_in_vpc => false,
|
|
145
|
+
:cfg_name => "dnszone",
|
|
146
|
+
:cfg_plural => "dnszones",
|
|
147
|
+
:interface => self.const_get("DNSZone"),
|
|
148
|
+
:deps_wait_on_my_creation => true,
|
|
149
|
+
:waits_on_parent_completion => true,
|
|
150
|
+
:class => generic_class_methods + [:genericMuDNSEntry, :createRecordsFromConfig],
|
|
151
|
+
:instance => generic_instance_methods
|
|
152
|
+
},
|
|
153
|
+
:FirewallRule => {
|
|
154
|
+
:has_multiples => false,
|
|
155
|
+
:can_live_in_vpc => true,
|
|
156
|
+
:cfg_name => "firewall_rule",
|
|
157
|
+
:cfg_plural => "firewall_rules",
|
|
158
|
+
:interface => self.const_get("FirewallRule"),
|
|
159
|
+
:deps_wait_on_my_creation => true,
|
|
160
|
+
:waits_on_parent_completion => false,
|
|
161
|
+
:class => generic_class_methods,
|
|
162
|
+
:instance => generic_instance_methods + [:groom, :addRule]
|
|
163
|
+
},
|
|
164
|
+
:LoadBalancer => {
|
|
165
|
+
:has_multiples => false,
|
|
166
|
+
:can_live_in_vpc => true,
|
|
167
|
+
:cfg_name => "loadbalancer",
|
|
168
|
+
:cfg_plural => "loadbalancers",
|
|
169
|
+
:interface => self.const_get("LoadBalancer"),
|
|
170
|
+
:deps_wait_on_my_creation => true,
|
|
171
|
+
:waits_on_parent_completion => false,
|
|
172
|
+
:class => generic_class_methods,
|
|
173
|
+
:instance => generic_instance_methods + [:registerNode]
|
|
174
|
+
},
|
|
175
|
+
:Server => {
|
|
176
|
+
:has_multiples => true,
|
|
177
|
+
:can_live_in_vpc => true,
|
|
178
|
+
:cfg_name => "server",
|
|
179
|
+
:cfg_plural => "servers",
|
|
180
|
+
:interface => self.const_get("Server"),
|
|
181
|
+
:deps_wait_on_my_creation => false,
|
|
182
|
+
:waits_on_parent_completion => false,
|
|
183
|
+
:class => generic_class_methods + [:validateInstanceType],
|
|
184
|
+
:instance => generic_instance_methods + [:groom, :postBoot, :getSSHConfig, :canonicalIP, :getWindowsAdminPassword, :active?, :groomer, :mu_windows_name, :mu_windows_name=, :reboot, :addVolume]
|
|
185
|
+
},
|
|
186
|
+
:ServerPool => {
|
|
187
|
+
:has_multiples => false,
|
|
188
|
+
:can_live_in_vpc => true,
|
|
189
|
+
:cfg_name => "server_pool",
|
|
190
|
+
:cfg_plural => "server_pools",
|
|
191
|
+
:interface => self.const_get("ServerPool"),
|
|
192
|
+
:deps_wait_on_my_creation => false,
|
|
193
|
+
:waits_on_parent_completion => true,
|
|
194
|
+
:class => generic_class_methods,
|
|
195
|
+
:instance => generic_instance_methods + [:groom, :listNodes]
|
|
196
|
+
},
|
|
197
|
+
:VPC => {
|
|
198
|
+
:has_multiples => false,
|
|
199
|
+
:can_live_in_vpc => false,
|
|
200
|
+
:cfg_name => "vpc",
|
|
201
|
+
:cfg_plural => "vpcs",
|
|
202
|
+
:interface => self.const_get("VPC"),
|
|
203
|
+
:deps_wait_on_my_creation => true,
|
|
204
|
+
:waits_on_parent_completion => false,
|
|
205
|
+
:class => generic_class_methods,
|
|
206
|
+
:instance => generic_instance_methods + [:groom, :subnets, :getSubnet, :listSubnets, :findBastion, :findNat]
|
|
207
|
+
},
|
|
208
|
+
:CacheCluster => {
|
|
209
|
+
:has_multiples => true,
|
|
210
|
+
:can_live_in_vpc => true,
|
|
211
|
+
:cfg_name => "cache_cluster",
|
|
212
|
+
:cfg_plural => "cache_clusters",
|
|
213
|
+
:interface => self.const_get("CacheCluster"),
|
|
214
|
+
:deps_wait_on_my_creation => true,
|
|
215
|
+
:waits_on_parent_completion => false,
|
|
216
|
+
:class => generic_class_methods,
|
|
217
|
+
:instance => generic_instance_methods + [:groom]
|
|
218
|
+
},
|
|
219
|
+
:Alarm => {
|
|
220
|
+
:has_multiples => false,
|
|
221
|
+
:can_live_in_vpc => false,
|
|
222
|
+
:cfg_name => "alarm",
|
|
223
|
+
:cfg_plural => "alarms",
|
|
224
|
+
:interface => self.const_get("Alarm"),
|
|
225
|
+
:deps_wait_on_my_creation => false,
|
|
226
|
+
:waits_on_parent_completion => true,
|
|
227
|
+
:class => generic_class_methods,
|
|
228
|
+
:instance => generic_instance_methods + [:groom]
|
|
229
|
+
},
|
|
230
|
+
:Notification => {
|
|
231
|
+
:has_multiples => false,
|
|
232
|
+
:can_live_in_vpc => false,
|
|
233
|
+
:cfg_name => "notification",
|
|
234
|
+
:cfg_plural => "notifications",
|
|
235
|
+
:interface => self.const_get("Notification"),
|
|
236
|
+
:deps_wait_on_my_creation => false,
|
|
237
|
+
:waits_on_parent_completion => false,
|
|
238
|
+
:class => generic_class_methods,
|
|
239
|
+
:instance => generic_instance_methods + [:groom]
|
|
240
|
+
},
|
|
241
|
+
:Log => {
|
|
242
|
+
:has_multiples => false,
|
|
243
|
+
:can_live_in_vpc => false,
|
|
244
|
+
:cfg_name => "log",
|
|
245
|
+
:cfg_plural => "logs",
|
|
246
|
+
:interface => self.const_get("Log"),
|
|
247
|
+
:deps_wait_on_my_creation => true,
|
|
248
|
+
:waits_on_parent_completion => true,
|
|
249
|
+
:class => generic_class_methods,
|
|
250
|
+
:instance => generic_instance_methods + [:groom]
|
|
251
|
+
},
|
|
252
|
+
:StoragePool => {
|
|
253
|
+
:has_multiples => false,
|
|
254
|
+
:can_live_in_vpc => true,
|
|
255
|
+
:cfg_name => "storage_pool",
|
|
256
|
+
:cfg_plural => "storage_pools",
|
|
257
|
+
:interface => self.const_get("StoragePool"),
|
|
258
|
+
:deps_wait_on_my_creation => true,
|
|
259
|
+
:waits_on_parent_completion => false,
|
|
260
|
+
:class => generic_class_methods,
|
|
261
|
+
:instance => generic_instance_methods + [:groom]
|
|
262
|
+
},
|
|
263
|
+
:Function => {
|
|
264
|
+
:has_multiples => false,
|
|
265
|
+
:can_live_in_vpc => true,
|
|
266
|
+
:cfg_name => "function",
|
|
267
|
+
:cfg_plural => "functions",
|
|
268
|
+
:interface => self.const_get("Function"),
|
|
269
|
+
:deps_wait_on_my_creation => true,
|
|
270
|
+
:waits_on_parent_completion => false,
|
|
271
|
+
:class => generic_class_methods,
|
|
272
|
+
:instance => generic_instance_methods
|
|
273
|
+
},
|
|
274
|
+
:ContainerCluster => {
|
|
275
|
+
:has_multiples => false,
|
|
276
|
+
:can_live_in_vpc => true,
|
|
277
|
+
:cfg_name => "container_cluster",
|
|
278
|
+
:cfg_plural => "container_clusters",
|
|
279
|
+
:interface => self.const_get("ContainerCluster"),
|
|
280
|
+
:deps_wait_on_my_creation => true,
|
|
281
|
+
:waits_on_parent_completion => false,
|
|
282
|
+
:class => generic_class_methods,
|
|
283
|
+
:instance => generic_instance_methods + [:groom]
|
|
284
|
+
},
|
|
285
|
+
:SearchDomain => {
|
|
286
|
+
:has_multiples => false,
|
|
287
|
+
:can_live_in_vpc => true,
|
|
288
|
+
:cfg_name => "search_domain",
|
|
289
|
+
:cfg_plural => "search_domains",
|
|
290
|
+
:interface => self.const_get("SearchDomain"),
|
|
291
|
+
:deps_wait_on_my_creation => true,
|
|
292
|
+
:waits_on_parent_completion => false,
|
|
293
|
+
:class => generic_class_methods,
|
|
294
|
+
:instance => generic_instance_methods + [:groom]
|
|
295
|
+
},
|
|
296
|
+
:MsgQueue => {
|
|
297
|
+
:has_multiples => false,
|
|
298
|
+
:can_live_in_vpc => false,
|
|
299
|
+
:cfg_name => "msg_queue",
|
|
300
|
+
:cfg_plural => "msg_queues",
|
|
301
|
+
:interface => self.const_get("MsgQueue"),
|
|
302
|
+
:deps_wait_on_my_creation => true,
|
|
303
|
+
:waits_on_parent_completion => true,
|
|
304
|
+
:class => generic_class_methods,
|
|
305
|
+
:instance => generic_instance_methods + [:groom]
|
|
306
|
+
},
|
|
307
|
+
:Project => {
|
|
308
|
+
:has_multiples => false,
|
|
309
|
+
:can_live_in_vpc => false,
|
|
310
|
+
:cfg_name => "project",
|
|
311
|
+
:cfg_plural => "projects",
|
|
312
|
+
:interface => self.const_get("Project"),
|
|
313
|
+
:deps_wait_on_my_creation => true,
|
|
314
|
+
:waits_on_parent_completion => true,
|
|
315
|
+
:class => generic_class_methods,
|
|
316
|
+
:instance => generic_instance_methods
|
|
317
|
+
},
|
|
318
|
+
:Folder => {
|
|
319
|
+
:has_multiples => false,
|
|
320
|
+
:can_live_in_vpc => false,
|
|
321
|
+
:cfg_name => "folder",
|
|
322
|
+
:cfg_plural => "folders",
|
|
323
|
+
:interface => self.const_get("Folder"),
|
|
324
|
+
:deps_wait_on_my_creation => true,
|
|
325
|
+
:waits_on_parent_completion => true,
|
|
326
|
+
:class => generic_class_methods,
|
|
327
|
+
:instance => generic_instance_methods
|
|
328
|
+
},
|
|
329
|
+
:User => {
|
|
330
|
+
:has_multiples => false,
|
|
331
|
+
:can_live_in_vpc => false,
|
|
332
|
+
:cfg_name => "user",
|
|
333
|
+
:cfg_plural => "users",
|
|
334
|
+
:interface => self.const_get("User"),
|
|
335
|
+
:deps_wait_on_my_creation => true,
|
|
336
|
+
:waits_on_parent_completion => true,
|
|
337
|
+
:class => generic_class_methods,
|
|
338
|
+
:instance => generic_instance_methods + [:groom]
|
|
339
|
+
},
|
|
340
|
+
:Group => {
|
|
341
|
+
:has_multiples => false,
|
|
342
|
+
:can_live_in_vpc => false,
|
|
343
|
+
:cfg_name => "group",
|
|
344
|
+
:cfg_plural => "groups",
|
|
345
|
+
:interface => self.const_get("Group"),
|
|
346
|
+
:deps_wait_on_my_creation => true,
|
|
347
|
+
:waits_on_parent_completion => true,
|
|
348
|
+
:class => generic_class_methods,
|
|
349
|
+
:instance => generic_instance_methods + [:groom]
|
|
350
|
+
},
|
|
351
|
+
:Role => {
|
|
352
|
+
:has_multiples => false,
|
|
353
|
+
:can_live_in_vpc => false,
|
|
354
|
+
:cfg_name => "role",
|
|
355
|
+
:cfg_plural => "roles",
|
|
356
|
+
:interface => self.const_get("Role"),
|
|
357
|
+
:deps_wait_on_my_creation => true,
|
|
358
|
+
:waits_on_parent_completion => true,
|
|
359
|
+
:class => generic_class_methods,
|
|
360
|
+
:instance => generic_instance_methods + [:groom]
|
|
361
|
+
}
|
|
362
|
+
}.freeze
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
# A list of supported cloud resource types as Mu classes
|
|
366
|
+
def self.resource_types;
|
|
367
|
+
@@resource_types
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# Shorthand lookup for resource type names. Given any of the shorthand class name, configuration name (singular or plural), or full class name, return all four as a set.
|
|
371
|
+
# @param type [String]: A string that looks like our short or full class name or singular or plural configuration names.
|
|
372
|
+
# @return [Array]: Class name (Symbol), singular config name (String), plural config name (String), full class name (Object)
|
|
373
|
+
def self.getResourceNames(type)
|
|
374
|
+
@@resource_types.each_pair { |name, cloudclass|
|
|
375
|
+
if name == type.to_sym or
|
|
376
|
+
cloudclass[:cfg_name] == type or
|
|
377
|
+
cloudclass[:cfg_plural] == type or
|
|
378
|
+
Object.const_get("MU").const_get("Cloud").const_get(name) == type
|
|
379
|
+
cfg_name = cloudclass[:cfg_name]
|
|
380
|
+
type = name
|
|
381
|
+
return [type.to_sym, cloudclass[:cfg_name], cloudclass[:cfg_plural], Object.const_get("MU").const_get("Cloud").const_get(name), cloudclass]
|
|
382
|
+
end
|
|
383
|
+
}
|
|
384
|
+
[nil, nil, nil, nil, {}]
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Net::SSH exceptions seem to have their own behavior vis a vis threads,
|
|
388
|
+
# and our regular call stack gets circumvented when they're thrown. Cheat
|
|
389
|
+
# here to catch them gracefully.
|
|
390
|
+
def self.handleNetSSHExceptions
|
|
391
|
+
Thread.handle_interrupt(Net::SSH::Exception => :never) {
|
|
392
|
+
begin
|
|
393
|
+
Thread.handle_interrupt(Net::SSH::Exception => :immediate) {
|
|
394
|
+
MU.log "(Probably harmless) Caught a Net::SSH Exception in #{Thread.current.inspect}", MU::DEBUG, details: Thread.current.backtrace
|
|
395
|
+
}
|
|
396
|
+
ensure
|
|
397
|
+
# raise NetSSHFail, "Net::SSH had a nutty"
|
|
398
|
+
end
|
|
399
|
+
}
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# List of known/supported Cloud providers
|
|
403
|
+
def self.supportedClouds
|
|
404
|
+
["AWS", "CloudFormation", "Google"]
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# Load the container class for each cloud we know about, and inject autoload
|
|
408
|
+
# code for each of its supported resource type classes.
|
|
409
|
+
MU::Cloud.supportedClouds.each { |cloud|
|
|
410
|
+
require "mu/clouds/#{cloud.downcase}"
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
# @return [Mutex]
|
|
414
|
+
def self.userdata_mutex
|
|
415
|
+
@userdata_mutex ||= Mutex.new
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Fetch our baseline userdata argument (read: "script that runs on first
|
|
419
|
+
# boot") for a given platform.
|
|
420
|
+
# *XXX* both the eval() and the blind File.read() based on the platform
|
|
421
|
+
# variable are dangerous without cleaning. Clean them.
|
|
422
|
+
# @param platform [String]: The target OS.
|
|
423
|
+
# @param template_variables [Hash]: A list of variable substitutions to pass as globals to the ERB parser when loading the userdata script.
|
|
424
|
+
# @param custom_append [String]: Arbitrary extra code to append to our default userdata behavior.
|
|
425
|
+
# @return [String]
|
|
426
|
+
def self.fetchUserdata(platform: "linux", template_variables: {}, custom_append: nil, cloud: "aws", scrub_mu_isms: false)
|
|
427
|
+
return nil if platform.nil? or platform.empty?
|
|
428
|
+
userdata_mutex.synchronize {
|
|
429
|
+
script = ""
|
|
430
|
+
if !scrub_mu_isms
|
|
431
|
+
if template_variables.nil? or !template_variables.is_a?(Hash)
|
|
432
|
+
raise MuError, "My second argument should be a hash of variables to pass into ERB templates"
|
|
433
|
+
end
|
|
434
|
+
$mu = OpenStruct.new(template_variables)
|
|
435
|
+
userdata_dir = File.expand_path(MU.myRoot+"/modules/mu/clouds/#{cloud}/userdata")
|
|
436
|
+
platform = "linux" if %w{centos centos6 centos7 ubuntu ubuntu14 rhel rhel7 rhel71 amazon}.include? platform
|
|
437
|
+
platform = "windows" if %w{win2k12r2 win2k12 win2k8 win2k8r2 win2k16}.include? platform
|
|
438
|
+
erbfile = "#{userdata_dir}/#{platform}.erb"
|
|
439
|
+
if !File.exist?(erbfile)
|
|
440
|
+
MU.log "No such userdata template '#{erbfile}'", MU::WARN, details: caller
|
|
441
|
+
return ""
|
|
442
|
+
end
|
|
443
|
+
userdata = File.read(erbfile)
|
|
444
|
+
begin
|
|
445
|
+
erb = ERB.new(userdata)
|
|
446
|
+
script = erb.result
|
|
447
|
+
rescue NameError => e
|
|
448
|
+
raise MuError, "Error parsing userdata script #{erbfile} as an ERB template: #{e.inspect}"
|
|
449
|
+
end
|
|
450
|
+
MU.log "Parsed #{erbfile} as ERB", MU::DEBUG, details: script
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
if !custom_append.nil?
|
|
454
|
+
if custom_append['path'].nil?
|
|
455
|
+
raise MuError, "Got a custom userdata script argument, but no ['path'] component"
|
|
456
|
+
end
|
|
457
|
+
erbfile = File.read(custom_append['path'])
|
|
458
|
+
MU.log "Loaded userdata script from #{custom_append['path']}"
|
|
459
|
+
if custom_append['use_erb']
|
|
460
|
+
begin
|
|
461
|
+
erb = ERB.new(erbfile, 1)
|
|
462
|
+
if custom_append['skip_std']
|
|
463
|
+
script = +erb.result
|
|
464
|
+
else
|
|
465
|
+
script = script+"\n"+erb.result
|
|
466
|
+
end
|
|
467
|
+
rescue NameError => e
|
|
468
|
+
raise MuError, "Error parsing userdata script #{erbfile} as an ERB template: #{e.inspect}"
|
|
469
|
+
end
|
|
470
|
+
MU.log "Parsed #{custom_append['path']} as ERB", MU::DEBUG, details: script
|
|
471
|
+
else
|
|
472
|
+
if custom_append['skip_std']
|
|
473
|
+
script = erbfile
|
|
474
|
+
else
|
|
475
|
+
script = script+"\n"+erbfile
|
|
476
|
+
end
|
|
477
|
+
MU.log "Parsed #{custom_append['path']} as flat file", MU::DEBUG, details: script
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
return script
|
|
481
|
+
}
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
@cloud_class_cache = {}
|
|
485
|
+
# Given a cloud layer and resource type, return the class which implements it.
|
|
486
|
+
# @param cloud [String]: The Cloud layer
|
|
487
|
+
# @param type [String]: The resource type. Can be the full class name, symbolic name, or Basket of Kittens configuration shorthand for the resource type.
|
|
488
|
+
# @return [Class]: The cloud-specific class implementing this resource
|
|
489
|
+
def self.loadCloudType(cloud, type)
|
|
490
|
+
raise MuError, "cloud argument to MU::Cloud.loadCloudType cannot be nil" if cloud.nil?
|
|
491
|
+
shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(type)
|
|
492
|
+
if @cloud_class_cache.has_key?(cloud) and @cloud_class_cache[cloud].has_key?(type)
|
|
493
|
+
if @cloud_class_cache[cloud][type].nil?
|
|
494
|
+
raise MuError, "The '#{type}' resource is not supported in cloud #{cloud} (tried MU::#{cloud}::#{type})", caller
|
|
495
|
+
end
|
|
496
|
+
return @cloud_class_cache[cloud][type]
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
if cfg_name.nil?
|
|
500
|
+
raise MuError, "Can't find a cloud resource type named '#{type}'"
|
|
501
|
+
end
|
|
502
|
+
if !File.size?(MU.myRoot+"/modules/mu/clouds/#{cloud.downcase}.rb")
|
|
503
|
+
raise MuError, "Requested to use unsupported provisioning layer #{cloud}"
|
|
504
|
+
end
|
|
505
|
+
begin
|
|
506
|
+
require "mu/clouds/#{cloud.downcase}/#{cfg_name}"
|
|
507
|
+
rescue LoadError => e
|
|
508
|
+
raise MuCloudResourceNotImplemented, "MU::Cloud::#{cloud} does not currently implement #{shortclass}"
|
|
509
|
+
end
|
|
510
|
+
@cloud_class_cache[cloud] = {} if !@cloud_class_cache.has_key?(cloud)
|
|
511
|
+
begin
|
|
512
|
+
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
|
513
|
+
myclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(type)
|
|
514
|
+
@@resource_types[type.to_sym][:class].each { |class_method|
|
|
515
|
+
if !myclass.respond_to?(class_method) or myclass.method(class_method).owner.to_s != "#<Class:#{myclass}>"
|
|
516
|
+
raise MuError, "MU::Cloud::#{cloud}::#{type} has not implemented required class method #{class_method}"
|
|
517
|
+
end
|
|
518
|
+
}
|
|
519
|
+
@@resource_types[type.to_sym][:instance].each { |instance_method|
|
|
520
|
+
if !myclass.public_instance_methods.include?(instance_method)
|
|
521
|
+
raise MuError, "MU::Cloud::#{cloud}::#{type} has not implemented required instance method #{instance_method}"
|
|
522
|
+
end
|
|
523
|
+
}
|
|
524
|
+
cloudclass.required_instance_methods.each { |instance_method|
|
|
525
|
+
if !myclass.public_instance_methods.include?(instance_method)
|
|
526
|
+
raise MuError, "MU::Cloud::#{cloud}::#{type} has not implemented required instance method #{instance_method}"
|
|
527
|
+
end
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
@cloud_class_cache[cloud][type] = myclass
|
|
531
|
+
return myclass
|
|
532
|
+
rescue NameError => e
|
|
533
|
+
@cloud_class_cache[cloud][type] = nil
|
|
534
|
+
raise MuError, "The '#{type}' resource is not supported in cloud #{cloud} (tried MU::#{cloud}::#{type})", e.backtrace
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
MU::Cloud.supportedClouds.each { |cloud|
|
|
539
|
+
Object.const_get("MU").const_get("Cloud").const_get(cloud).class_eval {
|
|
540
|
+
|
|
541
|
+
# Automatically load supported cloud resource classes when they're
|
|
542
|
+
# referenced.
|
|
543
|
+
def self.const_missing(symbol)
|
|
544
|
+
if MU::Cloud.resource_types.has_key?(symbol.to_sym)
|
|
545
|
+
return MU::Cloud.loadCloudType(name.sub(/.*?::([^:]+)$/, '\1'), symbol)
|
|
546
|
+
else
|
|
547
|
+
raise MuCloudResourceNotImplemented, "No such cloud resource #{name}:#{symbol}"
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
@@resource_types.each_pair { |name, attrs|
|
|
554
|
+
Object.const_get("MU").const_get("Cloud").const_get(name).class_eval {
|
|
555
|
+
attr_reader :cloud
|
|
556
|
+
attr_reader :environment
|
|
557
|
+
attr_reader :cloudclass
|
|
558
|
+
attr_reader :cloudobj
|
|
559
|
+
attr_reader :deploy_id
|
|
560
|
+
attr_reader :mu_name
|
|
561
|
+
attr_reader :cloud_id
|
|
562
|
+
attr_reader :url
|
|
563
|
+
attr_reader :config
|
|
564
|
+
attr_reader :deploydata
|
|
565
|
+
attr_reader :destroyed
|
|
566
|
+
attr_reader :cfm_template
|
|
567
|
+
attr_reader :cfm_name
|
|
568
|
+
attr_reader :delayed_save
|
|
569
|
+
|
|
570
|
+
def self.shortname
|
|
571
|
+
name.sub(/.*?::([^:]+)$/, '\1')
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
def self.cfg_plural
|
|
575
|
+
MU::Cloud.resource_types[shortname.to_sym][:cfg_plural]
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
def self.has_multiples
|
|
579
|
+
MU::Cloud.resource_types[shortname.to_sym][:has_multiples]
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
def self.cfg_name
|
|
583
|
+
MU::Cloud.resource_types[shortname.to_sym][:cfg_name]
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
def self.can_live_in_vpc
|
|
587
|
+
MU::Cloud.resource_types[shortname.to_sym][:can_live_in_vpc]
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def self.waits_on_parent_completion
|
|
591
|
+
MU::Cloud.resource_types[shortname.to_sym][:waits_on_parent_completion]
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
def self.deps_wait_on_my_creation
|
|
595
|
+
MU::Cloud.resource_types[shortname.to_sym][:deps_wait_on_my_creation]
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
def groomer
|
|
599
|
+
return @cloudobj.groomer if !@cloudobj.nil?
|
|
600
|
+
nil
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
# Print something palatable when we're called in a string context.
|
|
604
|
+
def to_s
|
|
605
|
+
fullname = "#{self.class.shortname}"
|
|
606
|
+
if !@cloudobj.nil? and !@cloudobj.mu_name.nil?
|
|
607
|
+
@mu_name ||= @cloudobj.mu_name
|
|
608
|
+
end
|
|
609
|
+
if !@mu_name.nil? and !@mu_name.empty?
|
|
610
|
+
fullname = fullname + " '#{@mu_name}'"
|
|
611
|
+
end
|
|
612
|
+
if !@cloud_id.nil?
|
|
613
|
+
fullname = fullname + " (#{@cloud_id})"
|
|
614
|
+
end
|
|
615
|
+
return fullname
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
# @param mommacat [MU::MommaCat]: The deployment containing this cloud resource
|
|
620
|
+
# @param mu_name [String]: Optional- specify the full Mu resource name of an existing resource to load, instead of creating a new one
|
|
621
|
+
# @param cloud_id [String]: Optional- specify the cloud provider's identifier for an existing resource to load, instead of creating a new one
|
|
622
|
+
# @param kitten_cfg [Hash]: The parse configuration for this object from {MU::Config}
|
|
623
|
+
def initialize(mommacat: nil,
|
|
624
|
+
mu_name: nil,
|
|
625
|
+
cloud_id: nil,
|
|
626
|
+
kitten_cfg: nil,
|
|
627
|
+
delayed_save: false)
|
|
628
|
+
raise MuError, "Cannot invoke Cloud objects without a configuration" if kitten_cfg.nil?
|
|
629
|
+
@live = true
|
|
630
|
+
@deploy = mommacat
|
|
631
|
+
@config = kitten_cfg
|
|
632
|
+
@delayed_save = delayed_save
|
|
633
|
+
@cloud_id = cloud_id
|
|
634
|
+
|
|
635
|
+
if !@deploy.nil?
|
|
636
|
+
@deploy_id = @deploy.deploy_id
|
|
637
|
+
MU.log "Initializing an instance of #{self.class.name} in #{@deploy_id} #{mu_name}", MU::DEBUG, details: kitten_cfg
|
|
638
|
+
elsif mu_name.nil?
|
|
639
|
+
raise MuError, "Can't instantiate a MU::Cloud object with a live deploy or giving us a mu_name"
|
|
640
|
+
else
|
|
641
|
+
MU.log "Initializing an independent instance of #{self.class.name} named #{mu_name}", MU::DEBUG, details: kitten_cfg
|
|
642
|
+
end
|
|
643
|
+
if !kitten_cfg.has_key?("cloud")
|
|
644
|
+
kitten_cfg['cloud'] = MU::Config.defaultCloud
|
|
645
|
+
end
|
|
646
|
+
@cloud = kitten_cfg['cloud']
|
|
647
|
+
@cloudclass = MU::Cloud.loadCloudType(@cloud, self.class.shortname)
|
|
648
|
+
@environment = kitten_cfg['environment']
|
|
649
|
+
@method_semaphore = Mutex.new
|
|
650
|
+
@method_locks = {}
|
|
651
|
+
# XXX require subclass to provide attr_readers of @config and @deploy
|
|
652
|
+
|
|
653
|
+
@cloudobj = @cloudclass.new(mommacat: mommacat, kitten_cfg: kitten_cfg, cloud_id: cloud_id, mu_name: mu_name)
|
|
654
|
+
|
|
655
|
+
raise MuError, "Unknown error instantiating #{self}" if @cloudobj.nil?
|
|
656
|
+
|
|
657
|
+
# If we just loaded an existing object, go ahead and prepopulate the
|
|
658
|
+
# describe() cache
|
|
659
|
+
if !cloud_id.nil? or !mu_name.nil?
|
|
660
|
+
@cloudobj.describe(cloud_id: cloud_id)
|
|
661
|
+
@cloud_id ||= @cloudobj.cloud_id
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
@deploydata = @cloudobj.deploydata
|
|
665
|
+
@config = @cloudobj.config
|
|
666
|
+
|
|
667
|
+
# If we're going to be integrated into AD or otherwise need a short
|
|
668
|
+
# hostname, generate it now.
|
|
669
|
+
if self.class.shortname == "Server" and (@cloudobj.windows? or @config['active_directory']) and @cloudobj.mu_windows_name.nil?
|
|
670
|
+
if !@deploydata.nil? and !@deploydata['mu_windows_name'].nil?
|
|
671
|
+
@cloudobj.mu_windows_name = @deploydata['mu_windows_name']
|
|
672
|
+
else
|
|
673
|
+
# Use the same random differentiator as the "real" name if we're
|
|
674
|
+
# from a ServerPool. Helpful for admin sanity.
|
|
675
|
+
unq = @cloudobj.mu_name.sub(/^.*?-(...)$/, '\1')
|
|
676
|
+
if @config['basis'] and !unq.nil? and !unq.empty?
|
|
677
|
+
@cloudobj.mu_windows_name = @deploy.getResourceName(@config['name'], max_length: 15, need_unique_string: true, use_unique_string: unq, reuse_unique_string: true)
|
|
678
|
+
else
|
|
679
|
+
@cloudobj.mu_windows_name = @deploy.getResourceName(@config['name'], max_length: 15, need_unique_string: true)
|
|
680
|
+
end
|
|
681
|
+
end
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
# Register us with our parent deploy so that we can be found by our
|
|
685
|
+
# littermates if needed.
|
|
686
|
+
if !@deploy.nil? and !@cloudobj.mu_name.nil? and !@cloudobj.mu_name.empty?
|
|
687
|
+
describe # XXX is this actually safe here?
|
|
688
|
+
@deploy.addKitten(self.class.cfg_name, @config['name'], self)
|
|
689
|
+
elsif !@deploy.nil?
|
|
690
|
+
MU.log "#{self} didn't generate a mu_name after being loaded/initialized, dependencies on this resource will probably be confused!", MU::ERR
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
# Remove all metadata and cloud resources associated with this object
|
|
696
|
+
def destroy
|
|
697
|
+
if !@cloudobj.nil? and !@cloudobj.groomer.nil?
|
|
698
|
+
@cloudobj.groomer.cleanup
|
|
699
|
+
elsif !@groomer.nil?
|
|
700
|
+
@groomer.cleanup
|
|
701
|
+
end
|
|
702
|
+
if !@deploy.nil?
|
|
703
|
+
if !@cloudobj.nil? and !@config.nil? and !@cloudobj.mu_name.nil?
|
|
704
|
+
@deploy.notify(self.class.cfg_plural, @config['name'], nil, mu_name: @cloudobj.mu_name, remove: true, triggering_node: @cloudobj, delayed_save: @delayed_save)
|
|
705
|
+
elsif !@mu_name.nil?
|
|
706
|
+
@deploy.notify(self.class.cfg_plural, @config['name'], nil, mu_name: @mu_name, remove: true, triggering_node: self, delayed_save: @delayed_save)
|
|
707
|
+
end
|
|
708
|
+
@deploy.removeKitten(self)
|
|
709
|
+
end
|
|
710
|
+
# Make sure that if notify gets called again it won't go returning a
|
|
711
|
+
# bunch of now-bogus metadata.
|
|
712
|
+
@destroyed = true
|
|
713
|
+
if !@cloudobj.nil?
|
|
714
|
+
def @cloudobj.notify
|
|
715
|
+
{}
|
|
716
|
+
end
|
|
717
|
+
else
|
|
718
|
+
def notify
|
|
719
|
+
{}
|
|
720
|
+
end
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
def cloud_desc
|
|
725
|
+
describe
|
|
726
|
+
if !@cloudobj.nil?
|
|
727
|
+
@cloud_desc = @cloudobj.cloud_desc
|
|
728
|
+
@url = @cloudobj.url if @cloudobj.respond_to?(:url)
|
|
729
|
+
elsif !@config.nil? and !@cloud_id.nil?
|
|
730
|
+
# The find() method should be returning a Hash with the cloud_id
|
|
731
|
+
# as a key and a cloud platform descriptor as the value.
|
|
732
|
+
begin
|
|
733
|
+
matches = self.class.find(region: @config['region'], cloud_id: @cloud_id, flags: @config)
|
|
734
|
+
if !matches.nil? and matches.is_a?(Hash) and matches.has_key?(@cloud_id)
|
|
735
|
+
@cloud_desc = matches[@cloud_id]
|
|
736
|
+
else
|
|
737
|
+
MU.log "Failed to find a live #{self.class.shortname} with identifier #{@cloud_id} in #{@config['region']}, which has a record in deploy #{@deploy.deploy_id}", MU::WARN, details: caller
|
|
738
|
+
end
|
|
739
|
+
rescue Exception => e
|
|
740
|
+
MU.log "Got #{e.inspect} trying to find cloud handle for #{self.class.shortname} #{@mu_name} (#{@cloud_id})", MU::WARN
|
|
741
|
+
raise e
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
return @cloud_desc
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
# Retrieve all of the known metadata for this resource.
|
|
749
|
+
# @param cloud_id [String]: The cloud platform's identifier for the resource we're describing. Makes lookups more efficient.
|
|
750
|
+
# @param update_cache [Boolean]: Ignore cached data if we have any, instead reconsituting from original sources.
|
|
751
|
+
# @return [Array<Hash>]: mu_name, config, deploydata
|
|
752
|
+
def describe(cloud_id: nil, update_cache: false)
|
|
753
|
+
if cloud_id.nil? and !@cloudobj.nil?
|
|
754
|
+
@cloud_id ||= @cloudobj.cloud_id
|
|
755
|
+
end
|
|
756
|
+
res_type = self.class.cfg_plural
|
|
757
|
+
res_name = @config['name'] if !@config.nil?
|
|
758
|
+
deploydata = nil
|
|
759
|
+
if !@deploy.nil? and @deploy.is_a?(MU::MommaCat) and
|
|
760
|
+
!@deploy.deployment.nil? and
|
|
761
|
+
!@deploy.deployment[res_type].nil? and
|
|
762
|
+
!@deploy.deployment[res_type][res_name].nil?
|
|
763
|
+
deploydata = @deploy.deployment[res_type][res_name]
|
|
764
|
+
else
|
|
765
|
+
# XXX This should only happen on a brand new resource, but we should
|
|
766
|
+
# probably complain under other circumstances, if we can
|
|
767
|
+
# differentiate them.
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
if self.class.has_multiples and !@mu_name.nil? and deploydata.is_a?(Hash) and deploydata.has_key?(@mu_name)
|
|
771
|
+
@deploydata = deploydata[@mu_name]
|
|
772
|
+
elsif deploydata.is_a?(Hash)
|
|
773
|
+
@deploydata = deploydata
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
if @cloud_id.nil? and @deploydata.is_a?(Hash)
|
|
777
|
+
if @mu_name.nil? and @deploydata.has_key?('#MU_NAME')
|
|
778
|
+
@mu_name = @deploydata['#MU_NAME']
|
|
779
|
+
end
|
|
780
|
+
if @deploydata.has_key?('cloud_id')
|
|
781
|
+
@cloud_id ||= @deploydata['cloud_id']
|
|
782
|
+
else
|
|
783
|
+
# XXX temp hack to catch old Amazon-style identifiers. Remove this
|
|
784
|
+
# before supporting any other cloud layers, otherwise name
|
|
785
|
+
# collision is possible.
|
|
786
|
+
["group_id", "instance_id", "awsname", "identifier", "vpc_id", "id"].each { |identifier|
|
|
787
|
+
if @deploydata.has_key?(identifier)
|
|
788
|
+
@cloud_id ||= @deploydata[identifier]
|
|
789
|
+
if @mu_name.nil? and (identifier == "awsname" or identifier == "identifier" or identifier == "group_id")
|
|
790
|
+
@mu_name = @deploydata[identifier]
|
|
791
|
+
end
|
|
792
|
+
break
|
|
793
|
+
end
|
|
794
|
+
}
|
|
795
|
+
end
|
|
796
|
+
end
|
|
797
|
+
|
|
798
|
+
return [@mu_name, @config, @deploydata]
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
# Fetch MU::Cloud objects for each of this object's dependencies, and
|
|
802
|
+
# return in an easily-navigable Hash. This can include things listed in
|
|
803
|
+
# @config['dependencies'], implicitly-defined dependencies such as
|
|
804
|
+
# add_firewall_rules or vpc stanzas, and may refer to objects internal
|
|
805
|
+
# to this deployment or external. Will populate the instance variables
|
|
806
|
+
# @dependencies (general dependencies, which can only be sibling
|
|
807
|
+
# resources in this deployment), as well as for certain config stanzas
|
|
808
|
+
# which can refer to external resources (@vpc, @loadbalancers,
|
|
809
|
+
# @add_firewall_rules)
|
|
810
|
+
def dependencies(use_cache: false)
|
|
811
|
+
@dependencies = {} if @dependencies.nil?
|
|
812
|
+
@loadbalancers = [] if @loadbalancers.nil?
|
|
813
|
+
if @config.nil?
|
|
814
|
+
return [@dependencies, @vpc, @loadbalancers]
|
|
815
|
+
end
|
|
816
|
+
if use_cache and @dependencies.size > 0
|
|
817
|
+
return [@dependencies, @vpc, @loadbalancers]
|
|
818
|
+
end
|
|
819
|
+
@config['dependencies'] = [] if @config['dependencies'].nil?
|
|
820
|
+
|
|
821
|
+
# First, general dependencies. These should all be fellow members of
|
|
822
|
+
# the current deployment.
|
|
823
|
+
@config['dependencies'].each { |dep|
|
|
824
|
+
@dependencies[dep['type']] ||= {}
|
|
825
|
+
next if @dependencies[dep['type']].has_key?(dep['name'])
|
|
826
|
+
handle = @deploy.findLitterMate(type: dep['type'], name: dep['name']) if !@deploy.nil?
|
|
827
|
+
if !handle.nil?
|
|
828
|
+
MU.log "Loaded dependency for #{self}: #{dep['name']} => #{handle}", MU::DEBUG
|
|
829
|
+
@dependencies[dep['type']][dep['name']] = handle
|
|
830
|
+
else
|
|
831
|
+
# XXX yell under circumstances where we should expect to have
|
|
832
|
+
# our stuff available already?
|
|
833
|
+
end
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
# Special dependencies: my containing VPC
|
|
837
|
+
if self.class.can_live_in_vpc and !@config['vpc'].nil?
|
|
838
|
+
MU.log "Loading VPC for #{self}", MU::DEBUG, details: @config['vpc']
|
|
839
|
+
if !@config['vpc']["vpc_name"].nil? and
|
|
840
|
+
@dependencies.has_key?("vpc") and
|
|
841
|
+
@dependencies["vpc"].has_key?(@config['vpc']["vpc_name"])
|
|
842
|
+
@vpc = @dependencies["vpc"][@config['vpc']["vpc_name"]]
|
|
843
|
+
else
|
|
844
|
+
tag_key, tag_value = @config['vpc']['tag'].split(/=/, 2) if !@config['vpc']['tag'].nil?
|
|
845
|
+
if !@config['vpc'].has_key?("vpc_id") and
|
|
846
|
+
!@config['vpc'].has_key?("deploy_id") and !@deploy.nil?
|
|
847
|
+
@config['vpc']["deploy_id"] = @deploy.deploy_id
|
|
848
|
+
end
|
|
849
|
+
vpcs = MU::MommaCat.findStray(
|
|
850
|
+
@config['cloud'],
|
|
851
|
+
"vpc",
|
|
852
|
+
deploy_id: @config['vpc']["deploy_id"],
|
|
853
|
+
cloud_id: @config['vpc']["vpc_id"],
|
|
854
|
+
name: @config['vpc']["vpc_name"],
|
|
855
|
+
tag_key: tag_key,
|
|
856
|
+
tag_value: tag_value,
|
|
857
|
+
region: @config['vpc']["region"],
|
|
858
|
+
calling_deploy: @deploy,
|
|
859
|
+
dummy_ok: true
|
|
860
|
+
)
|
|
861
|
+
@vpc = vpcs.first if !vpcs.nil? and vpcs.size > 0
|
|
862
|
+
end
|
|
863
|
+
if !@vpc.nil? and (
|
|
864
|
+
@config['vpc'].has_key?("nat_host_id") or
|
|
865
|
+
@config['vpc'].has_key?("nat_host_tag") or
|
|
866
|
+
@config['vpc'].has_key?("nat_host_ip") or
|
|
867
|
+
@config['vpc'].has_key?("nat_host_name")
|
|
868
|
+
)
|
|
869
|
+
|
|
870
|
+
nat_tag_key, nat_tag_value = @config['vpc']['nat_host_tag'].split(/=/, 2) if !@config['vpc']['nat_host_tag'].nil?
|
|
871
|
+
|
|
872
|
+
@nat = @vpc.findBastion(
|
|
873
|
+
nat_name: @config['vpc']['nat_host_name'],
|
|
874
|
+
nat_cloud_id: @config['vpc']['nat_host_id'],
|
|
875
|
+
nat_tag_key: nat_tag_key,
|
|
876
|
+
nat_tag_value: nat_tag_value,
|
|
877
|
+
nat_ip: @config['vpc']['nat_host_ip']
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
if @nat.nil?
|
|
881
|
+
if !@vpc.cloud_desc.nil?
|
|
882
|
+
@nat = @vpc.findNat(
|
|
883
|
+
nat_cloud_id: @config['vpc']['nat_host_id'],
|
|
884
|
+
nat_filter_key: "vpc-id",
|
|
885
|
+
region: @config['vpc']["region"],
|
|
886
|
+
nat_filter_value: @vpc.cloud_id
|
|
887
|
+
)
|
|
888
|
+
else
|
|
889
|
+
@nat = @vpc.findNat(
|
|
890
|
+
nat_cloud_id: @config['vpc']['nat_host_id'],
|
|
891
|
+
region: @config['vpc']["region"]
|
|
892
|
+
)
|
|
893
|
+
end
|
|
894
|
+
end
|
|
895
|
+
end
|
|
896
|
+
elsif self.class.cfg_name == "vpc"
|
|
897
|
+
@vpc = self
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
# Special dependencies: LoadBalancers I've asked to attach to an
|
|
901
|
+
# instance.
|
|
902
|
+
if @config.has_key?("loadbalancers")
|
|
903
|
+
@loadbalancers = [] if !@loadbalancers
|
|
904
|
+
@config['loadbalancers'].each { |lb|
|
|
905
|
+
MU.log "Loading LoadBalancer for #{self}", MU::DEBUG, details: lb
|
|
906
|
+
if @dependencies.has_key?("loadbalancer") and
|
|
907
|
+
@dependencies["loadbalancer"].has_key?(lb['concurrent_load_balancer'])
|
|
908
|
+
@loadbalancers << @dependencies["loadbalancer"][lb['concurrent_load_balancer']]
|
|
909
|
+
else
|
|
910
|
+
if !lb.has_key?("existing_load_balancer") and
|
|
911
|
+
!lb.has_key?("deploy_id") and !@deploy.nil?
|
|
912
|
+
lb["deploy_id"] = @deploy.deploy_id
|
|
913
|
+
end
|
|
914
|
+
lbs = MU::MommaCat.findStray(
|
|
915
|
+
@config['cloud'],
|
|
916
|
+
"loadbalancer",
|
|
917
|
+
deploy_id: lb["deploy_id"],
|
|
918
|
+
cloud_id: lb['existing_load_balancer'],
|
|
919
|
+
name: lb['concurrent_load_balancer'],
|
|
920
|
+
region: @config["region"],
|
|
921
|
+
calling_deploy: @deploy,
|
|
922
|
+
dummy_ok: true
|
|
923
|
+
)
|
|
924
|
+
@loadbalancers << lbs.first if !lbs.nil? and lbs.size > 0
|
|
925
|
+
end
|
|
926
|
+
}
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
return [@dependencies, @vpc, @loadbalancers]
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
def self.find(*flags)
|
|
933
|
+
allfound = {}
|
|
934
|
+
|
|
935
|
+
MU::Cloud.supportedClouds.each { |cloud|
|
|
936
|
+
begin
|
|
937
|
+
args = flags.first
|
|
938
|
+
# skip this cloud if we have a region argument that makes no
|
|
939
|
+
# sense there
|
|
940
|
+
cloudbase = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
|
941
|
+
if args[:region] and cloudbase.respond_to?(:listRegions)
|
|
942
|
+
next if !cloudbase.listRegions.include?(args[:region])
|
|
943
|
+
end
|
|
944
|
+
cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
|
|
945
|
+
|
|
946
|
+
found = cloudclass.find(args)
|
|
947
|
+
if !found.nil?
|
|
948
|
+
if found.is_a?(Hash)
|
|
949
|
+
allfound.merge!(found)
|
|
950
|
+
else
|
|
951
|
+
raise MuError, "#{cloudclass}.find returned a non-Hash result"
|
|
952
|
+
end
|
|
953
|
+
end
|
|
954
|
+
rescue MuCloudResourceNotImplemented
|
|
955
|
+
end
|
|
956
|
+
}
|
|
957
|
+
allfound
|
|
958
|
+
end
|
|
959
|
+
|
|
960
|
+
if shortname == "DNSZone"
|
|
961
|
+
def self.genericMuDNSEntry(*flags)
|
|
962
|
+
# XXX have this switch on a global config for where Mu puts its DNS
|
|
963
|
+
cloudclass = MU::Cloud.loadCloudType(MU::Config.defaultCloud, "DNSZone")
|
|
964
|
+
cloudclass.genericMuDNSEntry(flags.first)
|
|
965
|
+
end
|
|
966
|
+
def self.createRecordsFromConfig(*flags)
|
|
967
|
+
cloudclass = MU::Cloud.loadCloudType(MU::Config.defaultCloud, "DNSZone")
|
|
968
|
+
if !flags.nil? and flags.size == 1
|
|
969
|
+
cloudclass.createRecordsFromConfig(flags.first)
|
|
970
|
+
else
|
|
971
|
+
cloudclass.createRecordsFromConfig(*flags)
|
|
972
|
+
end
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
if shortname == "Server"
|
|
977
|
+
def windows?
|
|
978
|
+
return true if %w{win2k16 win2k12r2 win2k12 win2k8 win2k8r2 windows}.include?(@config['platform'])
|
|
979
|
+
begin
|
|
980
|
+
return true if cloud_desc.respond_to?(:platform) and cloud_desc.platform == "Windows"
|
|
981
|
+
# XXX ^ that's AWS-speak, doesn't cover GCP or anything else; maybe we should require cloud layers to implement this so we can just call @cloudobj.windows?
|
|
982
|
+
rescue MU::MuError
|
|
983
|
+
return false
|
|
984
|
+
end
|
|
985
|
+
false
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
# Gracefully message and attempt to accommodate the common transient errors peculiar to Windows nodes
|
|
989
|
+
# @param e [Exception]: The exception that we're handling
|
|
990
|
+
# @param retries [Integer]: The current number of retries, which we'll increment and pass back to the caller
|
|
991
|
+
# @param rebootable_fails [Integer]: The current number of reboot-worthy failures, which we'll increment and pass back to the caller
|
|
992
|
+
# @param max_retries [Integer]: Maximum number of retries to attempt; we'll raise an exception if this is exceeded
|
|
993
|
+
# @param reboot_on_problems [Boolean]: Whether we should try to reboot a "stuck" machine
|
|
994
|
+
# @param retry_interval [Integer]: How many seconds to wait before returning for another attempt
|
|
995
|
+
def handleWindowsFail(e, retries, rebootable_fails, max_retries: 30, reboot_on_problems: false, retry_interval: 45)
|
|
996
|
+
msg = "WinRM connection to https://"+@mu_name+":5986/wsman: #{e.message}, waiting #{retry_interval}s (attempt #{retries}/#{max_retries})"
|
|
997
|
+
if e.class.name == "WinRM::WinRMAuthorizationError" or e.message.match(/execution expired/) and reboot_on_problems
|
|
998
|
+
if rebootable_fails > 0 and (rebootable_fails % 5) == 0
|
|
999
|
+
MU.log "#{@mu_name} still misbehaving, forcing Stop and Start from API", MU::WARN
|
|
1000
|
+
reboot(true) # vicious API stop/start
|
|
1001
|
+
sleep retry_interval*3
|
|
1002
|
+
rebootable_fails = 0
|
|
1003
|
+
else
|
|
1004
|
+
if rebootable_fails == 3
|
|
1005
|
+
MU.log "#{@mu_name} misbehaving, attempting to reboot from API", MU::WARN
|
|
1006
|
+
reboot # graceful API restart
|
|
1007
|
+
sleep retry_interval*2
|
|
1008
|
+
end
|
|
1009
|
+
rebootable_fails = rebootable_fails + 1
|
|
1010
|
+
end
|
|
1011
|
+
end
|
|
1012
|
+
if retries < max_retries
|
|
1013
|
+
if retries == 1 or (retries/max_retries <= 0.5 and (retries % 3) == 0 and retries != 0)
|
|
1014
|
+
MU.log msg, MU::NOTICE
|
|
1015
|
+
elsif retries/max_retries > 0.5
|
|
1016
|
+
MU.log msg, MU::WARN, details: e.inspect
|
|
1017
|
+
end
|
|
1018
|
+
sleep retry_interval
|
|
1019
|
+
retries = retries + 1
|
|
1020
|
+
else
|
|
1021
|
+
raise MuError, "#{@mu_name}: #{e.inspect} trying to connect with WinRM, max_retries exceeded", e.backtrace
|
|
1022
|
+
end
|
|
1023
|
+
return [retries, rebootable_fails]
|
|
1024
|
+
end
|
|
1025
|
+
|
|
1026
|
+
def windowsRebootPending?(shell = nil)
|
|
1027
|
+
if shell.nil?
|
|
1028
|
+
shell = getWinRMSession(1, 30)
|
|
1029
|
+
end
|
|
1030
|
+
# if (Get-Item "HKLM:/SOFTWARE/Microsoft/Windows/CurrentVersion/WindowsUpdate/Auto Update/RebootRequired" -EA Ignore) { exit 1 }
|
|
1031
|
+
cmd = %Q{
|
|
1032
|
+
if (Get-ChildItem "HKLM:/Software/Microsoft/Windows/CurrentVersion/Component Based Servicing/RebootPending" -EA Ignore) {
|
|
1033
|
+
echo "Component Based Servicing/RebootPending is true"
|
|
1034
|
+
exit 1
|
|
1035
|
+
}
|
|
1036
|
+
if (Get-ItemProperty "HKLM:/SYSTEM/CurrentControlSet/Control/Session Manager" -Name PendingFileRenameOperations -EA Ignore) {
|
|
1037
|
+
echo "Control/Session Manager/PendingFileRenameOperations is true"
|
|
1038
|
+
exit 1
|
|
1039
|
+
}
|
|
1040
|
+
try {
|
|
1041
|
+
$util = [wmiclass]"\\\\.\\root\\ccm\\clientsdk:CCM_ClientUtilities"
|
|
1042
|
+
$status = $util.DetermineIfRebootPending()
|
|
1043
|
+
if(($status -ne $null) -and $status.RebootPending){
|
|
1044
|
+
echo "WMI says RebootPending is true"
|
|
1045
|
+
exit 1
|
|
1046
|
+
}
|
|
1047
|
+
} catch {
|
|
1048
|
+
exit 0
|
|
1049
|
+
}
|
|
1050
|
+
exit 0
|
|
1051
|
+
}
|
|
1052
|
+
resp = shell.run(cmd)
|
|
1053
|
+
returnval = resp.exitcode == 0 ? false : true
|
|
1054
|
+
shell.close
|
|
1055
|
+
returnval
|
|
1056
|
+
end
|
|
1057
|
+
|
|
1058
|
+
# Basic setup tasks performed on a new node during its first WinRM
|
|
1059
|
+
# connection. Most of this is terrible Windows glue.
|
|
1060
|
+
# @param shell [WinRM::Shells::Powershell]: An active Powershell session to the new node.
|
|
1061
|
+
def initialWinRMTasks(shell)
|
|
1062
|
+
retries = 0
|
|
1063
|
+
rebootable_fails = 0
|
|
1064
|
+
begin
|
|
1065
|
+
if !@config['use_cloud_provider_windows_password']
|
|
1066
|
+
pw = @groomer.getSecret(
|
|
1067
|
+
vault: @config['mu_name'],
|
|
1068
|
+
item: "windows_credentials",
|
|
1069
|
+
field: "password"
|
|
1070
|
+
)
|
|
1071
|
+
win_check_for_pw = %Q{Add-Type -AssemblyName System.DirectoryServices.AccountManagement; $Creds = (New-Object System.Management.Automation.PSCredential("#{@config["windows_admin_username"]}", (ConvertTo-SecureString "#{pw}" -AsPlainText -Force)));$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine); $DS.ValidateCredentials($Creds.GetNetworkCredential().UserName, $Creds.GetNetworkCredential().password); echo $Result}
|
|
1072
|
+
resp = shell.run(win_check_for_pw)
|
|
1073
|
+
if resp.stdout.chomp != "True"
|
|
1074
|
+
win_set_pw = %Q{(([adsi]('WinNT://./#{@config["windows_admin_username"]}, user')).psbase.invoke('SetPassword', '#{pw}'))}
|
|
1075
|
+
resp = shell.run(win_set_pw)
|
|
1076
|
+
puts resp.stdout
|
|
1077
|
+
MU.log "Resetting Windows host password", MU::NOTICE, details: resp.stdout
|
|
1078
|
+
end
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1081
|
+
# Install Cygwin here, because for some reason it breaks inside Chef
|
|
1082
|
+
# XXX would love to not do this here
|
|
1083
|
+
pkgs = ["bash", "mintty", "vim", "curl", "openssl", "wget", "lynx", "openssh"]
|
|
1084
|
+
admin_home = "c:/bin/cygwin/home/#{@config["windows_admin_username"]}"
|
|
1085
|
+
install_cygwin = %Q{
|
|
1086
|
+
If (!(Test-Path "c:/bin/cygwin/Cygwin.bat")){
|
|
1087
|
+
$WebClient = New-Object System.Net.WebClient
|
|
1088
|
+
$WebClient.DownloadFile("http://cygwin.com/setup-x86_64.exe","$env:Temp/setup-x86_64.exe")
|
|
1089
|
+
Start-Process -wait -FilePath $env:Temp/setup-x86_64.exe -ArgumentList "-q -n -l $env:Temp/cygwin -R c:/bin/cygwin -s http://mirror.cs.vt.edu/pub/cygwin/cygwin/ -P #{pkgs.join(',')}"
|
|
1090
|
+
}
|
|
1091
|
+
if(!(Test-Path #{admin_home})){
|
|
1092
|
+
New-Item -type directory -path #{admin_home}
|
|
1093
|
+
}
|
|
1094
|
+
if(!(Test-Path #{admin_home}/.ssh)){
|
|
1095
|
+
New-Item -type directory -path #{admin_home}/.ssh
|
|
1096
|
+
}
|
|
1097
|
+
if(!(Test-Path #{admin_home}/.ssh/authorized_keys)){
|
|
1098
|
+
New-Item #{admin_home}/.ssh/authorized_keys -type file -force -value "#{@deploy.ssh_public_key}"
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
resp = shell.run(install_cygwin)
|
|
1102
|
+
if resp.exitcode != 0
|
|
1103
|
+
MU.log "Failed at installing Cygwin", MU::ERR, details: resp
|
|
1104
|
+
end
|
|
1105
|
+
|
|
1106
|
+
set_hostname = true
|
|
1107
|
+
hostname = nil
|
|
1108
|
+
if !@config['active_directory'].nil?
|
|
1109
|
+
if @config['active_directory']['node_type'] == "domain_controller" && @config['active_directory']['domain_controller_hostname']
|
|
1110
|
+
hostname = @config['active_directory']['domain_controller_hostname']
|
|
1111
|
+
@mu_windows_name = hostname
|
|
1112
|
+
set_hostname = true
|
|
1113
|
+
else
|
|
1114
|
+
# Do we have an AD specific hostname?
|
|
1115
|
+
hostname = @mu_windows_name
|
|
1116
|
+
set_hostname = true
|
|
1117
|
+
end
|
|
1118
|
+
else
|
|
1119
|
+
hostname = @mu_windows_name
|
|
1120
|
+
end
|
|
1121
|
+
resp = shell.run(%Q{hostname})
|
|
1122
|
+
|
|
1123
|
+
if resp.stdout.chomp != hostname
|
|
1124
|
+
resp = shell.run(%Q{Rename-Computer -NewName '#{hostname}' -Force -PassThru -Restart; Restart-Computer -Force})
|
|
1125
|
+
MU.log "Renaming Windows host to #{hostname}; this will trigger a reboot", MU::NOTICE, details: resp.stdout
|
|
1126
|
+
reboot(true)
|
|
1127
|
+
sleep 30
|
|
1128
|
+
end
|
|
1129
|
+
rescue WinRM::WinRMError, HTTPClient::ConnectTimeoutError => e
|
|
1130
|
+
retries, rebootable_fails = handleWindowsFail(e, retries, rebootable_fails, max_retries: 10, reboot_on_problems: true, retry_interval: 30)
|
|
1131
|
+
retry
|
|
1132
|
+
end
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
# Basic setup tasks performed on a new node during its first initial
|
|
1137
|
+
# ssh connection. Most of this is terrible Windows glue.
|
|
1138
|
+
# @param ssh [Net::SSH::Connection::Session]: The active SSH session to the new node.
|
|
1139
|
+
def initialSSHTasks(ssh)
|
|
1140
|
+
win_env_fix = %q{echo 'export PATH="$PATH:/cygdrive/c/opscode/chef/embedded/bin"' > "$HOME/chef-client"; echo 'prev_dir="`pwd`"; for __dir in /proc/registry/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session\ Manager/Environment;do cd "$__dir"; for __var in `ls * | grep -v TEMP | grep -v TMP`;do __var=`echo $__var | tr "[a-z]" "[A-Z]"`; test -z "${!__var}" && export $__var="`cat $__var`" >/dev/null 2>&1; done; done; cd "$prev_dir"; /cygdrive/c/opscode/chef/bin/chef-client.bat $@' >> "$HOME/chef-client"; chmod 700 "$HOME/chef-client"; ( grep "^alias chef-client=" "$HOME/.bashrc" || echo 'alias chef-client="$HOME/chef-client"' >> "$HOME/.bashrc" ) ; ( grep "^alias mu-groom=" "$HOME/.bashrc" || echo 'alias mu-groom="powershell -File \"c:/Program Files/Amazon/Ec2ConfigService/Scripts/UserScript.ps1\""' >> "$HOME/.bashrc" )}
|
|
1141
|
+
win_installer_check = %q{ls /proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Installer/}
|
|
1142
|
+
lnx_installer_check = %q{ps auxww | awk '{print $11}' | egrep '(/usr/bin/yum|apt-get|dpkg)'}
|
|
1143
|
+
lnx_updates_check = %q{( test -f /.mu-installer-ran-updates || ! test -d /var/lib/cloud/instance ) || echo "userdata still running"}
|
|
1144
|
+
win_set_pw = nil
|
|
1145
|
+
|
|
1146
|
+
if windows? and !@config['use_cloud_provider_windows_password']
|
|
1147
|
+
# This covers both the case where we have a windows password passed from a vault and where we need to use a a random Windows Admin password generated by MU::Cloud::Server.generateWindowsPassword
|
|
1148
|
+
pw = @groomer.getSecret(
|
|
1149
|
+
vault: @config['mu_name'],
|
|
1150
|
+
item: "windows_credentials",
|
|
1151
|
+
field: "password"
|
|
1152
|
+
)
|
|
1153
|
+
win_check_for_pw = %Q{powershell -Command '& {Add-Type -AssemblyName System.DirectoryServices.AccountManagement; $Creds = (New-Object System.Management.Automation.PSCredential("#{@config["windows_admin_username"]}", (ConvertTo-SecureString "#{pw}" -AsPlainText -Force)));$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine); $DS.ValidateCredentials($Creds.GetNetworkCredential().UserName, $Creds.GetNetworkCredential().password); echo $Result}'}
|
|
1154
|
+
win_set_pw = %Q{powershell -Command "& {(([adsi]('WinNT://./#{@config["windows_admin_username"]}, user')).psbase.invoke('SetPassword', '#{pw}'))}"}
|
|
1155
|
+
end
|
|
1156
|
+
|
|
1157
|
+
# There shouldn't be a use case where a domain joined computer goes through initialSSHTasks. Removing Active Directory specific computer rename.
|
|
1158
|
+
set_hostname = true
|
|
1159
|
+
hostname = nil
|
|
1160
|
+
if !@config['active_directory'].nil?
|
|
1161
|
+
if @config['active_directory']['node_type'] == "domain_controller" && @config['active_directory']['domain_controller_hostname']
|
|
1162
|
+
hostname = @config['active_directory']['domain_controller_hostname']
|
|
1163
|
+
@mu_windows_name = hostname
|
|
1164
|
+
set_hostname = true
|
|
1165
|
+
else
|
|
1166
|
+
# Do we have an AD specific hostname?
|
|
1167
|
+
hostname = @mu_windows_name
|
|
1168
|
+
set_hostname = true
|
|
1169
|
+
end
|
|
1170
|
+
else
|
|
1171
|
+
hostname = @mu_windows_name
|
|
1172
|
+
end
|
|
1173
|
+
win_check_for_hostname = %Q{powershell -Command '& {hostname}'}
|
|
1174
|
+
win_set_hostname = %Q{powershell -Command "& {Rename-Computer -NewName '#{hostname}' -Force -PassThru -Restart; Restart-Computer -Force }"}
|
|
1175
|
+
|
|
1176
|
+
begin
|
|
1177
|
+
# Set our admin password first, if we need to
|
|
1178
|
+
if windows? and !win_set_pw.nil? and !win_check_for_pw.nil?
|
|
1179
|
+
output = ssh.exec!(win_check_for_pw)
|
|
1180
|
+
raise MU::Cloud::BootstrapTempFail, "Got nil output from ssh session, waiting and retrying" if output.nil?
|
|
1181
|
+
if !output.match(/True/)
|
|
1182
|
+
MU.log "Setting Windows password for user #{@config['windows_admin_username']}", details: ssh.exec!(win_set_pw)
|
|
1183
|
+
end
|
|
1184
|
+
end
|
|
1185
|
+
if windows?
|
|
1186
|
+
output = ssh.exec!(win_env_fix)
|
|
1187
|
+
output = ssh.exec!(win_installer_check)
|
|
1188
|
+
raise MU::Cloud::BootstrapTempFail, "Got nil output from ssh session, waiting and retrying" if output.nil?
|
|
1189
|
+
if output.match(/InProgress/)
|
|
1190
|
+
raise MU::Cloud::BootstrapTempFail, "Windows Installer service is still doing something, need to wait"
|
|
1191
|
+
end
|
|
1192
|
+
if set_hostname and !@hostname_set and @mu_windows_name
|
|
1193
|
+
output = ssh.exec!(win_check_for_hostname)
|
|
1194
|
+
raise MU::Cloud::BootstrapTempFail, "Got nil output from ssh session, waiting and retrying" if output.nil?
|
|
1195
|
+
if !output.match(/#{@mu_windows_name}/)
|
|
1196
|
+
MU.log "Setting Windows hostname to #{@mu_windows_name}", details: ssh.exec!(win_set_hostname)
|
|
1197
|
+
@hostname_set = true
|
|
1198
|
+
# Reboot from the API too, in case Windows is flailing
|
|
1199
|
+
if !@cloudobj.nil?
|
|
1200
|
+
@cloudobj.reboot
|
|
1201
|
+
else
|
|
1202
|
+
reboot
|
|
1203
|
+
end
|
|
1204
|
+
raise MU::Cloud::BootstrapTempFail, "Set hostname in Windows, waiting for reboot"
|
|
1205
|
+
end
|
|
1206
|
+
end
|
|
1207
|
+
else
|
|
1208
|
+
output = ssh.exec!(lnx_installer_check)
|
|
1209
|
+
if !output.nil? and !output.empty?
|
|
1210
|
+
raise MU::Cloud::BootstrapTempFail, "Linux package manager is still doing something, need to wait (#{output})"
|
|
1211
|
+
end
|
|
1212
|
+
if !@config['skipinitialupdates']
|
|
1213
|
+
output = ssh.exec!(lnx_updates_check)
|
|
1214
|
+
if !output.nil? and output.match(/userdata still running/)
|
|
1215
|
+
raise MU::Cloud::BootstrapTempFail, "Waiting for initial userdata system updates to complete"
|
|
1216
|
+
end
|
|
1217
|
+
end
|
|
1218
|
+
end
|
|
1219
|
+
rescue RuntimeError => e
|
|
1220
|
+
raise MU::Cloud::BootstrapTempFail, "Got #{e.inspect} performing initial SSH connect tasks, will try again"
|
|
1221
|
+
end
|
|
1222
|
+
|
|
1223
|
+
end
|
|
1224
|
+
|
|
1225
|
+
# Get a privileged Powershell session on the server in question, using SSL-encrypted WinRM with certificate authentication.
|
|
1226
|
+
# @param max_retries [Integer]:
|
|
1227
|
+
# @param retry_interval [Integer]:
|
|
1228
|
+
# @param timeout [Integer]:
|
|
1229
|
+
# @param winrm_retries [Integer]:
|
|
1230
|
+
# @param reboot_on_problems [Boolean]:
|
|
1231
|
+
def getWinRMSession(max_retries = 40, retry_interval = 60, timeout: 30, winrm_retries: 5, reboot_on_problems: false)
|
|
1232
|
+
nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
|
|
1233
|
+
@mu_name ||= @config['mu_name']
|
|
1234
|
+
|
|
1235
|
+
conn = nil
|
|
1236
|
+
shell = nil
|
|
1237
|
+
opts = nil
|
|
1238
|
+
# and now, a thing I really don't want to do
|
|
1239
|
+
MU::MommaCat.addInstanceToEtcHosts(canonical_ip, @mu_name)
|
|
1240
|
+
|
|
1241
|
+
# catch exceptions that circumvent our regular call stack
|
|
1242
|
+
Thread.abort_on_exception = false
|
|
1243
|
+
Thread.handle_interrupt(WinRM::WinRMWSManFault => :never) {
|
|
1244
|
+
begin
|
|
1245
|
+
Thread.handle_interrupt(WinRM::WinRMWSManFault => :immediate) {
|
|
1246
|
+
MU.log "(Probably harmless) Caught a WinRM::WinRMWSManFault in #{Thread.current.inspect}", MU::DEBUG, details: Thread.current.backtrace
|
|
1247
|
+
}
|
|
1248
|
+
ensure
|
|
1249
|
+
# Reraise something useful
|
|
1250
|
+
end
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
retries = 0
|
|
1254
|
+
rebootable_fails = 0
|
|
1255
|
+
begin
|
|
1256
|
+
MU.log "Calling WinRM on #{@mu_name}", MU::DEBUG, details: opts
|
|
1257
|
+
opts = {
|
|
1258
|
+
endpoint: 'https://'+@mu_name+':5986/wsman',
|
|
1259
|
+
retry_limit: winrm_retries,
|
|
1260
|
+
no_ssl_peer_verification: true, # XXX this should not be necessary; we get 'hostname "foo" does not match the server certificate' even when it clearly does match
|
|
1261
|
+
ca_trust_path: "#{MU.mySSLDir}/Mu_CA.pem",
|
|
1262
|
+
transport: :ssl,
|
|
1263
|
+
operation_timeout: timeout,
|
|
1264
|
+
client_cert: "#{MU.mySSLDir}/#{@mu_name}-winrm.crt",
|
|
1265
|
+
client_key: "#{MU.mySSLDir}/#{@mu_name}-winrm.key"
|
|
1266
|
+
}
|
|
1267
|
+
conn = WinRM::Connection.new(opts)
|
|
1268
|
+
MU.log "WinRM connection to #{@mu_name} created", MU::DEBUG, details: conn
|
|
1269
|
+
shell = conn.shell(:powershell)
|
|
1270
|
+
shell.run('ipconfig') # verify that we can do something
|
|
1271
|
+
rescue Errno::EHOSTUNREACH, Errno::ECONNREFUSED, HTTPClient::ConnectTimeoutError, OpenSSL::SSL::SSLError, SocketError, WinRM::WinRMError, Timeout::Error => e
|
|
1272
|
+
retries, rebootable_fails = handleWindowsFail(e, retries, rebootable_fails, max_retries: max_retries, reboot_on_problems: reboot_on_problems, retry_interval: retry_interval)
|
|
1273
|
+
retry
|
|
1274
|
+
ensure
|
|
1275
|
+
MU::MommaCat.removeInstanceFromEtcHosts(@mu_name)
|
|
1276
|
+
end
|
|
1277
|
+
|
|
1278
|
+
shell
|
|
1279
|
+
end
|
|
1280
|
+
|
|
1281
|
+
# @param max_retries [Integer]: Number of connection attempts to make before giving up
|
|
1282
|
+
# @param retry_interval [Integer]: Number of seconds to wait between connection attempts
|
|
1283
|
+
# @return [Net::SSH::Connection::Session]
|
|
1284
|
+
def getSSHSession(max_retries = 12, retry_interval = 30)
|
|
1285
|
+
ssh_keydir = Etc.getpwnam(@deploy.mu_user).dir+"/.ssh"
|
|
1286
|
+
nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
|
|
1287
|
+
session = nil
|
|
1288
|
+
retries = 0
|
|
1289
|
+
|
|
1290
|
+
# XXX WHY is this a thing
|
|
1291
|
+
Thread.handle_interrupt(Errno::ECONNREFUSED => :never) {
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
begin
|
|
1295
|
+
MU::Cloud.handleNetSSHExceptions
|
|
1296
|
+
if !nat_ssh_host.nil?
|
|
1297
|
+
proxy_cmd = "ssh -q -o StrictHostKeyChecking=no -W %h:%p #{nat_ssh_user}@#{nat_ssh_host}"
|
|
1298
|
+
MU.log "Attempting SSH to #{canonical_ip} (#{@mu_name}) as #{ssh_user} with key #{@deploy.ssh_key_name} using proxy '#{proxy_cmd}'" if retries == 0
|
|
1299
|
+
proxy = Net::SSH::Proxy::Command.new(proxy_cmd)
|
|
1300
|
+
session = Net::SSH.start(
|
|
1301
|
+
canonical_ip,
|
|
1302
|
+
ssh_user,
|
|
1303
|
+
:config => false,
|
|
1304
|
+
:keys_only => true,
|
|
1305
|
+
:keys => [ssh_keydir+"/"+nat_ssh_key, ssh_keydir+"/"+@deploy.ssh_key_name],
|
|
1306
|
+
:verify_host_key => false,
|
|
1307
|
+
# :verbose => :info,
|
|
1308
|
+
:port => 22,
|
|
1309
|
+
:auth_methods => ['publickey'],
|
|
1310
|
+
:proxy => proxy
|
|
1311
|
+
)
|
|
1312
|
+
else
|
|
1313
|
+
MU.log "Attempting SSH to #{canonical_ip} (#{@mu_name}) as #{ssh_user} with key #{ssh_keydir}/#{@deploy.ssh_key_name}" if retries == 0
|
|
1314
|
+
session = Net::SSH.start(
|
|
1315
|
+
canonical_ip,
|
|
1316
|
+
ssh_user,
|
|
1317
|
+
:config => false,
|
|
1318
|
+
:keys_only => true,
|
|
1319
|
+
:keys => [ssh_keydir+"/"+@deploy.ssh_key_name],
|
|
1320
|
+
:verify_host_key => false,
|
|
1321
|
+
# :verbose => :info,
|
|
1322
|
+
:port => 22,
|
|
1323
|
+
:auth_methods => ['publickey']
|
|
1324
|
+
)
|
|
1325
|
+
end
|
|
1326
|
+
retries = 0
|
|
1327
|
+
rescue Net::SSH::HostKeyMismatch => e
|
|
1328
|
+
MU.log("Remembering new key: #{e.fingerprint}")
|
|
1329
|
+
e.remember_host!
|
|
1330
|
+
session.close
|
|
1331
|
+
retry
|
|
1332
|
+
rescue SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, MU::Cloud::NetSSHFail => e
|
|
1333
|
+
begin
|
|
1334
|
+
session.close if !session.nil?
|
|
1335
|
+
rescue Net::SSH::Disconnect, IOError => e
|
|
1336
|
+
if windows?
|
|
1337
|
+
MU.log "Windows has probably closed the ssh session before we could. Waiting before trying again", MU::NOTICE
|
|
1338
|
+
else
|
|
1339
|
+
MU.log "ssh session was closed unexpectedly, waiting before trying again", MU::NOTICE
|
|
1340
|
+
end
|
|
1341
|
+
sleep 10
|
|
1342
|
+
end
|
|
1343
|
+
|
|
1344
|
+
if retries < max_retries
|
|
1345
|
+
retries = retries + 1
|
|
1346
|
+
msg = "ssh #{ssh_user}@#{@config['mu_name']}: #{e.message}, waiting #{retry_interval}s (attempt #{retries}/#{max_retries})", MU::WARN
|
|
1347
|
+
if retries == 1 or (retries/max_retries <= 0.5 and (retries % 3) == 0)
|
|
1348
|
+
MU.log msg, MU::NOTICE
|
|
1349
|
+
elsif retries/max_retries > 0.5
|
|
1350
|
+
MU.log msg, MU::WARN, details: e.inspect
|
|
1351
|
+
end
|
|
1352
|
+
sleep retry_interval
|
|
1353
|
+
retry
|
|
1354
|
+
else
|
|
1355
|
+
raise MuError, "#{@config['mu_name']}: #{e.inspect} trying to connect with SSH, max_retries exceeded", e.backtrace
|
|
1356
|
+
end
|
|
1357
|
+
end
|
|
1358
|
+
return session
|
|
1359
|
+
end
|
|
1360
|
+
end
|
|
1361
|
+
|
|
1362
|
+
# Wrapper for the cleanup class method of underlying cloud object implementations.
|
|
1363
|
+
def self.cleanup(*flags)
|
|
1364
|
+
params = flags.first
|
|
1365
|
+
clouds = MU::Cloud.supportedClouds
|
|
1366
|
+
if params[:cloud]
|
|
1367
|
+
clouds = [params[:cloud]]
|
|
1368
|
+
params.delete(:cloud)
|
|
1369
|
+
end
|
|
1370
|
+
clouds.each { |cloud|
|
|
1371
|
+
begin
|
|
1372
|
+
cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
|
|
1373
|
+
raise MuCloudResourceNotImplemented if !cloudclass.respond_to?(:cleanup) or cloudclass.method(:cleanup).owner.to_s != "#<Class:#{cloudclass}>"
|
|
1374
|
+
MU.log "Invoking #{cloudclass}.cleanup from #{shortname}", MU::DEBUG, details: flags
|
|
1375
|
+
cloudclass.cleanup(params)
|
|
1376
|
+
rescue MuCloudResourceNotImplemented
|
|
1377
|
+
MU.log "No #{cloud} implementation of #{shortname}.cleanup, skipping", MU::DEBUG, details: flags
|
|
1378
|
+
end
|
|
1379
|
+
}
|
|
1380
|
+
MU::MommaCat.unlockAll
|
|
1381
|
+
end
|
|
1382
|
+
|
|
1383
|
+
# Wrap the instance methods that this cloud resource type has to
|
|
1384
|
+
# implement.
|
|
1385
|
+
MU::Cloud.resource_types[name.to_sym][:instance].each { |method|
|
|
1386
|
+
define_method method do |*args|
|
|
1387
|
+
return nil if @cloudobj.nil?
|
|
1388
|
+
MU.log "Invoking #{@cloudobj}.#{method}", MU::DEBUG
|
|
1389
|
+
|
|
1390
|
+
# Go ahead and guarantee that we can't accidentally trigger these
|
|
1391
|
+
# methods recursively.
|
|
1392
|
+
@method_semaphore.synchronize {
|
|
1393
|
+
# We're looking for recursion, not contention, so ignore some
|
|
1394
|
+
# obviously harmless things.
|
|
1395
|
+
if @method_locks.has_key?(method) and method != :findBastion and method != :cloud_id
|
|
1396
|
+
MU.log "Double-call to cloud method #{method} for #{self}", MU::DEBUG, details: caller + ["competing call stack:"] + @method_locks[method]
|
|
1397
|
+
end
|
|
1398
|
+
@method_locks[method] = caller
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
# Make sure the describe() caches are fresh
|
|
1402
|
+
@cloudobj.describe if method != :describe
|
|
1403
|
+
|
|
1404
|
+
# Don't run through dependencies on simple attr_reader lookups
|
|
1405
|
+
if ![:dependencies, :cloud_id, :config, :mu_name].include?(method)
|
|
1406
|
+
@cloudobj.dependencies
|
|
1407
|
+
end
|
|
1408
|
+
|
|
1409
|
+
retval = nil
|
|
1410
|
+
if !args.nil? and args.size == 1
|
|
1411
|
+
retval = @cloudobj.method(method).call(args.first)
|
|
1412
|
+
elsif !args.nil? and args.size > 0
|
|
1413
|
+
retval = @cloudobj.method(method).call(*args)
|
|
1414
|
+
else
|
|
1415
|
+
retval = @cloudobj.method(method).call
|
|
1416
|
+
end
|
|
1417
|
+
if (method == :create or method == :groom or method == :postBoot) and
|
|
1418
|
+
(!@destroyed and !@cloudobj.destroyed)
|
|
1419
|
+
deploydata = @cloudobj.method(:notify).call
|
|
1420
|
+
if deploydata.nil? or !deploydata.is_a?(Hash)
|
|
1421
|
+
MU.log "#{self} notify method did not return a Hash of deployment data", MU::WARN
|
|
1422
|
+
deploydata = MU.structToHash(@cloudobj.cloud_desc)
|
|
1423
|
+
end
|
|
1424
|
+
deploydata['cloud_id'] = @cloudobj.cloud_id if !@cloudobj.cloud_id.nil?
|
|
1425
|
+
deploydata['mu_name'] = @cloudobj.mu_name if !@cloudobj.mu_name.nil?
|
|
1426
|
+
@deploy.notify(self.class.cfg_plural, @config['name'], deploydata, triggering_node: @cloudobj, delayed_save: @delayed_save) if !@deploy.nil?
|
|
1427
|
+
elsif method == :notify
|
|
1428
|
+
retval['cloud_id'] = @cloudobj.cloud_id if !@cloudobj.cloud_id.nil?
|
|
1429
|
+
retval['mu_name'] = @cloudobj.mu_name if !@cloudobj.mu_name.nil?
|
|
1430
|
+
@deploy.notify(self.class.cfg_plural, @config['name'], retval, triggering_node: @cloudobj, delayed_save: @delayed_save) if !@deploy.nil?
|
|
1431
|
+
end
|
|
1432
|
+
@method_semaphore.synchronize {
|
|
1433
|
+
@method_locks.delete(method)
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
@deploydata = @cloudobj.deploydata
|
|
1437
|
+
@config = @cloudobj.config
|
|
1438
|
+
retval
|
|
1439
|
+
end
|
|
1440
|
+
} # end instance method list
|
|
1441
|
+
} # end dynamic class generation block
|
|
1442
|
+
} # end resource type iteration
|
|
1443
|
+
|
|
1444
|
+
end
|
|
1445
|
+
|
|
1446
|
+
end
|