diff --git a/.fixtures.yml b/.fixtures.yml new file mode 100644 index 0000000..dc69f75 --- /dev/null +++ b/.fixtures.yml @@ -0,0 +1,8 @@ +fixtures: + repositories: + "stdlib": "git://github.com/puppetlabs/puppetlabs-stdlib.git" + "firewall": "git://github.com/puppetlabs/puppetlabs-firewall.git" + "mysql": "git://github.com/rochaporto/puppet-mysql.git" + symlinks: + "cloudstack": "#{source_dir}" + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e898bd --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.vagrant +puppet.conf* +auth.conf* +fileserver.conf* +*.swp +*.swo +tests +environments +.idea +*~ +Gemfile.lock +.bundle +vendor +spec/fixtures diff --git a/.puppet-lint.rc b/.puppet-lint.rc new file mode 100644 index 0000000..b0d12b7 --- /dev/null +++ b/.puppet-lint.rc @@ -0,0 +1 @@ +--no-80chars-check diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6d27ea1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,30 @@ +language: ruby +rvm: + - 1.8.7 + - 1.9.3 + - 2.1.4 +script: + - "bundle exec rake spec SPEC_OPTS='--format documentation'" +env: + - PUPPET_VERSION="~> 2.6.0" + - PUPPET_VERSION="~> 2.7.0" + - PUPPET_VERSION="~> 3.0.0" + - PUPPET_VERSION="~> 3.1.0" + - PUPPET_VERSION="~> 3.8.0" + - PUPPET_VERSION="~> 4.2" +matrix: + exclude: + - rvm: 1.8.7 + env: PUPPET_VERSION="~> 4.2" + - rvm: 1.9.3 + env: PUPPET_VERSION="~> 2.6.0" + - rvm: 2.1.4 + env: PUPPET_VERSION="~> 2.6.0" + - rvm: 2.1.4 + env: PUPPET_VERSION="~> 2.7.0" + - rvm: 2.1.4 + env: PUPPET_VERSION="~> 3.0.0" + - rvm: 2.1.4 + env: PUPPET_VERSION="~> 3.1.0" + +sudo: false diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..5e01bf6 --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source 'https://rubygems.org' + +puppetversion = ENV['PUPPET_VERSION'] +gem 'puppet', puppetversion, :require => false +gem 'puppet-lint' +gem 'rspec', '~> 3.1.0', :platforms => :ruby_18 +gem 'puppetlabs_spec_helper', '>= 0.1.0' diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..57bc88a --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/Modulefile b/Modulefile new file mode 100644 index 0000000..1092e00 --- /dev/null +++ b/Modulefile @@ -0,0 +1,13 @@ +name 'puppetlabs-cloudstack' +version '0.0.1' +source 'git://github.com/puppetlabs/puppetlabs-cloudstack' +author 'puppetlabs' +license 'Apache 2.0' +summary 'CloudStack management module' +description 'Installation and configuration of all CloudStack components' +project_page 'https://github.com/puppetlabs/puppetlabs-cloudstack' + +## Add dependencies, if any: +dependency 'puppetlabs/stdlib', '>= 2.0.0' +dependency 'puppetlabs/firewall', '>= 0.0.4' +dependency 'rocha/mysql' '>= 0.1.0' diff --git a/README b/README deleted file mode 100644 index 972c6c9..0000000 --- a/README +++ /dev/null @@ -1,25 +0,0 @@ -This is the CloudStack puppet manifest. -The original location for this is: -https://gitorious.org/cloudstack-puppet - - -To the extent that this manifest is copyrightable (and that is questionable, as configurations generally aren't) it is licensed under the GPLv3 or at your option any later version. - -For problems or help, please send messages on: -https://lists.sourceforge.net/lists/listinfo/cloudstack-devel - -Test Plan: -So this should start from easiest submodules to most complex. -So I am testing in this order: - -NFS server: -(Can I successfully add primary and secondary storage to an existing cloudstack instance) - -Management Server: -Do the packages get installed properly (repos setup?) -Once installed does database get provisioned -Once database provisioned does UI come up? - -Agent: -Soooo much to test here.....basically does it work. - diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..603e7c7 --- /dev/null +++ b/README.markdown @@ -0,0 +1,5 @@ +* cloudstack-puppet + +This is the CloudStack puppet manifest. + +Original content herein licensed under the Apache 2.0 license. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..1a8a8a0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,5 @@ +require 'rubygems' +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint' +PuppetLint.configuration.send("disable_80chars") +PuppetLint.configuration.send('disable_class_parameter_defaults') diff --git a/manifests/cluster.pp b/manifests/cluster.pp new file mode 100644 index 0000000..3364709 --- /dev/null +++ b/manifests/cluster.pp @@ -0,0 +1,50 @@ +# Defined resource type: cloudstack::zone +# +# This defined type is used to identify a CloudStack zone +# +# Parameters: +# zone_dns - The external DNS server +# zone_internal_dns - Internal DNS server +# networktype - Network type to use for zone. Valid options are +# +# Actions: +# +# Requires: +# +# +# Sample Usage: +# cloudstack::zone { 'samplezone': +# zone_dns => 'myinternaldns', +# } +# +define cloudstack::cluster( + $zoneid, + $podid, + $clustertype = 'CloudManaged', + $hypervisor = $hvtype, + ) { + #### NEED TO VERIFY THAT ZONEID AND PODID ARE VALID! + $teststring_zone = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=listZones&\" + + \"available=true\" %>" ) + $teststring_pod = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=listPods&\" + + \"available=true\" %>" ) + $teststring_cluster = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=listClusters&\" + + \"available=true\" %>" ) + $reststring = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=addCluster&\" + + \"clustername=${name}&clustertype=${clustertype}&\" + + \"hypervisor=${hypervisor}&zoneid=${zoneid}&\" + + \"podid=${podid}\" %>" ) + + exec { "/usr/bin/curl \'${reststring}\'": + onlyif => [ + "/usr/bin/curl \'${teststring_zone}\' | grep ${zoneid}", + "/usr/bin/curl \'${teststring_pod}\' | grep ${podid}", + "/usr/bin/curl \'${teststring_cluster}\' | grep -v ${cluster}" + ], + require => Exec[ 'cloudstack_setup_databases' ], + } +} diff --git a/manifests/init.pp b/manifests/init.pp index 32d4027..f52a023 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,358 +1,96 @@ -class cloudstack { - include cloudstack::no_selinux - - case $operatingsystem { - centos,redhat : { - yumrepo{"Cloudstack": - baseurl => "http://yumrepo/repositories/rhel/$operatingsystemrelease/stable/oss/", - name => "CloudStack", - enable => 1, - gpgcheck => 0, - } - } - fedora : { - yumrepo{"Cloudstack": - baseurl => "http://192.168.203.177/foo/", - name => "CloudStack", - enabled => 1, - gpgcheck => 0, - } - - } - - } - file { "/etc/sudoers": - source => "puppet://puppet/cloudstack/sudoers", - mode => 440, - owner => root, - group => root, - } - - file { "/etc/hosts": - content => template("cloudstack/hosts"), - } - - package {wget: ensure => present} ### Not needed after 2.2.9, see bug 11258 -######### DEFINITIONS #################### - - $cs_mgmt_server = "192.168.203.177" - $internaldns1 = "192.168.203.1" - $dns1 = "8.8.8.8" - $cs_agent_netmask = "255.255.255.0" - $cs_sec_storage_nfs_server = "192.168.203.176" - $cs_sec_storage_mnt_point = "/secondary" - $pri_storage_nfs_server = "192.168.203.176" - $pri_storage_mnt_point = "/primary" - $hvtype = "KVM" - $system_tmplt_dl_cmd = "/usr/lib64/cloud/agent/scripts/storage/secondary/cloud-install-sys-tmplt" - $sysvm_url_kvm = "http://download.cloud.com/releases/2.2.0/systemvm.qcow2.bz2" - $sysvm_url_xen = "http://download.cloud.com/releases/2.2.0/systemvm.vhd.bz2" - - -} -class cloudstack::nfs-common { -#this subclass provides NFS for primary and secondary storage on a single machine. -#this is not production quality - but useful for a POC/demo/dev/test environment. -#you will either want to significantly alter or use your own nfs class - - include cloudstack - - package {nfs-utils: ensure => present} - - service {nfs: - ensure => running, - enable => true, - hasstatus => true, - require => [ Service[rpcbind], File["/primary"], File["/secondary"] ], - } - - service {rpcbind: - ensure => running, - enable => true, - hasstatus => true, - } - file {"/primary": - ensure => directory, - mode => 777, - } - file {"/secondary": - ensure => directory, - mode => 777, - } - file {"/etc/sysconfig/nfs": - source => "puppet://puppet/cloudstack/nfs", - notify => Service[nfs], - } - - file {"/etc/exports": - source => "puppet://puppet/cloudstack/exports", - notify => Service[nfs], - } - - iptables {"udp111": - proto => "udp", - dport=> "111", - jump => "ACCEPT", - } - - iptables {"tcp111": - proto => "tcp", - dport => "111", - jump => "ACCEPT", - } - - iptables {"tcp2049": - proto => "tcp", - dport => "2049", - jump => "ACCEPT", - } - - iptables {"tcp32803": - proto => "tcp", - dport => "32803", - jump => "ACCEPT", - } - - iptables {"udp32769": - proto => "udp", - dport => "32769", - jump => "ACCEPT", - } - - iptables {"tcp892": - proto => "tcp", - dport => "892", - jump => "ACCEPT", - } - - iptables {"udp892": - proto => "udp", - dport => "892", - jump => "ACCEPT", - } - - iptables {"tcp875": - proto => "tcp", - dport => "875", - jump => "ACCEPT", - } - - iptables {"udp875": - proto => "udp", - dport => "875", - jump => "ACCEPT", - } - - iptables {"tcp662": - proto => "tcp", - dport => "662", - jump => "ACCEPT", - } - - iptables {"udp662": - proto => "udp", - dport => "662", - jump => "ACCEPT", - } - -} - - -class cloudstack::kvmagent { - include cloudstack - package {cloud-agent : ensure => present, require => Yumrepo[CloudStack], } - - exec { "cloud-setup-agent": - creates => "/var/log/cloud/setupAgent.log", - requires => [ Package[cloud-agent], - Package[NetworkManager], - File["/etc/sudoers"], - File["/etc/cloud/agent/agent.properties"], - File["/etc/sysconfig/network-scripts/ifcfg-eth0"], - File["/etc/hosts"], - File["/etc/sysconfig/network"], - File["/etc/resolv.conf"], - Service["network"], ] - } - - - file { "/etc/cloud/agent/agent.properties": - ensure => present, - requires => Package[cloud-agent], - content => template("cloudstack/agent.properties") - } - -######## AGENT NETWORKING SECTION SEE NOTES BEFORE END OF NETWORKING SECTION ############ - - file { "/etc/sysconfig/network-scripts/ifcfg-eth0": - content => template("cloudstack/ifcfg-eth0"), - } - - - service { network: - ensure => running, - enabed => true, - hasstatus => true, ## Is that really true? - requires => [ Package[NetworkManager], File["/etc/sysconfig/network-scripts/ifcfg-eth0"], ] - } - - package { NetworkManager: - ensure => absent, - } - - file { "/etc/sysconfig/network": - content => template("cloudstack/network"), - } - - - file { "/etc/resolv.conf": - content => template("cloudstack/resolv.conf"), - } - -### NOTES: This assumes a single NIC (eth0) will be used for CloudStack and ensures that the -### config file is correct syntactically and in place -### If you wish to use more than a single NIC you will need to edit both the agent.properties -### file and add additional ifcfg-ethX files to this configuration. -### - -######### END AGENT NETWORKING ############################################################## - - -########## Also need to create a agent.properties stanza, and likely need to define -########## IP address or name for management server - and do agent.properties as a template. -############ Need to do something that will take care of IP configuration -############ Need to do something that will take care of KVM - make sure module is loaded - need to define what tests cloud-setup-agent actually runs to test for KVM and ensure that we do those tests as well, and rectify if needed (do a reboot?? ) -### Need to handle hostname addition as well - and probably a def gw and ensuring that DNS is set since -### we are so backwards as to not use DHCP - - -### IP Address thoughts: -### Use a template based on /etc/sysconfig/ifcfg-ethX -### By default only specify eth0, with liberal commenting about what to do in the event of needing to change our simple configuration (e.g. edit agent.properites, add additional network config, etc. -### Require network to be enable -### Require NetworkManager be disabled (Is it installed by default, do we need to do a case?, perhaps we 'ensure absent') -### Make sure we cycle network after deploying a ifcfg. -### Do we handle creation of cloud-br0? I am thinking not, seems like there's a lot of magic there. For now, lets stay away from that. - -} - -class cloudstack::mgmt { - include cloudstack - - - package {cloud-client : ensure => present, require => Yumrepo[CloudStack], } - - exec { "cloud-setup-management": - onlyif => [ "test -e /var/lib/mysql/cloud", - "test -e /etc/sysconfig/cloud-management", - "service cloud-management status |grep -v running" ] - #The last check won't work on systemd, need to come up with some alternative - } -########## Requires the iptables module from: http://github.com/camptocamp/puppet-iptables/ - - iptables { "http": - proto => "tcp", - dport=> "80", - jump => "ACCEPT",} - - iptables { "http-alt": - proto => "tcp", - dport=> "8080", - jump => "ACCEPT", - } - -# iptables { "port-8096": ###### this is the unauthenticated API interface - should be locked down by default. -# proto => "tcp", -# dport=> "8096", -# jump => "ACCEPT", -# } - - iptables { "port-8250": ############ Think this is for cpvm, but check for certain. - proto => "tcp", - dport=> "8250", - jump => "ACCEPT", - } - - iptables { "port-9090": ####################### find out what this does in cloudstack - proto => "tcp", - dport=> "9090", - jump => "ACCEPT", - } - - -#################### MYSQL SECTION - can likely be removed if you are using puppet in production and use your own mysql module ######### -# wondering if i should do this as a separate subclass - - package {mysql-server : ensure => present } - - service {mysqld: - name => $operatingsystem? { - default => "mysqld", - ubuntu => "mysql", - }, - ensure => running, - enable => true, - hasstatus => true, - require => Package[mysql-server], - } - file {"/etc/my.cnf": - source => "puppet://puppet/cloudstack/my.cnf", - notify => Service[mysqld], - } - - exec {"cloud-setup-databases cloud:dbpassword@localhost --deploy-as=root": - creates => "/var/lib/mysql/cloud", - } - -################## END MYSQL SECTION ################################################################################################### - -################## CloudStack configuration section #################################################################################### - -########## Zone ################ - - exec {"curl 'http://localhost:8096/?command=createZone&dns1=8.8.8.8&internaldns1=8.8.8.8&name=Zone1&networktype=Basic'": - onlyif => "curl 'http://localhost:8096/?command=listZones&available=true' | grep -v Zone1" - } - -########## Pod ################# - - exec {"curl 'http://localhost:8096?command=createPod&gateway=192.168.203.1&name=Pod1&netmask=255.255.255.0&startip=192.168.203.200&zoneid=4&endip=192.168.203.230'": - onlyif => ["curl 'http://localhost:8096/?command=listZones&available=true' | grep Zone1", - "curl 'http://localhost:8096/?command=listPods' | grep -v Pod1", ] - } - -########## Cluster ############## - - exec {"curl 'http://localhost:8096?command=addCluster&clustername=Cluster1&clustertype=CloudManaged&hypervisor=${hvtype}&zoneid=4&podid=1'": - onlyif => ["curl 'http://localhost:8096/?command=listZones&available=true' | grep Zone1", - "curl 'http://localhost:8096/?command=listPods' | grep Pod1", - "curl 'http://localhost:8096/?command=listClusters' | grep -v Cluster1" ], - } - -########## SecStorage ############ -## NOTE: This will take a LONG time to run. Go get a cup of coffee - exec { "mount ${cloudstack::cs_sec_storage_nfs_server}:${cloudstack::cs_sec_storage_mnt_point} /mnt ; - ${cloudstack::system_tmplt_dl_cmd} -m /mnt -u ${cloudstack::sysvm_url_kvm} -h kvm -F ; - curl 'http://localhost:8096/?command=addSecondaryStorage&url=nfs://${cloudstack::cs_sec_storage_nfs_server}${cloudstack::cs_sec_storage_mnt_point}&zoneid=1' ; - touch /var/lib/cloud/ssvm": - onlyif => ["test ! -e /var/lib/cloud/ssvm", "curl 'http://localhost:8096/?command=listZones&available=true' | grep Zone1",] - } - -########## Primary Storage ######## -### THis needs to add a check for a host to have been added - exec { "curl 'http://localhost:8096/?command=createStoragePool&name=PStorage&url=nfs://${cloudstack::pri_storage_nfs_server}${cloudstack::pri_storage_mnt_point}&zoneid=4&podid=1'": - onlyif => ["curl 'http://localhost:8096/?command=listPods' | grep Pod1", - "curl 'http://localhost:8096/?command=listStoragePools' | grep -v PStorage", ] - } - - -} - -class cloudstack::no_selinux { - file { "/etc/selinux/config": - source => "puppet://puppet/cloudstack/config", - } - exec { "/usr/sbin/setenforce 0": - onlyif => "/usr/sbin/getenforce | grep Enforcing", - } +# Class: cloudstack +# +# This class installs the base CloudStack components +# +# Parameters: +# +# Actions: +# Install the CloudStack repository: [cloudstack] +# Manage sudoers entry for cloud user +# Manage hosts file +# Turn off selinux +# Ensure wget installed +# +# Requires: +# +# Package[ 'sudo' ] + +# Sample Usage: +# This class should not be included directly. It is called from other modules. +# +class cloudstack( + + $mgmt_port = $cloudstack::params::mgmt_port, + $cs_mgmt_server = $cloudstack::params::cs_mgmt_server, + $cs_agent_netmask = $cloudstack::params::cs_agent_netmask, + $cs_sec_storage_nfs_server = $cloudstack::params::cs_sec_storage_nfs_server, + $cs_sec_storage_mnt_point = $cloudstack::params::cs_sec_storage_mnt_point, + $pri_storage_nfs_server = $cloudstack::params::pri_storage_nfs_server, + $pri_storage_mnt_point = $cloudstack::params::pri_storage_mnt_point, + $hvtype = $cloudstack::params::hvtype, + $system_tmplt_dl_cmd = $cloudstack::params::system_tmplt_dl_cmd, + $sysvm_url_kvm = $cloudstack::params::sysvm_url_kvm, + $sysvm_url_xen = $cloudstack::params::sysvm_url_xen, + + +) inherits cloudstack::params { + + + resources { 'host': + name => 'host', + purge => true, + } + + + yumrepo{ 'cloudstack': + descr => 'Cloudstack repo 4.5', + baseurl => 'http://cloudstack.apt-get.eu/rhel/4.5/', + enabled => '1', + gpgcheck => '0', + } + + file_line { 'cs_sudo_rule': + path => '/etc/sudoers', + line => 'cloud ALL = NOPASSWD : ALL', + } + file_line { 'cloud tty': + path => '/etc/sudoers', + line => 'Defaults:cloud !requiretty', + } + + host { 'localhost': + ensure => present, + ip => '127.0.0.1', + host_aliases => [ $::fqdn, 'localhost.localdomain', $::hostname ], + } + + package { 'wget': ensure => present } # Not needed after 2.2.9, see bug 11258 + + file { '/etc/selinux/config': + source => 'puppet:///modules/cloudstack/config', + } + + exec { 'disable_selinux': + command => '/usr/sbin/setenforce 0', + onlyif => '/usr/sbin/getenforce | grep Enforcing', + } + + + +################ base firewall ############################ +# + + firewall { '001 allow icmp': + proto => 'icmp', + action => 'accept', + } + firewall { '002 allow all to lo interface': + iniface => 'lo', + action => 'accept', + } + + firewall { '003 allow ssh': + dport => '22', + proto => 'tcp', + } } diff --git a/manifests/kvmagent.pp b/manifests/kvmagent.pp new file mode 100644 index 0000000..7b62d0d --- /dev/null +++ b/manifests/kvmagent.pp @@ -0,0 +1,84 @@ +# Class: cloudstack::kvmagent +# +# This class installs the base CloudStack KVM agent +# +# Parameters: +# +# Actions: +# Install base cloudstack agent +# Install Package['cloud-agent'] +# Run script Exec['cloud-setup-agent'] +# +# Requires: +# +# Sample Usage: +# +class cloudstack::kvmagent { + + package { 'cloudstack-agent': + ensure => present, + require => Yumrepo[ 'cloudstack' ], + } + + package { 'NetworkManager': + ensure => absent; + } + + service { 'network': + ensure => running, + hasstatus => true, + require => Package[ 'cloudstack-agent' ], + } + + # Needs params + #exec { '/usr/bin/cloudstack-setup-agent': + # creates => '/var/log/cloud/setupAgent.log', + # require => [ + # Package[ 'cloudstack-agent' ], + # File[ '/etc/cloudstack/agent/agent.properties' ], + # File_line[ 'cs_sudo_rule' ], + # Host[ 'localhost' ], + # ], + #} + + + file { '/etc/cloudstack/agent/agent.properties': + ensure => present, + require => Package[ 'cloudstack-agent' ], + content => template( 'cloudstack/agent.properties' ), + } + +################## Firewall stuff ######################### +# + + firewall { '001 first range ': + proto => 'tcp', + dport => '49152-49216', + action => 'accept', + } + + firewall { '191 VNC rules': + proto => 'tcp', + dport => '5900-6100', + action => 'accept', + } + + firewall { '192 port 16509': + proto => 'tcp', + dport => '16509', + action => 'accept', + } + +# Need to do something that will take care of KVM - make sure module is loaded +# - need to define what tests cloud-setup-agent actually runs to test for KVM +# and ensure that we do those tests as well, and rectify if needed (reboot?? ) +# Need to handle hostname addition as well +#- and probably a def gw and ensuring that DNS is set since + + +### Require network to be enable +### Require NetworkManager be disabled (Is it installed by default, do we need to do a case?, perhaps we 'ensure absent') +### Make sure we cycle network after deploying a ifcfg. +### Do we handle creation of cloud-br0? I am thinking not, seems like there's a lot of magic there. For now, lets stay away from that. + +} diff --git a/manifests/mgmt.pp b/manifests/mgmt.pp new file mode 100644 index 0000000..243638c --- /dev/null +++ b/manifests/mgmt.pp @@ -0,0 +1,148 @@ +# Class: cloudstack::mgmt +# +# This class builds the CloudStack management node +# +# Parameters: +# +# Actions: +# Install the cloud-client package +# Install cloud database only if MySQL is installed and configured +# Run cloud-setup-management script +# Open appropriate iptables ports +# +# Requires: +# +# Package[ 'sudo' ] + +# Sample Usage: +# This class should not be included directly. It is called from other modules. +# +class cloudstack::mgmt { + +# include mysql::server # +## We really want to specify this - but in the absence of this + +########### MYSQL section ######### + package { 'mysql-server': + ensure => present, + } + + service { 'mysqld': + ensure => running, + enable => true, + hasstatus => true, + require => Package[ 'mysql-server' ], + } + +######### END MYSQL ##################################### + + $dbstring = inline_template( "<%= \"/usr/bin/cloudstack-setup-databases \" + + \"cloud:dbpassword@localhost --deploy-as=root\" %>" ) +# If you are using a separate database or different passwords, change it above + + + package { 'cloudstack-management': + ensure => present, + require => Yumrepo[ 'cloudstack' ], + } + + service { 'cloudstack-management': + ensure => running, + enable => true, + hasstatus => true, + require => [Package[ 'cloudstack-management' ], Service[ 'mysqld' ], File[ '/etc/cloudstack/management/tomcat6.conf' ], File[ '/usr/share/cloudstack-management/conf/server.xml' ] ], + } + + exec { '/usr/bin/cloudstack-setup-management': + unless => [ '/usr/bin/test -e /etc/sysconfig/cloudstack-management' ], + require => [ Service[ 'cloudstack-management' ], + Exec[ 'cloudstack_setup_databases' ] ], + } + + exec { 'cloudstack_setup_databases': + command => $dbstring, + creates => '/var/lib/mysql/cloud', + require => [Package[ 'cloudstack-management' ], Service[ 'mysqld' ] ], + } + + + ###################################################### + ############## tomcat section ######################## + ###################################################### + + + file { '/etc/cloudstack/management/tomcat6.conf': + ensure => 'link', + group => '0', + mode => '0777', + owner => '0', + target => 'tomcat6-nonssl.conf', + require => Package[ 'cloudstack-management' ], + } + + file { '/usr/share/cloudstack-management/conf/server.xml': + ensure => 'link', + group => '0', + mode => '0777', + owner => '0', + target => 'server-nonssl.xml', + require => Package[ 'cloudstack-management' ], + } + + +###################################################### +############ firewall section ######################## +###################################################### + + + firewall { '003 allow port 80 in': + proto => 'tcp', + dport => '80', + action => 'accept', + } + + + firewall { '120 permit 8080 - web interface': + proto => 'tcp', + dport => '8080', + action => 'accept', + } + +###### this is the unauthed API interface - should be locked down by default. +# firewall { '130 permit unauthed API': +# proto => 'tcp', +# dport => '8096', +# jump => 'accept', +# } +# + + firewall { '8250 CPVM': #### Think this is for cpvm, but check for certain. + proto => 'tcp', + dport => '8250', + action => 'accept', + } + + firewall { '9090 unk port': ######## find out what this does in cloudstack + proto => 'tcp', + dport => '9090', + action => 'accept', + } + + +} +########## SecStorage ############ +## NOTE: This will take a LONG time to run. Go get a cup of coffee +# exec { 'mount ${cloudstack::cs_sec_storage_nfs_server}:${cloudstack::cs_sec_storage_mnt_point} /mnt ; +# ${cloudstack::system_tmplt_dl_cmd} -m /mnt -u ${cloudstack::sysvm_url_kvm} -h kvm -F ; +# curl 'http://localhost:8096/?command=addSecondaryStorage&url=nfs://${cloudstack::cs_sec_storage_nfs_server}${cloudstack::cs_sec_storage_mnt_point}&zoneid=1' ; +# touch /var/lib/cloud/ssvm': +# onlyif => [ 'test ! -e /var/lib/cloud/ssvm', 'curl 'http://localhost:8096/?command=listZones&available=true' | grep Zone1',] +# } + +########## Primary Storage ######## +### THis needs to add a check for a host to have been added +# exec { 'curl 'http://localhost:8096/?command=createStoragePool&name=PStorage&url=nfs://${cloudstack::pri_storage_nfs_server}${cloudstack::pri_storage_mnt_point}&zoneid=4&podid=1'': +# onlyif => ['curl 'http://localhost:8096/?command=listPods' | grep Pod1', +# 'curl 'http://localhost:8096/?command=listStoragePools' | grep -v PStorage', +# ] +# } diff --git a/manifests/nfs_common.pp b/manifests/nfs_common.pp new file mode 100644 index 0000000..a438b11 --- /dev/null +++ b/manifests/nfs_common.pp @@ -0,0 +1,110 @@ +# Class: cloudstack::nfs_common +# +# this subclass provides NFS for primary and secondary storage +# on a single machine. this is not production quality - but useful +# for a POC/demo/dev/test environment. +# you will either want to significantly alter or use your own nfs class +class cloudstack::nfs_common { + + + package {'nfs-utils': + ensure => present + } + + service {'nfs': + ensure => running, + enable => true, + hasstatus => true, + require => [ Service[rpcbind], File['/primary'], File['/secondary'] ], + } + + service {'rpcbind': + ensure => running, + enable => true, + hasstatus => true, + } + file {'/primary': + ensure => directory, + mode => '0777', + } + file {'/secondary': + ensure => directory, + mode => '0777', + } + file {'/etc/sysconfig/nfs': + source => 'puppet:///modules/cloudstack/nfs', + notify => Service[nfs], + } + + file {'/etc/exports': + source => 'puppet:///modules/cloudstack/exports', + notify => Service[nfs], + } + + firewall {'111 udp': + proto => 'udp', + dport => '111', + action => 'accept', + } + + firewall {'111 tcp': + proto => 'tcp', + dport => '111', + action => 'accept', + } + + firewall {'2049 tcp': + proto => 'tcp', + dport => '2049', + action => 'accept', + } + + firewall {'32803 tcp': + proto => 'tcp', + dport => '32803', + action => 'accept', + } + + firewall {'32769 udp': + proto => 'udp', + dport => '32769', + action => 'accept', + } + + firewall {'892 tcp': + proto => 'tcp', + dport => '892', + action => 'accept', + } + + firewall {'892 udp': + proto => 'udp', + dport => '892', + action => 'accept', + } + + firewall {'875 tcp': + proto => 'tcp', + dport => '875', + action => 'accept', + } + + firewall {'875 udp': + proto => 'udp', + dport => '875', + action => 'accept', + } + + firewall {'662 tcp': + proto => 'tcp', + dport => '662', + action => 'accept', + } + + firewall {'662 udp': + proto => 'udp', + dport => '662', + action => 'accept', + } + +} diff --git a/manifests/params.pp b/manifests/params.pp new file mode 100644 index 0000000..6e439dc --- /dev/null +++ b/manifests/params.pp @@ -0,0 +1,16 @@ +# Class:: cloudstack::params +# +# +class cloudstack::params { + $mgmt_port = '8096' + $cs_mgmt_server = '192.168.203.177' + $cs_agent_netmask = '255.255.255.0' + $cs_sec_storage_nfs_server = '192.168.203.177' + $cs_sec_storage_mnt_point = '/secondary' + $pri_storage_nfs_server = '192.168.203.177' + $pri_storage_mnt_point = '/primary' + $hvtype = 'KVM' + $system_tmplt_dl_cmd = '/usr/lib64/cloud/agent/scripts/storage/secondary/cloud-install-sys-tmplt' + $sysvm_url_kvm = 'http://cloudstack.apt-get.eu/systemvm/4.5/systemvm64template-4.5-kvm.qcow2.bz2' + $sysvm_url_xen = 'http://cloudstack.apt-get.eu/systemvm/4.5/systemvm64template-4.5-xen.vhd.bz2' +} # Class:: cloudstack::params diff --git a/manifests/pod.pp b/manifests/pod.pp new file mode 100644 index 0000000..d934834 --- /dev/null +++ b/manifests/pod.pp @@ -0,0 +1,45 @@ +# Defined resource type: cloudstack::zone +# +# This defined type is used to identify a CloudStack zone +# +# Parameters: +# zone_dns - The external DNS server +# zone_internal_dns - Internal DNS server +# networktype - Network type to use for zone. Valid options are +# +# Actions: +# +# Requires: +# +# +# Sample Usage: +# cloudstack::zone { 'samplezone': +# zone_dns => 'myinternaldns', +# } +# +define cloudstack::pod( + $gateway, + $netmask, + $startip, + $endip, + $zoneid + ) { + $teststring_zone = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=listZones&\" + + \"available=true\" %>" ) + $teststring_pod = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=listPods&\" + + \"available=true\" %>" ) + $reststring = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=createPod&\" + + \"gateway=${gateway}&name=${name}&netmask=${netmask}&\" + + \"startip=${startip}&endip=${endip}&zoneid=${zoneid}\" %>" ) + + exec { "/usr/bin/curl \'${reststring}\'": + unless => [ + "/usr/bin/curl \'${teststring_zone}\' | grep ${zoneid}", + "/usr/bin/curl \'${teststring_pod}\' | grep -v ${pod}", + ], + require => Exec[ 'cloudstack_setup_databases' ], + } +} diff --git a/manifests/zone.pp b/manifests/zone.pp new file mode 100644 index 0000000..394e8c5 --- /dev/null +++ b/manifests/zone.pp @@ -0,0 +1,37 @@ +# Defined resource type: cloudstack::zone +# +# This defined type is used to identify a CloudStack zone +# +# Parameters: +# zone_dns - The external DNS server +# zone_internal_dns - Internal DNS server +# networktype - Network type to use for zone. Valid options are +# +# Actions: +# +# Requires: +# +# +# Sample Usage: +# cloudstack::zone { 'samplezone': +# zone_dns => 'myinternaldns', +# } +# +define cloudstack::zone( + $zone_dns='8.8.8.8', + $zone_internal_dns='8.8.8.8', + $networktype='Basic' + ) { + $teststring = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=listZones&\" + + \"available=true\" %>" ) + $reststring = inline_template( "<%= \"http://localhost:\" + + \"${cloudstack::params::mgmt_port}/?command=createZone&dns1\" + + \"=${zone_internal_dns}&internaldns1=${zone_internal_dns}\" + + \"&name=${name}&networktype=${networktype}\" %>" ) + + exec { "/usr/bin/curl \'${reststring}\'": + onlyif => "/usr/bin/curl \'${teststring}\' | grep -v ${name}", + require => Exec[ 'cloudstack_setup_databases' ], + } +} diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb new file mode 100644 index 0000000..021e37e --- /dev/null +++ b/spec/classes/init_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe 'cloudstack' do + let(:node) { 'cloudstack.example42.com' } + let(:facts) {{ + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '12.10' + }} + + describe 'generic test' do + it { should compile } + it { should contain_class('cloudstack') } + end +end diff --git a/spec/classes/kvmagent_spec.rb b/spec/classes/kvmagent_spec.rb new file mode 100644 index 0000000..6eb0cb4 --- /dev/null +++ b/spec/classes/kvmagent_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe 'cloudstack::kvmagent' do + let(:node) { 'cloudstack.example42.com' } + let(:pre_condition) { 'include cloudstack' } + let(:facts) {{ + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '12.10' + }} + + describe 'generic test' do + it { should compile } + it { should contain_class('cloudstack::kvmagent') } + end +end diff --git a/spec/classes/mgmt_spec.rb b/spec/classes/mgmt_spec.rb new file mode 100644 index 0000000..ad2d825 --- /dev/null +++ b/spec/classes/mgmt_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe 'cloudstack::mgmt' do + let(:node) { 'cloudstack.example42.com' } + let(:pre_condition) { 'include cloudstack' } + let(:facts) {{ + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '12.10' + }} + + describe 'generic test' do + it { should compile } + it { should contain_class('cloudstack::mgmt') } + end +end diff --git a/spec/classes/nfs_common_spec.rb b/spec/classes/nfs_common_spec.rb new file mode 100644 index 0000000..bfe6d53 --- /dev/null +++ b/spec/classes/nfs_common_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe 'cloudstack::nfs_common' do + let(:node) { 'cloudstack.example42.com' } + let(:facts) {{ + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '12.10' + }} + + describe 'generic test' do + it { should compile } + it { should contain_class('cloudstack::nfs_common') } + end +end diff --git a/spec/defines/cluster_spec.rb b/spec/defines/cluster_spec.rb new file mode 100644 index 0000000..0ce665d --- /dev/null +++ b/spec/defines/cluster_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe 'cloudstack::cluster', :type => :define do + let(:title) { 'example42' } + let(:facts) {{ + :osfamily => 'RedHat', + :operatingsystem => 'CentOS' + }} + let(:params) {{ + :zoneid => 'cloudstack', + :podid => 'example42' + }} + let(:pre_condition) {[ + 'include cloudstack', + 'include cloudstack::mgmt', + ]} + it { should compile } +end diff --git a/spec/defines/pod_spec.rb b/spec/defines/pod_spec.rb new file mode 100644 index 0000000..e88c31e --- /dev/null +++ b/spec/defines/pod_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe 'cloudstack::pod', :type => :define do + let(:title) { 'example42' } + let(:facts) {{ + :osfamily => 'RedHat', + :operatingsystem => 'CentOS' + }} + let(:params) {{ + :gateway => '127.0.0.1', + :netmask => '255.255.0.0', + :startip => '10.0.2.0', + :endip => '10.2.0.3', + :zoneid => 'example42' + }} + let(:pre_condition) {[ + 'include cloudstack', + 'include cloudstack::mgmt' + ]} + it { should compile } +end diff --git a/spec/defines/zone_spec.rb b/spec/defines/zone_spec.rb new file mode 100644 index 0000000..fc5f3ba --- /dev/null +++ b/spec/defines/zone_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +describe 'cloudstack::zone', :type => :define do + let(:title) { 'example42' } + let(:facts) {{ + :osfamily => 'RedHat', + :operatingsystem => 'CentOS' + }} + let(:pre_condition) {[ + 'include cloudstack', + 'include cloudstack::mgmt' + ]} + it { should compile } +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..2c6f566 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1 @@ +require 'puppetlabs_spec_helper/module_spec_helper' diff --git a/tests/init.pp b/tests/init.pp new file mode 100644 index 0000000..5407152 --- /dev/null +++ b/tests/init.pp @@ -0,0 +1,18 @@ +include cloudstack::mgmt + +cloudstack::zone { 'zone1': } -> + +cloudstack::pod { 'pod1': + gateway => '192.168.203.1', + netmask => '255.255.255.0', + startip => '192.168.203.200', + endip => '192.168.203.230', + zoneid => '1', +} + +cloudstack::cluster { 'cluster1': + clustertype => 'CloudManaged', + hypervisor => $hvtype, + zoneid => '1', + podid => '1', +}