├── .gitignore ├── .gitreview ├── CONTRIBUTING.rst ├── LICENSE.md ├── README.md ├── Vagrantfile ├── config.yaml.sample ├── puppet ├── manifests │ ├── cleanup.pp │ └── default.pp └── modules │ ├── base │ ├── files │ │ └── git_clone.sh │ └── manifests │ │ └── init.pp │ ├── devstack │ ├── files │ │ └── local.sh │ ├── manifests │ │ └── init.pp │ └── templates │ │ └── local.erb │ ├── grenade │ └── manifests │ │ └── init.pp │ └── user │ ├── files │ ├── stack_bashrc │ └── stack_sudoers │ └── manifests │ ├── create.pp │ ├── stack.pp │ └── vagrant.pp └── tools └── vagrant_package.sh /.gitignore: -------------------------------------------------------------------------------- 1 | local_config.rb 2 | config.yaml 3 | .vagrant 4 | .#* 5 | #* 6 | *.box -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=review.opendev.org 3 | port=29418 4 | project=openstack/devstack-vagrant.git 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | The source repository for this project can be found at: 2 | 3 | https://opendev.org/openstack/devstack-vagrant 4 | 5 | Pull requests submitted through GitHub are not monitored. 6 | 7 | To start contributing to OpenStack, follow the steps in the contribution guide 8 | to set up and use Gerrit: 9 | 10 | https://docs.openstack.org/contributors/code-and-documentation/quick-start.html 11 | 12 | Bugs should be filed on Launchpad: 13 | 14 | https://bugs.launchpad.net/devstack 15 | 16 | For more specific information about contributing to this repository, see the 17 | Devstack contributor guide: 18 | 19 | https://docs.openstack.org/devstack/latest/contributor/contributing.html 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | devstack-vagrant 2 | ================ 3 | 4 | This is an attempt to build an easy to use tool to bring up a 2 node 5 | devstack environment for local testing using Vagrant + Puppet. 6 | 7 | It is *almost* fully generic, but still hard codes a few things about 8 | my environment for lack of a way to figure out how to do this 9 | completely generically (puppet templates currently hate me under 10 | vagrant). 11 | 12 | This will build a vagrant cluster that is L2 bridged to the interface 13 | that you specify in ``config.yaml``. All devstack guests (2nd 14 | level) will also be L2 bridged to that network as well. That means 15 | that once you bring up this environment you will be able to ssh 16 | stack@api (or whatever your hostname is) from any machines on your 17 | network. 18 | 19 | Vagrant Setup 20 | ------------------------ 21 | 22 | Install vagrant & virtual box 23 | 24 | Configure a base ``~/.vagrant.d/Vagrantfile`` to set your VM size. If you 25 | have enough horsepower you should make the file something like: 26 | 27 | VAGRANTFILE_API_VERSION = "2" 28 | 29 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 30 | config.vm.provider :virtualbox do |vb| 31 | 32 | # Use VBoxManage to customize the VM. For example to change memory: 33 | vb.customize ["modifyvm", :id, "--memory", "8192"] 34 | vb.customize ["modifyvm", :id, "--cpus", "4"] 35 | end 36 | end 37 | 38 | You can probably get away with less cpus, and 4096 MB of memory, but 39 | the above is recommended size. 40 | 41 | If the used hostnames in the ``config.yaml`` file (variable ``hostname_manager`` 42 | and ``hostname_compute``) are not resolvable you have to install the 43 | ``vagrant-hostmanager`` plugin (``vagrant plugin install vagrant-hostmanager``). 44 | 45 | If the nodes are still not able to communicate to each other even after 46 | installing the ``vagrant-hostnamanger`` plugin (for example you get errors about 47 | the compute node not being able to communicate to *cinder c-api* during the 48 | *vagrant up* phase), set the variable ``use_ip_resolver`` in the ``config.yaml`` 49 | file to ``true``, in order to obtain the correct nodes ip. 50 | 51 | 52 | Local Setup 53 | -------------------- 54 | Copy ``config.yaml.sample`` to ``config.yaml`` and provide the 55 | hostnames you want, and password, and sshkey for 56 | the stack user. 57 | 58 | Then run vagrant up. 59 | 60 | On a 32 GB Ram, 4 core i7 haswell, on an SSD, with Fios, this takes 61 | 25 - 30 minutes. So it's not quick. However it is repeatable. 62 | 63 | If you want to speed-up the process, install the 64 | [vagrant-cachier](https://github.com/fgrehm/vagrant-cachier) plugin in order 65 | to let vagrant cache files, such as apt packages, with: 66 | 67 | vagrant plugin install vagrant-cachier 68 | 69 | 70 | What you should get 71 | ----------------------------------- 72 | A 2 node devstack that includes cirros mini cloud image populated in glance. 73 | You can get other images population such as fedora 20, ubuntu 12.04, 74 | and ubuntu 14.04, just with a small addtion to ``extra_images`` part 75 | in ``config.yaml.sample``. 76 | 77 | Default security group with ssh and ping opened up. 78 | 79 | Installation of the stack user ssh key as the default keypair. 80 | 81 | Enable additional services 82 | ------------------------ 83 | The devstack environment created by this `Vagrantfile` includes just the basic 84 | services to get started with OpenStack. If you want to try more services, you 85 | can enable them on the manager node through the ``config.yaml`` file. 86 | 87 | For example if you want to enable 88 | [Swift](https://docs.openstack.org/developer/swift), you can add the 89 | following line to your ``config.yaml``: 90 | 91 | manager_extra_services: s-proxy s-object s-container s-account 92 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 5 | VAGRANTFILE_API_VERSION = "2" if not defined? VAGRANTFILE_API_VERSION 6 | 7 | require 'yaml' 8 | if File.file?('config.yaml') 9 | conf = YAML.load_file('config.yaml') 10 | else 11 | raise "Configuration file 'config.yaml' does not exist." 12 | end 13 | 14 | $add_manager_to_hosts= <> /etc/hosts 18 | fi 19 | SETHOSTS 20 | $git_use_https= < $add_manager_to_hosts 34 | else 35 | vm.network :private_network, type: "dhcp" 36 | end 37 | else 38 | # we do an L2 bridge directly onto the physical network, which means 39 | # that your OpenStack hosts (manager, compute) are directly in the 40 | # same network as your physical host. Your OpenStack guests (2nd 41 | # level guests that you create in nova) will be also on the same L2, 42 | # however they will be in a different address space (10.0.0.0/24 by 43 | # default). 44 | # 45 | # :use_dhcp_assigned_default_route true is important to let your 46 | # guests actually route all the way out to the real internet. 47 | vm.network :public_network, :bridge => conf['bridge_int'], :use_dhcp_assigned_default_route => true 48 | end 49 | 50 | vm.provider :virtualbox do |vb| 51 | # you need this for openstack guests to talk to each other 52 | vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"] 53 | # if specified assign a static MAC address 54 | if conf["mac_address_#{name}"] 55 | vb.customize ["modifyvm", :id, "--macaddress2", conf["mac_address_#{name}"]] 56 | end 57 | end 58 | 59 | # puppet not installed by default in ubuntu-xenial 60 | vm.provision "shell", inline: "sudo apt-get update" 61 | vm.provision "shell", inline: "sudo apt-get install -y puppet" 62 | 63 | # puppet provisioning 64 | vm.provision "puppet" do |puppet| 65 | puppet.manifests_path = "puppet/manifests" 66 | puppet.module_path = "puppet/modules" 67 | puppet.manifest_file = "default.pp" 68 | puppet.options = "--verbose --debug" 69 | ## custom facts provided to Puppet 70 | puppet.facter = { 71 | ## tells default.pp that we're running in Vagrant 72 | "is_vagrant" => true, 73 | "is_compute" => (name != "manager"), 74 | "use_ldap" => conf["use_ldap"] || false, 75 | "extra_images" => conf["extra_images"] || "", 76 | "guest_interface_default" => conf["guest_interface_default"] || "enp0s8", 77 | "host_ip_iface" => conf["host_ip_iface"] || "enp0s8", 78 | "vagrant_username" => conf["vagrant_username"] || "ubuntu", 79 | "ip_version" => conf["ip_version"] || "4", 80 | } 81 | # add all the rest of the content in the conf file 82 | conf.each do |k, v| 83 | puppet.facter[k] = v 84 | end 85 | end 86 | 87 | if conf['setup_mode'] == "devstack" 88 | vm.provision "shell" do |shell| 89 | shell.inline = "sudo su - stack -c 'cd ~/devstack && ./stack.sh'" 90 | end 91 | end 92 | 93 | if conf['setup_mode'] == "grenade" 94 | vm.provision "shell" do |shell| 95 | shell.inline = "sudo su - stack -c 'cd ~/grenade && ./grenade.sh'" 96 | end 97 | end 98 | 99 | end 100 | 101 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 102 | # All Vagrant configuration is done here. The most common configuration 103 | # options are documented and commented below. For a complete reference, 104 | # please see the online documentation at vagrantup.com. 105 | 106 | # Step 1: what's you base box that you are going to use 107 | # 108 | # - if you specify a local box_name on your system, we'll use that 109 | # - else we're going to use an upstream box from the cloud at 14.04 level 110 | # - lastly, let you override the url in case you have something cached locally 111 | # 112 | # The boot time is long for these, so I recommend that you convert to a local 113 | # version as soon as you can. 114 | config.vm.box = conf['box_name'] || 'ubuntu/bionic64' 115 | config.vm.box_url = conf['box_url'] if conf['box_url'] 116 | 117 | if Vagrant.has_plugin?("vagrant-cachier") 118 | config.cache.scope = :box 119 | # see https://github.com/fgrehm/vagrant-cachier/issues/175 120 | config.cache.synced_folder_opts = { 121 | owner: "_apt", 122 | group: "ubuntu", 123 | mount_options: ["dmode=777", "fmode=666"] 124 | } 125 | end 126 | 127 | if Vagrant.has_plugin?("vagrant-proxyconf") && conf['proxy'] 128 | config.proxy.http = conf['proxy'] 129 | config.proxy.https = conf['proxy'] 130 | config.proxy.no_proxy = "localhost,127.0.0.1,`facter ipaddress_eth1`,#{conf['hostname_manager']},#{conf['hostname_compute']},#{conf['ip_address_compute']},#{conf['ip_address_manager']},#{conf['user_domains']}" 131 | config.vm.provision :shell, :inline => $git_use_https 132 | end 133 | 134 | # NOTE(berendt): This solves the Ubuntu-specific Vagrant issue 1673. 135 | # https://github.com/mitchellh/vagrant/issues/1673 136 | config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'" 137 | 138 | if Vagrant.has_plugin?("vagrant-hostmanager") 139 | config.hostmanager.enabled = true 140 | config.hostmanager.manage_host = true 141 | config.hostmanager.ignore_private_ip = false 142 | config.hostmanager.include_offline = true 143 | if conf["use_bridge"] == false || conf["use_ip_resolver"] == true 144 | config.hostmanager.ip_resolver = proc do |machine| 145 | result = "" 146 | begin 147 | machine.communicate.execute("ifconfig eth1") do |type, data| 148 | result << data if type == :stdout 149 | end 150 | # NOTE(jerryz): This catches the exception when host is still 151 | # not ssh reachable. 152 | # https://github.com/smdahlen/vagrant-hostmanager/issues/121 153 | rescue 154 | result = "# NOT-UP" 155 | end 156 | (ip = /inet addr:(\d+\.\d+\.\d+\.\d+)/.match(result)) && ip[1] 157 | end 158 | end 159 | end 160 | 161 | config.vm.define "manager", primary: true do |manager| 162 | configure_vm("manager", manager.vm, conf) 163 | manager.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" 164 | manager.vm.network "forwarded_port", guest: 6080, host: 6080, host_ip: "127.0.0.1" 165 | end 166 | 167 | if conf['hostname_compute'] 168 | config.vm.define "compute" do |compute| 169 | configure_vm("compute", compute.vm, conf) 170 | end 171 | end 172 | 173 | # If true, then any SSH connections made will enable agent forwarding. 174 | # Default value: false 175 | config.ssh.forward_agent = true 176 | 177 | # Share an additional folder to the guest VM. The first argument is 178 | # the path on the host to the actual folder. The second argument is 179 | # the path on the guest to mount the folder. And the optional third 180 | # argument is a set of non-required options. 181 | # config.vm.synced_folder "../data", "/vagrant_data" 182 | if conf['local_openstack_tree'] 183 | config.vm.synced_folder conf['local_openstack_tree'], "/home/vagrant/openstack" 184 | end 185 | 186 | end 187 | -------------------------------------------------------------------------------- /config.yaml.sample: -------------------------------------------------------------------------------- 1 | # Hostname of the manager and the compute nodes. 2 | hostname_manager: manager.openstack.site 3 | hostname_compute: compute.openstack.site 4 | 5 | # The domain names and ips to add in the no_proxy variable (comma separated) 6 | user_domains: .mycompany.com,10.20.30.40 7 | 8 | # The password that should be used for the system user 'stack'. 9 | stack_password: secretsecret 10 | 11 | # The password that should be used for services like the database or queuing. 12 | service_password: secretsecret 13 | 14 | # The password that should be used for the OpenStack admin user. 15 | admin_password: secretsecret 16 | 17 | # The public SSH key that should be used for the system user 'stack' (only the base64 encoded part). 18 | stack_sshkey: the_ssh_public_key_you_want_for_your_stack_user 19 | 20 | # Define the setup mode to install the environment. 21 | # valid values: grenade, devstack 22 | # default value: devstack 23 | setup_mode: devstack 24 | 25 | # What interface on the host should be used for a bridge will often be eth0, 26 | # but vagrant needs to know for sure. This needs to be the full string 27 | # descriptor of the interface. On some systems this can be something annoying 28 | # like 'en1: Wi-Fi (Airport)'. Vagrant will not use this setting unless you get 29 | # it exactly right. 30 | bridge_int: eth1 31 | 32 | # Enable the vagrant-hostmanager's ip_resolver in order to get the correct 33 | # nodes ip. You should install the vagrant-hostmanager plugin and enable this 34 | # option if the nodes are not able to communicate (for example you get errors 35 | # during the compute vagrant up phase not being able to communicate to c-api). 36 | #use_ip_resolver: true 37 | 38 | # A non upstream for the base box, used to speed things up. Choose one of 39 | # box_name (for a locally added box) or box_url for the url of a nearby box. 40 | #box_name: 'my.favorite' 41 | #box_url: http://gallifrey/vagrant/devstack-2014-02-19.box 42 | 43 | # Vagrant username used in box image, e.g. ubuntu 44 | #vagrant_username: vagrant 45 | 46 | # Non upstream Git URL to fetch Devstack from instead. 47 | #devstack_git: /home/vagrant/openstack/devstack 48 | 49 | # If you have code on a different branch than master, you can set it here. 50 | #devstack_branch: compute_err_exit 51 | 52 | # You can specify a proxy, for example https://github.com/tmatilai/polipo-box, 53 | # to be used for HTTP connections to speed things up. 54 | #proxy: http://10.0.10.30:8123/ 55 | 56 | # Uncomment below to setup LDAP on the management node and use it as backend 57 | # for keystone. 58 | #use_ldap: true 59 | 60 | # You can specify stable MAC addresses to keep this from resetting on every 61 | # create. 62 | #mac_address_manager: 0800274a508c 63 | #mac_address_compute: 0800274a508d 64 | 65 | # It is possible to use a hostonly-network instead of a bridged network when 66 | # setting the parameter use_bridge to false. 67 | #use_bridge: false 68 | 69 | # When using a hostonly-network it is possible to specify static IP addresses 70 | # using the following parameters. If those parameters are not specified DHCP 71 | # will be used. 72 | #ip_address_manager: 10.0.10.10 73 | #ip_address_compute: 10.0.10.20 74 | 75 | # Name of network interface in virtual machine - e.g. enp0s8 in ubuntu 76 | #guest_interface_default: eth1 77 | #host_ip_iface: eth1 78 | 79 | # IP version to configure Neutron to create either an Pv4, IPv6, or dual-stack self-service project data-network by with either ip_version:4, ip_version:6, or ip_version:4+6 respectively. 80 | #ip_version: 4 81 | 82 | # Extra images to download and add to glance, a list of url's comma separated 83 | # for new images to be added to glance 84 | #extra_images: https://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-amd64-disk1.img,https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img 85 | 86 | # Extra services to enable on the manager node, a space separated list of 87 | # additional services to enable on the manager node. For example, to enable 88 | # Swift, just uncomment the next line. 89 | #manager_extra_services: s-proxy s-object s-container s-account 90 | -------------------------------------------------------------------------------- /puppet/manifests/cleanup.pp: -------------------------------------------------------------------------------- 1 | node default { 2 | $dir = '/home/stack/devstack' 3 | 4 | file { '/etc/hostname': 5 | ensure => absent 6 | } 7 | 8 | file { '/etc/udev/rules.d/70-persistent-net.rules': 9 | ensure => absent 10 | } 11 | 12 | exec { 'clean.sh': 13 | cwd => $dir, 14 | path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:.', 15 | user => 'stack', 16 | command => "${dir}/clean.sh", 17 | logoutput => 'on_failure', 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /puppet/manifests/default.pp: -------------------------------------------------------------------------------- 1 | node default { 2 | include base 3 | include user::stack 4 | class {'user::vagrant': 5 | username => $::vagrant_username, 6 | } 7 | include grenade 8 | include devstack 9 | 10 | Class['base'] -> Class['user::stack'] -> Class['user::vagrant'] 11 | Class['user::stack'] -> Class['grenade'] 12 | Class['user::stack'] -> Class['devstack'] 13 | } 14 | -------------------------------------------------------------------------------- /puppet/modules/base/files/git_clone.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Functions taken liberally from devstack project, though trimmed down 4 | # for local use. 5 | 6 | # git update using reference as a branch. 7 | # git_update_branch ref 8 | function git_update_branch { 9 | 10 | local GIT_BRANCH=$1 11 | 12 | git checkout -f origin/$GIT_BRANCH 13 | # a local branch might not exist 14 | git branch -D $GIT_BRANCH || true 15 | git checkout -b $GIT_BRANCH 16 | } 17 | 18 | # git update using reference as a branch. 19 | # git_update_remote_branch ref 20 | function git_update_remote_branch { 21 | 22 | local GIT_BRANCH=$1 23 | 24 | git checkout -b $GIT_BRANCH -t origin/$GIT_BRANCH 25 | } 26 | 27 | # git update using reference as a tag. Be careful editing source at that repo 28 | # as working copy will be in a detached mode 29 | # git_update_tag ref 30 | function git_update_tag { 31 | 32 | local GIT_TAG=$1 33 | 34 | git tag -d $GIT_TAG 35 | # fetching given tag only 36 | git_timed fetch origin tag $GIT_TAG 37 | git checkout -f $GIT_TAG 38 | } 39 | 40 | # git clone only if directory doesn't exist already. Since ``DEST`` might not 41 | # be owned by the installation user, we create the directory and change the 42 | # ownership to the proper user. 43 | # git_clone remote dest-dir branch 44 | function git_clone { 45 | local GIT_REMOTE=$1 46 | local GIT_DEST=$2 47 | local GIT_REF=$3 48 | 49 | # Avoid git exiting when in some other dir than the typical /home/stack 50 | cd $(dirname $GIT_DEST) 51 | 52 | # do a full clone only if the directory doesn't exist 53 | if [[ ! -d $GIT_DEST ]]; then 54 | git_timed clone $GIT_REMOTE $GIT_DEST 55 | cd $GIT_DEST 56 | # This checkout syntax works for both branches and tags 57 | git checkout $GIT_REF 58 | else 59 | # if it does exist then simulate what clone does if asked to RECLONE 60 | cd $GIT_DEST 61 | # set the url to pull from and fetch 62 | git remote set-url origin $GIT_REMOTE 63 | git_timed fetch origin 64 | # remove the existing ignored files (like pyc) as they cause breakage 65 | # (due to the py files having older timestamps than our pyc, so python 66 | # thinks the pyc files are correct using them) 67 | find $GIT_DEST -name '*.pyc' -delete 68 | 69 | # handle GIT_REF accordingly to type (tag, branch) 70 | if [[ -n "`git show-ref refs/tags/$GIT_REF`" ]]; then 71 | git_update_tag $GIT_REF 72 | elif [[ -n "`git show-ref refs/heads/$GIT_REF`" ]]; then 73 | git_update_branch $GIT_REF 74 | elif [[ -n "`git show-ref refs/remotes/origin/$GIT_REF`" ]]; then 75 | git_update_remote_branch $GIT_REF 76 | else 77 | die $LINENO "$GIT_REF is neither branch nor tag" 78 | fi 79 | fi 80 | 81 | # print out the results so we know what change was used in the logs 82 | cd $GIT_DEST 83 | git show --oneline | head -1 84 | } 85 | 86 | # git can sometimes get itself infinitely stuck with transient network 87 | # errors or other issues with the remote end. This wraps git in a 88 | # timeout/retry loop and is intended to watch over non-local git 89 | # processes that might hang. GIT_TIMEOUT, if set, is passed directly 90 | # to timeout(1); otherwise the default value of 0 maintains the status 91 | # quo of waiting forever. 92 | # usage: git_timed 93 | function git_timed { 94 | local count=0 95 | local timeout=0 96 | 97 | if [[ -n "${GIT_TIMEOUT}" ]]; then 98 | timeout=${GIT_TIMEOUT} 99 | fi 100 | 101 | until timeout -s SIGINT ${timeout} git "$@"; do 102 | # 124 is timeout(1)'s special return code when it reached the 103 | # timeout; otherwise assume fatal failure 104 | if [[ $? -ne 124 ]]; then 105 | die $LINENO "git call failed: [git $@]" 106 | fi 107 | 108 | count=$(($count + 1)) 109 | warn "timeout ${count} for git call: [git $@]" 110 | if [ $count -eq 3 ]; then 111 | die $LINENO "Maximum of 3 git retries reached" 112 | fi 113 | sleep 5 114 | done 115 | } 116 | 117 | URL=${1:-https://opendev.org/openstack/devstack} 118 | BRANCH=${2:-master} 119 | LOCAL=${3:-/home/stack/devstack} 120 | 121 | set -o xtrace 122 | set -o errexit 123 | 124 | git_clone $URL $LOCAL $BRANCH 125 | -------------------------------------------------------------------------------- /puppet/modules/base/manifests/init.pp: -------------------------------------------------------------------------------- 1 | # == Class: base 2 | # 3 | 4 | class base { 5 | 6 | $vim = $::operatingsystem ? { 7 | /RedHat|Fedora|Centos/ => 'vim-enhanced', 8 | default => 'vim', 9 | } 10 | 11 | $editors = ['joe', $vim] 12 | $vcs = ['git'] 13 | 14 | case $operatingsystem { 15 | /Debian|Ubuntu/: { 16 | exec { "apt-get update": 17 | command => "/usr/bin/apt-get update", 18 | before => Exec["apt-get upgrade"], 19 | } 20 | 21 | exec { "apt-get upgrade": 22 | command => "/usr/bin/apt-get upgrade -y", 23 | require => Exec["apt-get update"], 24 | } 25 | } 26 | } 27 | 28 | package { $editors: 29 | ensure => latest 30 | } 31 | 32 | package { $vcs: 33 | ensure => latest 34 | } 35 | 36 | file { '/usr/local/bin/git_clone.sh': 37 | owner => 'root', 38 | group => 'root', 39 | mode => '0755', 40 | source => 'puppet:///modules/base/git_clone.sh', 41 | require => Package[$vcs], 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /puppet/modules/devstack/files/local.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Running local.sh" 4 | 5 | set -o xtrace 6 | 7 | openrc=/home/stack/devstack/openrc 8 | authorized_keys_file=/home/stack/.ssh/authorized_keys 9 | 10 | source "$openrc" 11 | 12 | if is_service_enabled n-api; then 13 | # Extract valid public key into tmp file to work around the issue, 14 | # introduced by puppet adding comments in the beginning of authorized_keys 15 | pubkey_file=`mktemp` 16 | grep -vE '^\s*#' "$authorized_keys_file" | head -n 1 > "$pubkey_file" 17 | 18 | for user in admin demo; do 19 | source "$openrc" "$user" "$user" 20 | openstack keypair create --public-key "$pubkey_file" default 21 | openstack security group rule create --proto icmp --dst-port -1 --remote-ip 0.0.0.0/0 default 22 | openstack security group rule create --proto tcp --dst-port 22 --remote-ip 0.0.0.0/0 default 23 | done 24 | 25 | # Tmp file cleanup 26 | rm -f "$pubkey_file" 27 | fi 28 | -------------------------------------------------------------------------------- /puppet/modules/devstack/manifests/init.pp: -------------------------------------------------------------------------------- 1 | # == Class: devstack 2 | # 3 | 4 | class devstack( 5 | $dir = '/home/stack/devstack' 6 | ) 7 | { 8 | $user = $user::stack::username 9 | 10 | if $devstack_git { 11 | $source = $devstack_git 12 | } else { 13 | $source = 'https://opendev.org/openstack/devstack' 14 | } 15 | 16 | if $devstack_branch { 17 | $branch = $devstack_branch 18 | } else { 19 | $branch = 'master' 20 | } 21 | 22 | exec { 'devstack_clone': 23 | require => File['/usr/local/bin/git_clone.sh'], 24 | path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:.', 25 | environment => "HOME=/home/$user", 26 | user => 'stack', 27 | group => 'stack', 28 | command => "/usr/local/bin/git_clone.sh ${source} ${branch} ${dir}", 29 | logoutput => true, 30 | timeout => 1200, 31 | } 32 | 33 | file { "$dir/local.sh": 34 | owner => $user, 35 | group => $user, 36 | mode => '0755', 37 | source => 'puppet:///modules/devstack/local.sh', 38 | require => Exec['devstack_clone'], 39 | } 40 | 41 | file { "$dir/local.conf": 42 | owner => $user, 43 | group => $user, 44 | mode => '0644', 45 | content => template('devstack/local.erb'), 46 | require => File["$dir/local.sh"], 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /puppet/modules/devstack/templates/local.erb: -------------------------------------------------------------------------------- 1 | [[local|localrc]] 2 | 3 | # generic configuration parameters 4 | 5 | DATABASE_PASSWORD=<%= @service_password %> 6 | RABBIT_PASSWORD=<%= @service_password %> 7 | SERVICE_TOKEN=<%= @service_password %> 8 | SERVICE_PASSWORD=<%= @service_password %> 9 | ADMIN_PASSWORD=<%= @admin_password %> 10 | 11 | MULTI_HOST="True" 12 | API_RATE_LIMIT="False" 13 | RECLONE="True" 14 | 15 | # database configuration parameters 16 | 17 | DATABASE_TYPE=mysql 18 | 19 | # networking configuration parameters 20 | 21 | GUEST_INTERFACE_DEFAULT=<%= @guest_interface_default %> 22 | HOST_IP_IFACE=<%= @host_ip_iface %> 23 | IP_VERSION=<%= @ip_version %> 24 | 25 | # logging configuration parameters 26 | 27 | LOGFILE=/opt/stack/logs/stack.sh.log 28 | VERBOSE=True 29 | LOG_COLOR=True 30 | SCREEN_LOGDIR=/opt/stack/logs 31 | 32 | <% if @is_compute == "true" %> 33 | # generic configuration parameters (compute) 34 | 35 | ENABLED_SERVICES=n-cpu,n-net,c-vol 36 | SERVICE_HOST=<%= @hostname_manager %> 37 | MYSQL_HOST=$SERVICE_HOST 38 | RABBIT_HOST=$SERVICE_HOST 39 | GLANCE_HOST=$SERVICE_HOST 40 | 41 | # configure ceilometer (compute) 42 | 43 | enable_service ceilometer-acompute 44 | <% else %> 45 | 46 | # configure images provided on glance (manager) 47 | 48 | IMAGE_URLS="<%= @extra_images %>" 49 | 50 | # configure ceilometer (manager) 51 | 52 | enable_service dstat 53 | enable_service ceilometer-acompute ceilometer-acentral ceilometer-anotification ceilometer-collector ceilometer-api 54 | enable_service ceilometer-alarm-notifier ceilometer-alarm-evaluator 55 | CEILOMETER_BACKEND=mongodb 56 | 57 | <% if @use_ldap == "true" %> 58 | # LDAP configuration parameters (manager) 59 | 60 | LDAP_PASSWORD=<%= @service_password %> 61 | enable_service ldap 62 | <% end %> 63 | 64 | <% if defined?(@manager_extra_services) %> 65 | # enable extra services 66 | 67 | enable_service <%= @manager_extra_services %> 68 | <% end %> 69 | 70 | <% end %> 71 | 72 | [[post-config|$NOVA_CONF]] 73 | [DEFAULT] 74 | flat_interface = eth1 75 | vlan_interface = eth1 76 | -------------------------------------------------------------------------------- /puppet/modules/grenade/manifests/init.pp: -------------------------------------------------------------------------------- 1 | # == Class: grenade 2 | # 3 | 4 | class grenade( 5 | $dir = '/home/stack/grenade' 6 | ) 7 | { 8 | $user = $user::stack::username 9 | 10 | if $grenade_git { 11 | $source = $grenade_git 12 | } else { 13 | $source = 'https://opendev.org/openstack/grenade' 14 | } 15 | 16 | if $grenade_branch { 17 | $branch = $grenade_branch 18 | } else { 19 | $branch = 'master' 20 | } 21 | 22 | exec { 'grenade_clone': 23 | require => File['/usr/local/bin/git_clone.sh'], 24 | path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:.', 25 | environment => "HOME=/home/$user", 26 | user => 'stack', 27 | group => 'stack', 28 | command => "/usr/local/bin/git_clone.sh ${source} ${branch} ${dir}", 29 | logoutput => true, 30 | timeout => 1200, 31 | } 32 | 33 | # file { "$dir/localrc": 34 | # owner => $user, 35 | # group => $user, 36 | # mode => 644, 37 | # source => "puppet:///modules/grenade/localrc", 38 | # require => File["$dir/local.sh"] 39 | # } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /puppet/modules/user/files/stack_bashrc: -------------------------------------------------------------------------------- 1 | # -*- shell-script -*- 2 | # .bashrc 3 | 4 | # This is a utility function to give you git branch in the prompt 5 | # if you are in a git directory 6 | function parse_git_branch { 7 | git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/' 8 | } 9 | 10 | alias ls='ls -F --color' 11 | 12 | export PROMPT_DIRTRIM=3 13 | 14 | # setup variables for prompt color codes. Makes it much easier to 15 | # read the prompt code below 16 | function proml { 17 | local BLUE="\[\033[0;34m\]" 18 | local RED="\[\033[0;31m\]" 19 | local LIGHT_RED="\[\033[1;31m\]" 20 | local GREEN="\[\033[0;32m\]" 21 | local YELLOW="\[\033[0;33m\]" 22 | local LIGHT_GREEN="\[\033[1;32m\]" 23 | local WHITE="\[\033[1;37m\]" 24 | local LIGHT_GRAY="\[\033[0;37m\]" 25 | local RESET="\[\e[0m\]" 26 | 27 | # These variables are used for prompt and title 28 | MYUSER="\u@" 29 | XMYUSER="" 30 | 31 | # if this terminal "is" an xterm (or compatible) build 32 | # a titlebar variable which is the same as the prompt more or less 33 | case $TERM in 34 | xterm*) 35 | TITLEBAR="\[\033]0;$MYUSER\h:\w\007\]" 36 | ;; 37 | *) 38 | TITLEBAR="" 39 | ;; 40 | esac 41 | 42 | # PS1 - normal prompt 43 | # set title bar 44 | # set prompt to yellow user@host : red directory (green git branch) > 45 | PS1="${TITLEBAR}\ 46 | $YELLOW$MYUSER\h$RED:\w$GREEN\$(parse_git_branch)\ 47 | $RED> $RESET" 48 | PS2='> ' 49 | PS4='+ ' 50 | } 51 | proml 52 | 53 | # Source global definitions 54 | if [ -f /etc/bashrc ]; then 55 | . /etc/bashrc 56 | fi 57 | # the variable is not defined, and after the /etc/inputrc 58 | # include the ~/.inputrc 59 | if [ -f /etc/bash_completion ]; then 60 | . /etc/bash_completion 61 | fi 62 | 63 | # because I'm not sure all platforms do this 64 | export PAGER=less 65 | 66 | # allow core files, I do development, and I want to see them 67 | ulimit -c unlimited 68 | 69 | export HISTIGNORE="&:ls:exit" 70 | 71 | # this massively speeds up pip install 72 | export PIP_DOWNLOAD_CACHE=~/.pip/cache 73 | -------------------------------------------------------------------------------- /puppet/modules/user/files/stack_sudoers: -------------------------------------------------------------------------------- 1 | stack ALL=(ALL) NOPASSWD:ALL -------------------------------------------------------------------------------- /puppet/modules/user/manifests/create.pp: -------------------------------------------------------------------------------- 1 | # == Class: user::create 2 | # 3 | 4 | define user::create ( 5 | $user = '', 6 | $pass = '', 7 | $key = '', 8 | $key_type = 'rsa', 9 | $home = "/home/${user}", 10 | $is_admin = false, 11 | ) 12 | { 13 | if $is_admin == true { 14 | $extra_groups = ['sudo', 'dialout'] 15 | } 16 | else { 17 | $extra_groups = ['dialout'] 18 | } 19 | 20 | group { $extra_groups: 21 | ensure => present, 22 | } -> 23 | 24 | group { $user: 25 | ensure => present, 26 | } -> 27 | 28 | user { $user: 29 | ensure => present, 30 | gid => $user, 31 | password => $pass, 32 | home => $home, 33 | groups => $extra_groups, 34 | shell => '/bin/bash' 35 | } -> 36 | 37 | file { $home: 38 | ensure => directory, 39 | owner => $user, 40 | group => $user, 41 | mode => '0755', 42 | } -> 43 | 44 | file { "${home}/bin": 45 | ensure => directory, 46 | owner => $user, 47 | group => $user, 48 | mode => '0755', 49 | } -> 50 | 51 | file { "${home}/.ssh": 52 | ensure => directory, 53 | owner => $user, 54 | group => $user, 55 | mode => '0700', 56 | } -> 57 | 58 | ssh_authorized_key { $user: 59 | ensure => present, 60 | key => $key, 61 | user => $user, 62 | type => $key_type, 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /puppet/modules/user/manifests/stack.pp: -------------------------------------------------------------------------------- 1 | # == Class: user::stack 2 | # 3 | 4 | class user::stack( 5 | $username = 'stack' 6 | ) 7 | { 8 | 9 | notify { 'after': 10 | message => "User params: u => $username, p => $stack_password, k => $stack_sshkey" 11 | } 12 | 13 | 14 | file { '/etc/sudoers.d/stack': 15 | owner => 'root', 16 | group => 'root', 17 | mode => '0440', 18 | source => 'puppet:///modules/user/stack_sudoers', 19 | } -> 20 | 21 | user::create { 'stack': 22 | user => $username, 23 | pass => $stack_password, 24 | key => $stack_sshkey, 25 | is_admin => true, 26 | } -> 27 | 28 | file {'/home/stack/.bashrc': 29 | owner => $username, 30 | group => $username, 31 | mode => '0644', 32 | source => 'puppet:///modules/user/stack_bashrc', 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /puppet/modules/user/manifests/vagrant.pp: -------------------------------------------------------------------------------- 1 | # == Class: user::vagrant 2 | # 3 | 4 | class user::vagrant( 5 | $username = 'vagrant' 6 | ) 7 | { 8 | file {"/home/${username}/.bashrc": 9 | owner => $username, 10 | group => $username, 11 | mode => '0644', 12 | source => 'puppet:///modules/user/stack_bashrc', 13 | } 14 | 15 | file {"/home/${username}/devstack": 16 | owner => $username, 17 | group => $username, 18 | mode => '0644', 19 | ensure => 'link', 20 | target => '/home/stack/devstack', 21 | } 22 | 23 | file {"/home/${username}/grenade": 24 | owner => $username, 25 | group => $username, 26 | mode => '0644', 27 | ensure => 'link', 28 | target => '/home/stack/grenade', 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /tools/vagrant_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # vagrant_clean.sh - clean the vagrant box to the point where you 4 | # can safely take a snapshot for local caching 5 | 6 | vagrant ssh manager -c "sudo su - stack -c 'cd ~/devstack && ./clean.sh'" 7 | vagrant ssh manager -c "sudo sed -i '/api/d' /etc/hosts" 8 | vagrant ssh manager -c "echo '127.0.0.1 localhost' | sudo tee -a /etc/hosts" 9 | 10 | VBOX_ID=$(VBoxManage list vms | grep 'devstack-vagrant_manager' | awk '{print $2}') 11 | NAME=devstack-vagrant-`date +%Y%m%d` 12 | vagrant package --base $VBOX_ID --output $NAME.box $NAME 13 | --------------------------------------------------------------------------------