├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── cluster ├── Vagrantfile ├── cluster.yml ├── hieradata │ └── common.yaml ├── lib │ ├── gen_node_configs.rb │ └── predicates.rb ├── manifests │ ├── mesos-master.pp │ └── mesos-slave.pp └── scripts │ ├── populate_sshkey.sh │ └── sshkey │ ├── id_dsa │ └── id_dsa.pub ├── hiera.yaml ├── modules └── basenode │ └── manifests │ └── init.pp └── standalone ├── Vagrantfile ├── aws.yaml ├── digital_ocean.yml ├── hieradata └── common.yaml ├── manifests └── default.pp └── scripts ├── populate_sshkey.sh └── sshkey ├── id_dsa └── id_dsa.pub /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "modules/docker"] 2 | path = modules/docker 3 | url = https://github.com/garethr/garethr-docker.git 4 | [submodule "modules/marathon"] 5 | path = modules/marathon 6 | url = https://github.com/meltwater/puppet-marathon.git 7 | [submodule "modules/mesos"] 8 | path = modules/mesos 9 | url = https://github.com/deric/puppet-mesos 10 | [submodule "modules/apt"] 11 | path = modules/apt 12 | url = https://github.com/puppetlabs/puppetlabs-apt.git 13 | [submodule "modules/stdlib"] 14 | path = modules/stdlib 15 | url = https://github.com/puppetlabs/puppetlabs-stdlib.git 16 | [submodule "modules/zookeeper"] 17 | path = modules/zookeeper 18 | url = https://github.com/deric/puppet-zookeeper 19 | [submodule "modules/epel"] 20 | path = modules/epel 21 | url = https://github.com/stahnma/puppet-module-epel.git 22 | [submodule "modules/archive"] 23 | path = modules/archive 24 | url = https://github.com/camptocamp/puppet-archive 25 | [submodule "modules/datacat"] 26 | path = modules/datacat 27 | url = https://github.com/richardc/puppet-datacat.git 28 | [submodule "modules/consul"] 29 | path = modules/consul 30 | url = https://github.com/solarkennedy/puppet-consul.git 31 | [submodule "modules/staging"] 32 | path = modules/staging 33 | url = https://github.com/nanliu/puppet-staging.git 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2014 Mesosphere 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vagrant-puppet-mesosphere 2 | ==================== 3 | Create your [Mesosphere](http://mesosphere.com) stack with [Vagrant](http://www.vagrantup.com) and [Puppet](http://puppetlabs.com/) (Virtualbox / AWS / Digital Ocean are supported providers). 4 | 5 | This creates a Mesos cluster in which [Marathon](https://github.com/mesosphere/marathon) framework and [Consul](https://github.com/hashicorp/consul) (Optional, used for service discovery) are running. This means you can build your own __Mesos+Marathon+Docker__ PaaS with `vagrant up`! _If you want to deploy docker containers, please refer to the chapter "Deploy Docker Container with Marathon" in [this blog entry](http://frankhinek.com/deploy-docker-containers-on-mesos-0-20/)._ 6 | 7 | * Using VirtualBox 8 | * [Mesos Standalone on VirtualBox](#svb) 9 | * [Mesos Cluster on VirtualBox](#clvb) 10 | 11 | Prerequisites 12 | ---- 13 | * vagrant 1.6.5+: 14 | * VirtualBox: (not required if you use ec2/DigitalOcean.) 15 | * vagrant plugins 16 | * [vagrant-hosts](https://github.com/adrienthebo/vagrant-hosts) 17 | `$ vagrant plugin install vagrant-hosts` 18 | * [vagrant-cachier](https://github.com/fgrehm/vagrant-cachier) 19 | `$ vagrant plugin install vagrant-cachier` 20 | * [vagrant-aws](https://github.com/mitchellh/vagrant-aws) (only if you use ec2.) 21 | `$ vagrant plugin install vagrant-aws` 22 | * [vagrant-digitalocean](https://github.com/smdahlen/vagrant-digitalocean) (only if you use DigitalOcean.) 23 | `$ vagrant plugin install vagrant-digitalocean` 24 | 25 | Clone this repository and update git submodules: 26 | 27 | ```shell 28 | $ git clone https://github.com/tayzlor/vagrant-puppet-mesosphere.git 29 | $ cd vagrant-puppet-mesosphere 30 | $ git submodule init 31 | $ git submodule update 32 | ``` 33 | 34 | 35 | Mesos Standalone on VirtualBox 36 | ---- 37 | 38 | Includes - 39 | 40 | * Docker (1.4.0) 41 | * Mesos master (x1) 42 | * Mesos slave (x1) 43 | * Marathon (0.7.5) 44 | * Zookeeper 45 | * Consul, running in server mode (Optional - configure via ```consul_enable:``` param in ```hieradata/common.yml``` ) 46 | 47 | ```shell 48 | $ cd standalone 49 | $ vagrant up 50 | ``` 51 | 52 | After box is up, you can see services running at: 53 | 54 | * Mesos web UI on: 55 | * [Marathon](https://github.com/mesosphere/marathon) web UI on: 56 | * [Consul](https://github.com/hashicorp/consul) web UI on: 57 | 58 | 59 | Mesos Cluster on VirtualBox 60 | ---- 61 | ### Cluster Configuration 62 | Cluster configuration is defined at `cluster/cluster.yml`. You can edit the file to configure cluster settings. 63 | 64 | ```yaml 65 | # Mesos cluster configurations 66 | # The numbers of servers 67 | ############################## 68 | master_n: 1 # hostname will be master1,master2,… 69 | slave_n : 1 # hostname will be slave1,slave2,… 70 | 71 | # Memory and Cpus setting(only for virtualbox) 72 | ########################################## 73 | master_mem : 256 74 | master_cpus: 1 75 | slave_mem : 512 76 | slave_cpus : 2 77 | 78 | # private ip bases 79 | # When ec2, this should be matched with 80 | # private addresses defined by subnet_id below. 81 | ################################################ 82 | master_ipbase: "172.31.1." 83 | slave_ipbase : "172.31.2." 84 | ``` 85 | 86 | ### Node types 87 | 88 | #### mesos-master 89 | Includes - 90 | 91 | * Docker (1.4.0) 92 | * Mesos (running in master server mode) 93 | * Marathon (0.7.5) 94 | * Zookeeper 95 | * Consul, running in server mode (Optional - configure via ```consul_enable:``` param in ```cluster.yml```) 96 | 97 | #### mesos-slave 98 | Includes - 99 | 100 | * Docker (1.4.0) 101 | * Mesos (running in slave server mode) 102 | * Consul, running in agent mode (optional - configure via ```consul_enable:``` param in ```cluster.yml```) 103 | 104 | ### Launch Cluster 105 | This may takes several minutes(10 to 20 min.). 106 | 107 | ```shell 108 | $ cd cluster 109 | $ vagrant up 110 | ``` 111 | 112 | At default setting, after all the boxes are up, you can see services running at: 113 | 114 | * Mesos web UI on: 115 | * [Marathon](https://github.com/mesosphere/marathon) web UI on: 116 | * [Chronos](https://github.com/mesosphere/chronos) web UI on: 117 | 118 | #### Destroy Cluster 119 | this operations all VM instances forming the cluster. 120 | 121 | ```shell 122 | $ cd cluster 123 | $ vagrant destroy 124 | ``` 125 | 126 | #### Credits 127 | Inspired by - [https://github.com/everpeace/vagrant-mesos](https://github.com/everpeace/vagrant-mesos) which is similar but uses Chef, and has a slightly different cluster layout / components. 128 | [http://philzim.com/2014/11/12/service-discovery-orchestration-with-mesos-and-consul](http://philzim.com/2014/11/12/service-discovery-orchestration-with-mesos-and-consul) 129 | -------------------------------------------------------------------------------- /cluster/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | require 'yaml' 4 | require './lib/gen_node_configs' 5 | require './lib/predicates' 6 | 7 | base_dir = File.expand_path(File.dirname(__FILE__)) 8 | conf = YAML.load_file(File.join(base_dir, "cluster.yml")) 9 | node_configs = gen_node_configs(conf) 10 | 11 | ## vagrant plugins required: 12 | # vagrant, vagrant-hosts, vagrant-cachier, vagrant-aws 13 | Vagrant.configure("2") do |config| 14 | 15 | if !conf["custom_ami"] then 16 | # https://vagrantcloud.com/puppetlabs/boxes/ubuntu-14.04-64-puppet 17 | config.vm.box = "puppetlabs/ubuntu-14.04-64-puppet" 18 | config.vm.box_version = "1.0.0" 19 | end 20 | 21 | # if you want to use vagrant-cachier, 22 | # please install vagrant-cachier plugin. 23 | if Vagrant.has_plugin?("vagrant-cachier") 24 | config.cache.enable :apt 25 | end 26 | 27 | # define VMs. all VMs has identical configuration. 28 | [node_configs[:master], node_configs[:slave]].flatten.each_with_index do |node, i| 29 | config.vm.define node[:hostname] do |cfg| 30 | 31 | cfg.vm.provider :virtualbox do |vb, override| 32 | override.vm.hostname = node[:hostname] 33 | override.vm.network :private_network, :ip => node[:ip] 34 | override.vm.provision :hosts 35 | 36 | vb.name = 'vagrant-mesos-' + node[:hostname] 37 | vb.customize ["modifyvm", :id, "--memory", node[:mem], "--cpus", node[:cpus] ] 38 | 39 | override.vm.provision :shell do |s| 40 | s.path = "scripts/populate_sshkey.sh" 41 | s.args = "/root root" 42 | end 43 | 44 | override.vm.provision :shell do |s| 45 | s.path = "scripts/populate_sshkey.sh" 46 | s.args = "/home/vagrant vagrant" 47 | end 48 | end 49 | 50 | cfg.vm.provider :digital_ocean do |digital_ocean, override| 51 | override.ssh.private_key_path = conf["ssh_private_key_path"] 52 | override.vm.box = 'digital_ocean' 53 | override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box" 54 | 55 | digital_ocean.token = conf["token"] 56 | digital_ocean.image = conf["image"] 57 | digital_ocean.region = conf["region"] 58 | digital_ocean.size = node[:size] 59 | end 60 | 61 | cfg.vm.provider :aws do |aws, override| 62 | aws.access_key_id = conf["access_key_id"] 63 | aws.secret_access_key = conf["secret_access_key"] 64 | 65 | aws.region = conf["region"] 66 | if conf["custom_ami"] then 67 | override.vm.box = "dummy" 68 | override.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box" 69 | aws.ami = conf["custom_ami"] 70 | end 71 | aws.instance_type = node[:instance_type] 72 | aws.keypair_name = conf["keypair_name"] 73 | aws.subnet_id = conf["subnet_id"] 74 | aws.security_groups = conf["security_groups"] 75 | aws.private_ip_address = node[:ip] 76 | aws.tags = { 77 | Name: "vagrant-mesos-#{node[:hostname]}" 78 | } 79 | if !conf["default_vpc"] then 80 | aws.associate_public_ip = true 81 | end 82 | 83 | override.ssh.username = "ubuntu" 84 | override.ssh.private_key_path = conf["ssh_private_key_path"] 85 | 86 | override.vm.provision :shell do |s| 87 | s.path = "scripts/populate_sshkey.sh" 88 | s.args = "/home/ubuntu ubuntu" 89 | end 90 | 91 | override.vm.provision :shell , :inline => <<-SCRIPT 92 | PUBLIC_DNS=`wget -q -O - http://169.254.169.254/latest/meta-data/public-hostname` 93 | hostname $PUBLIC_DNS 94 | echo $PUBLIC_DNS > /etc/hostname 95 | HOSTNAME=$PUBLIC_DNS # Fix the bash built-in hostname variable too 96 | SCRIPT 97 | 98 | if master?(node[:hostname]) then 99 | override.vm.provision :shell , :inline => 'restart mesos-master' 100 | end 101 | 102 | if slave?(node[:hostname]) then 103 | override.vm.provision :shell , :inline => 'restart mesos-slave' 104 | end 105 | end 106 | 107 | config.vm.provision "puppet" do |puppet| 108 | puppet.manifests_path = "manifests" 109 | puppet.module_path = "../modules" 110 | puppet.hiera_config_path = "../hiera.yaml" 111 | puppet.options = "--verbose --debug" 112 | 113 | if master?(node[:hostname]) then 114 | puppet.manifest_file = "mesos-master.pp" 115 | puppet.facter = { 116 | "quorum" => "#{(node_configs[:master].length.to_f/2).ceil}", 117 | "zookeeper" => "zk://"+node_configs[:master].map{|master| master[:ip]+":2181"}.join(",")+"/mesos", 118 | "zookeeper_id" => (/master([0-9]+)/.match node[:hostname])[1], 119 | "marathon_zk" => "zk://"+node_configs[:master].map{|master| master[:ip]+":2181"}.join(",")+"/marathon", 120 | } 121 | elsif slave?(node[:hostname]) then 122 | puppet.manifest_file = "mesos-slave.pp" 123 | puppet.facter = { 124 | "zookeeper" => "zk://"+node_configs[:master].map{|master| master[:ip]+":2181"}.join(",")+"/mesos", 125 | } 126 | end 127 | 128 | # General settings, for masters and slaves. 129 | puppet.facter["ip"] = "#{node[:ip]}" 130 | # Consul.io settings 131 | puppet.facter["consul_enable"] = conf["consul_enable"] 132 | puppet.facter["node_name"] = node[:hostname] 133 | puppet.facter["bootstrap_expect"] = node_configs[:master].length 134 | puppet.facter["datacenter"] = conf["consul_datacenter"] 135 | 136 | # Set the leader to join for the Consul Cluster 137 | node_configs[:master].each do |master| 138 | if master[:hostname] == conf["consul_join"] then 139 | puppet.facter["join_cluster"] = master[:ip] 140 | end 141 | end 142 | end 143 | 144 | # If you wanted use `.dockercfg` file 145 | # Please place the file simply on this directory 146 | if File.exist?(".dockercfg") 147 | config.vm.provision :shell, :priviledged => true, :inline => <<-SCRIPT 148 | cp /vagrant/.dockercfg /root/.dockercfg 149 | chmod 600 /root/.dockercfg 150 | chown root /root/.dockercfg 151 | SCRIPT 152 | end 153 | end 154 | end 155 | end 156 | -------------------------------------------------------------------------------- /cluster/cluster.yml: -------------------------------------------------------------------------------- 1 | # The numbers of servers 2 | ############################## 3 | master_n: 2 # hostname will be master1,master2,… 4 | slave_n: 2 # hostname will be slave1,slave2,… 5 | 6 | # Memory and Cpus setting(only for virtualbox) 7 | ########################################## 8 | master_mem : 256 9 | master_cpus: 1 10 | slave_mem : 1024 11 | slave_cpus : 2 12 | 13 | # private ip bases 14 | # When ec2, this should be matched with 15 | # private addresses defined by subnet_id below. 16 | ################################################ 17 | master_ipbase: "172.31.1." 18 | slave_ipbase : "172.31.2." 19 | 20 | # Consul.io settings 21 | consul_enable: true 22 | consul_datacenter: eu-west-1 23 | # The server to join for other nodes joining the cluster. Typically this server 24 | # would be provisioned first, then the other nodes would join the cluster as 25 | # they are provisioned. 26 | consul_join: master1 27 | 28 | ###################### 29 | # EC2 Configurations # 30 | ###################### 31 | # please choose one region from 32 | # ["ap-northeast-1", "ap-southeast-1", "eu-west-1", "sa-east-1", 33 | # "us-east-1", "us-west-1", "ap-southeast-2", "us-west-2"] 34 | # NOTE: if you used non-default vpc, you should make sure that 35 | # limit of the elastic ips is no less than (zk_n + master_n + slave_n). 36 | # In EC2, the limit default is 5. 37 | ######################## 38 | access_key_id: EDIT_HERE 39 | secret_access_key: EDIT_HERE 40 | 41 | default_vpc: true # default vpc or not. 42 | #subnet_id: EDIT_HERE # VPC subnet id 43 | #security_groups: ["EDIT_HERE"] # array of VPN security groups. e.g. ['sg*** '] 44 | keypair_name: EDIT_HERE 45 | ssh_private_key_path: EDIT_HERE 46 | region: EDIT_HERE 47 | 48 | # set a custom AMI to use if you need something other than the defaults 49 | #custom_ami: ami-267bd951 50 | 51 | # See http://aws.amazon.com/ec2/instance-types/#selecting-instance-types 52 | master_instance_type: m1.small 53 | slave_instance_type: m1.small 54 | 55 | ############################### 56 | # Digital Ocean Configuration # 57 | ############################### 58 | token: EDIT_HERE 59 | ssh_private_key_path: EDIT_HERE 60 | 61 | # Choose one from 62 | # "sgp1", "nyc1", "nyc2", "sfo1", "lon1", "ams3", "ams2", "nyc3" 63 | # Or vagrant digitalocean-list regions TOKEN 64 | region: EDIT_HERE 65 | 66 | # set a custom Droplet image to use 67 | image: EDIT_HERE 68 | 69 | # See Vagrant digitalocean-list sizes TOKEN 70 | master_droplet_size: 512mb 71 | slave_droplet_size: 512mb 72 | -------------------------------------------------------------------------------- /cluster/hieradata/common.yaml: -------------------------------------------------------------------------------- 1 | docker::version: '1.4.0' 2 | java::distribution: 'jre' 3 | 4 | marathon::version: '0.7.5' 5 | marathon::source_install: false 6 | marathon::install_java: false 7 | 8 | mesos::repo: 'mesosphere' 9 | mesos::master_port: 5050 10 | 11 | zookeeper::client_port: 2181 12 | -------------------------------------------------------------------------------- /cluster/lib/gen_node_configs.rb: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | def gen_node_configs(cluster_yml) 5 | master_n = cluster_yml['master_n'] 6 | master_mem = cluster_yml['master_mem'] 7 | master_cpus = cluster_yml['master_cpus'] 8 | slave_n = cluster_yml['slave_n'] 9 | slave_mem = cluster_yml['slave_mem'] 10 | slave_cpus = cluster_yml['slave_cpus'] 11 | master_ipbase = cluster_yml['master_ipbase'] 12 | slave_ipbase = cluster_yml['slave_ipbase'] 13 | master_instance_type = cluster_yml['master_instance_type'] 14 | slave_instance_type = cluster_yml['slave_instance_type'] 15 | master_droplet_size = cluster_yml['master_droplet_size'] 16 | slave_droplet_size = cluster_yml['slave_droplet_size'] 17 | 18 | master_infos = (1..master_n).map do |i| 19 | { :hostname => "master#{i}", 20 | :ip => master_ipbase + "#{10+i}", 21 | :mem => master_mem, 22 | :cpus => master_cpus, 23 | :instance_type => master_instance_type, 24 | :size => master_droplet_size 25 | } 26 | end 27 | slave_infos = (1..slave_n).map do |i| 28 | { :hostname => "slave#{i}", 29 | :ip => slave_ipbase + "#{10+i}", 30 | :mem => slave_mem, 31 | :cpus => slave_cpus, 32 | :instance_type => slave_instance_type, 33 | :size => slave_droplet_size 34 | } 35 | end 36 | 37 | return { :master => master_infos, :slave=>slave_infos } 38 | end 39 | -------------------------------------------------------------------------------- /cluster/lib/predicates.rb: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | def master?(name) 5 | return /^master/ =~ name 6 | end 7 | 8 | def slave?(name) 9 | return /^slave/ =~ name 10 | end 11 | -------------------------------------------------------------------------------- /cluster/manifests/mesos-master.pp: -------------------------------------------------------------------------------- 1 | # $zookeeper, $quorum, $ip and $marathon_zk are passed in 2 | # from the Vagrantfile depending on the cluster set up in cluster.yml 3 | 4 | include basenode 5 | class { 'mesos': 6 | zookeeper => $zookeeper 7 | } 8 | class { 'mesos::master': 9 | options => { 10 | quorum => $quorum, 11 | log_dir => '/var/log/mesos', 12 | hostname => $ip, 13 | ip => $ip, 14 | }, 15 | zookeeper => $zookeeper, 16 | } 17 | class { 'zookeeper': 18 | id => $zookeeper_id, 19 | } 20 | class { 'marathon': 21 | marathon_zk => $marathon_zk 22 | } 23 | 24 | # Ensure Slave service not running on master nodes. 25 | service { 'mesos-slave': 26 | ensure => stopped, 27 | enable => false, 28 | require => Package['mesos'] 29 | } 30 | 31 | if $consul_enable { 32 | class { 'consul': 33 | join_cluster => $join_cluster, 34 | config_hash => { 35 | 'server' => true, 36 | 'bootstrap_expect' => $bootstrap_expect, 37 | 'data_dir' => '/opt/consul', 38 | 'ui_dir' => '/opt/consul/ui', 39 | 'log_level' => 'INFO', 40 | 'client_addr' => '0.0.0.0', 41 | 'advertise_addr' => $ip, 42 | 'node_name' => $node_name, 43 | 'datacenter' => $datacenter, 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cluster/manifests/mesos-slave.pp: -------------------------------------------------------------------------------- 1 | # $zookeeper, $ip are passed in from the Vagrantfile depending on the cluster 2 | # set up in cluster.yml 3 | 4 | include basenode 5 | class { 'mesos': 6 | zookeeper => $zookeeper 7 | } 8 | class { 'mesos::slave': 9 | zookeeper => $zookeeper, 10 | options => { 11 | containerizers => 'docker,mesos', 12 | executor_registration_timeout => '5mins', 13 | hostname => $ip, 14 | ip => $ip, 15 | log_dir => '/var/log/mesos' 16 | } 17 | } 18 | 19 | # Ensure we are not running zk, mesos-master or marathon on slave nodes. 20 | service { 'mesos-master': 21 | ensure => stopped, 22 | enable => false, 23 | require => Package['mesos'] 24 | } 25 | service { 'zookeeper': 26 | ensure => stopped, 27 | enable => false, 28 | require => Package['mesos'] 29 | } 30 | 31 | if $consul_enable { 32 | class { 'consul': 33 | join_cluster => $join_cluster, 34 | config_hash => { 35 | 'data_dir' => '/opt/consul', 36 | 'log_level' => 'INFO', 37 | 'client_addr' => '0.0.0.0', 38 | 'advertise_addr' => $ip, 39 | 'node_name' => $node_name, 40 | 'datacenter' => $datacenter 41 | } 42 | } 43 | 44 | # Join the cluster manually. We do this to circumvent the issues described 45 | # over here - 46 | # https://github.com/solarkennedy/puppet-consul/pull/42 47 | # https://github.com/solarkennedy/puppet-consul/issues/31 48 | exec {'slave join consul cluster': 49 | cwd => $consul::config_dir, 50 | path => [$consul::bin_dir,'/bin','/usr/bin'], 51 | command => "consul join ${join_cluster}", 52 | subscribe => Service['consul'], 53 | require => Class['consul'], 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cluster/scripts/populate_sshkey.sh: -------------------------------------------------------------------------------- 1 | HOME=$1 2 | USER=$2 3 | 4 | sudo -u $USER mkdir -p $HOME/.ssh 5 | sudo -u $USER chmod 700 $HOME/.ssh 6 | sudo -u $USER cp /vagrant/scripts/sshkey/id_dsa $HOME/.ssh/id_dsa 7 | sudo -u $USER chmod 600 $HOME/.ssh/id_dsa 8 | sudo -u $USER cat /vagrant/scripts/sshkey/id_dsa.pub >> $HOME/.ssh/authorized_keys 9 | sudo -u $USER chmod 600 $HOME/.ssh/authorized_keys 10 | cat << EOT > $HOME/.ssh/config 11 | host * 12 | StrictHostKeyChecking no 13 | EOT 14 | chown $USER $HOME/.ssh/config 15 | 16 | -------------------------------------------------------------------------------- /cluster/scripts/sshkey/id_dsa: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | MIIBuwIBAAKBgQCG+zSeymTENzJtrzJzmB0ZLbCxk7013Cq0yTS/quRZrl30hH8O 3 | vqFmrue7Diz8SSAnNFh5WA6T2RgmFybdHt/GiqvWKypnoaezceNKp8tgC1ie0s7K 4 | WAkErmdXVkNwcpcs5La/Yb4YzTYg1Pgv1WnUQetZrr2sLsAT/Gh8nlakuQIVAPGr 5 | uz4Q9Bu1hHC41yxQuBETIQ+dAoGBAIYqRNMFcYPEL+Scoy+ZYy0eSE1bYJDy7dXg 6 | Rhj7/6VnfwAMH7tUMX6ey0CCxrL9CRe1M3phYzmlexIyZ6S9r/elMeHDk4oETbmG 7 | kiaGBB48M5eg8mKm5jGNEKrJh5Kv0Bk3Sexzk+vVfDkUgA+i/h3V++6zecKY+oDR 8 | psS5LU7wAoGAcOo4Y5uAd+Xp7YOAxXxjeOal+SZp2KkbUCpAx2oyju2JpgOWi/sA 9 | pZ8Zo6tHkP0rmYP195Ud1x/gJ1M1HUMqX9Or1/+2mtq3eufPObbyGgeAklthoO6Y 10 | R0U8HqadaGqVXc4xXY41bNnBUY7LCUbB1JI5IdEc2feHlGSSBPYu1JACFDgenGnF 11 | D2jR7yUCCs/TcC2iyRtc 12 | -----END DSA PRIVATE KEY----- 13 | -------------------------------------------------------------------------------- /cluster/scripts/sshkey/id_dsa.pub: -------------------------------------------------------------------------------- 1 | ssh-dss AAAAB3NzaC1kc3MAAACBAIb7NJ7KZMQ3Mm2vMnOYHRktsLGTvTXcKrTJNL+q5FmuXfSEfw6+oWau57sOLPxJICc0WHlYDpPZGCYXJt0e38aKq9YrKmehp7Nx40qny2ALWJ7SzspYCQSuZ1dWQ3Bylyzktr9hvhjNNiDU+C/VadRB61muvawuwBP8aHyeVqS5AAAAFQDxq7s+EPQbtYRwuNcsULgREyEPnQAAAIEAhipE0wVxg8Qv5JyjL5ljLR5ITVtgkPLt1eBGGPv/pWd/AAwfu1Qxfp7LQILGsv0JF7UzemFjOaV7EjJnpL2v96Ux4cOTigRNuYaSJoYEHjwzl6DyYqbmMY0QqsmHkq/QGTdJ7HOT69V8ORSAD6L+HdX77rN5wpj6gNGmxLktTvAAAACAcOo4Y5uAd+Xp7YOAxXxjeOal+SZp2KkbUCpAx2oyju2JpgOWi/sApZ8Zo6tHkP0rmYP195Ud1x/gJ1M1HUMqX9Or1/+2mtq3eufPObbyGgeAklthoO6YR0U8HqadaGqVXc4xXY41bNnBUY7LCUbB1JI5IdEc2feHlGSSBPYu1JA= omura@Shingo-no-MacBook-Pro.local 2 | -------------------------------------------------------------------------------- /hiera.yaml: -------------------------------------------------------------------------------- 1 | :hierarchy: 2 | - common 3 | 4 | :backends: yaml 5 | 6 | :yaml: 7 | :datadir: '/vagrant/hieradata' 8 | -------------------------------------------------------------------------------- /modules/basenode/manifests/init.pp: -------------------------------------------------------------------------------- 1 | class basenode() { 2 | Exec { path => ["/usr/bin", "/usr/sbin", "/bin", "/sbin"] } 3 | 4 | package { ['python-setuptools', 'python-protobuf']: 5 | ensure => present 6 | } 7 | 8 | include docker 9 | } 10 | -------------------------------------------------------------------------------- /standalone/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | require 'yaml' 4 | 5 | ## vagrant plugins required: 6 | # vagrant-digitalocean, vagrant-aws, vagrant, vagrant-hosts, vagrant-cachier 7 | Vagrant.configure("2") do |config| 8 | 9 | # https://vagrantcloud.com/puppetlabs/boxes/ubuntu-14.04-64-puppet 10 | config.vm.box = "puppetlabs/ubuntu-14.04-64-puppet" 11 | config.vm.box_version = "1.0.0" 12 | 13 | # If you want to use vagrant-cachier, 14 | # please install vagrant-cachier plugin. 15 | if Vagrant.has_plugin?("vagrant-cachier") 16 | config.cache.enable :apt 17 | end 18 | 19 | config.vm.provider :virtualbox do |vb, override| 20 | # Use VBoxManage to customize the VM. For example to change memory: 21 | vb.customize ["modifyvm", :id, "--memory", "#{1024*2}"] 22 | vb.customize ["modifyvm", :id, "--cpus", "2"] 23 | 24 | # Please customize hostname and private ip configuration if you needed. 25 | override.vm.hostname = "mesos" 26 | private_ip = "192.168.33.10" 27 | override.vm.network :private_network, ip: private_ip 28 | override.vm.provision :hosts do |provisioner| 29 | provisioner.add_host private_ip , [ config.vm.hostname ] 30 | end 31 | 32 | # Mesos web UI 33 | override.vm.network :forwarded_port, guest: 5050, host: 5050 34 | # Marathon web UI 35 | override.vm.network :forwarded_port, guest: 8080, host: 8080 36 | # Consul web UI 37 | override.vm.network :forwarded_port, guest: 8500, host: 8500 38 | 39 | override.vm.provision :shell do |s| 40 | s.path = "scripts/populate_sshkey.sh" 41 | s.args = "/home/vagrant vagrant" 42 | end 43 | end 44 | 45 | config.vm.provider :digital_ocean do |digital_ocean, override| 46 | conf = YAML.load_file('digital_ocean.yml') 47 | override.ssh.private_key_path = conf["ssh_private_key_path"] 48 | override.vm.box = 'digital_ocean' 49 | override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box" 50 | 51 | digital_ocean.token = conf["token"] 52 | digital_ocean.image = conf["image"] 53 | digital_ocean.region = conf["region"] 54 | digital_ocean.size = conf["size"] 55 | end 56 | 57 | config.vm.provider :aws do |aws, override| 58 | conf = YAML.load_file('aws.yaml') 59 | 60 | if conf["custom_ami"] then 61 | override.vm.box = "dummy" 62 | override.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box" 63 | end 64 | 65 | aws.access_key_id = conf["access_key_id"] 66 | aws.secret_access_key = conf["secret_access_key"] 67 | 68 | aws.region = conf["region"] 69 | if conf["custom_ami"] then 70 | aws.ami = conf["custom_ami"] 71 | end 72 | aws.instance_type = conf["instance_type"] 73 | aws.keypair_name = conf["keypair_name"] 74 | aws.security_groups = conf["security_groups"] 75 | aws.tags = { 76 | Name: 'vagrant-mesos-standalone' 77 | } 78 | 79 | override.ssh.username = "ubuntu" 80 | override.ssh.private_key_path = conf["ssh_private_key_path"] 81 | override.vm.provision :shell do |s| 82 | s.path = "scripts/populate_sshkey.sh" 83 | s.args = "/home/ubuntu ubuntu" 84 | end 85 | end 86 | 87 | config.vm.provision "puppet" do |puppet| 88 | puppet.manifests_path = "manifests" 89 | puppet.module_path = "../modules" 90 | puppet.manifest_file = "default.pp" 91 | puppet.hiera_config_path = "../hiera.yaml" 92 | puppet.options = "--verbose --debug" 93 | end 94 | 95 | # If you wanted use `.dockercfg` file 96 | # Please place the file simply on this directory 97 | if File.exist?(".dockercfg") 98 | config.vm.provision :shell, :priviledged => true, :inline => <<-SCRIPT 99 | cp /vagrant/.dockercfg /root/.dockercfg 100 | chmod 600 /root/.dockercfg 101 | chown root /root/.dockercfg 102 | SCRIPT 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /standalone/aws.yaml: -------------------------------------------------------------------------------- 1 | # Please set AWS credentials 2 | access_key_id: EDIT_HERE 3 | secret_access_key: EDIT_HERE 4 | 5 | # please choose one from 6 | # ["ap-northeast-1", "ap-southeast-1", "eu-west-1", "sa-east-1", "us-east-1", 7 | # "us-west-1", "ap-southeast-2", "us-west-2"] 8 | region: EDIT_HERE 9 | 10 | # set a custom AMI to use if you need something other than the defaults 11 | #custom_ami: ami-267bd951 12 | 13 | # array of security groups. e.g. ['sg*** '] 14 | # please make sure to open ports 22(SSH), 5050(Mesos), 8080(Marathon) 15 | #security_groups: EDIT_HERE 16 | 17 | # see http://aws.amazon.com/ec2/instance-types/#selecting-instance-types 18 | # for other instance types and its specs. 19 | instance_type: m1.small 20 | 21 | keypair_name: EDIT_HERE 22 | ssh_private_key_path: EDIT_HERE 23 | -------------------------------------------------------------------------------- /standalone/digital_ocean.yml: -------------------------------------------------------------------------------- 1 | # Please set Digital Ocean credentials 2 | token: EDIT_HERE 3 | ssh_private_key_path: EDIT_HERE 4 | 5 | # Choose one from 6 | # "sgp1", "nyc1", "nyc2", "sfo1", "lon1", "ams3", "ams2", "nyc3" 7 | # Or vagrant digitalocean-list regions TOKEN 8 | region: EDIT_HERE 9 | 10 | # set a custom Droplet image to use 11 | image: EDIT_HERE 12 | 13 | # See Vagrant digitalocean-list sizes TOKEN 14 | size: 512mb 15 | -------------------------------------------------------------------------------- /standalone/hieradata/common.yaml: -------------------------------------------------------------------------------- 1 | marathon::version: '0.7.5' 2 | marathon::source_install: false 3 | marathon::install_java: false 4 | 5 | mesos::repo: 'mesosphere' 6 | mesos::master_port: 5050 7 | mesos::zookeeper: 'zk://localhost:2181/mesos' 8 | 9 | mesos::master::options: 10 | quorum: '1' 11 | log_dir: '/var/log/mesos' 12 | 13 | mesos::slave::zookeeper: 'zk://localhost:2181/mesos' 14 | mesos::slave::options: 15 | containerizers: 'docker,mesos' 16 | executor_registration_timeout: '5mins' 17 | hostname: "%{::ipaddress_eth1}" 18 | ip: "%{::ipaddress_eth1}" 19 | 20 | docker::version: '1.4.0' 21 | java::distribution: 'jre' 22 | 23 | zookeeper::client_port: 2181 24 | 25 | consul::config_hash: 26 | # If using AWS / Digital Ocean change this to the desired location 27 | datacenter: 'eu-west-1' 28 | bootstrap_expect: 1 29 | data_dir: '/opt/consul' 30 | ui_dir: '/opt/consul/ui' 31 | client_addr: '0.0.0.0' 32 | log_level: 'INFO' 33 | node_name: 'mesos' 34 | server: true 35 | 36 | consul_enable: true 37 | -------------------------------------------------------------------------------- /standalone/manifests/default.pp: -------------------------------------------------------------------------------- 1 | include basenode 2 | include zookeeper 3 | include marathon 4 | include mesos::master 5 | include mesos::slave 6 | 7 | # Provision Consul if its enabled in common.yml. 8 | $consul_enable = hiera('consul_enable') 9 | if $consul_enable { 10 | include consul 11 | } 12 | -------------------------------------------------------------------------------- /standalone/scripts/populate_sshkey.sh: -------------------------------------------------------------------------------- 1 | HOME=$1 2 | USER=$2 3 | 4 | sudo -u $USER mkdir -p $HOME/.ssh 5 | sudo -u $USER chmod 700 $HOME/.ssh 6 | sudo -u $USER cp /vagrant/scripts/sshkey/id_dsa $HOME/.ssh/id_dsa 7 | sudo -u $USER chmod 600 $HOME/.ssh/id_dsa 8 | sudo -u $USER cat /vagrant/scripts/sshkey/id_dsa.pub >> $HOME/.ssh/authorized_keys 9 | sudo -u $USER chmod 600 $HOME/.ssh/authorized_keys 10 | cat << EOT > $HOME/.ssh/config 11 | host * 12 | StrictHostKeyChecking no 13 | EOT 14 | chown $USER $HOME/.ssh/config 15 | 16 | -------------------------------------------------------------------------------- /standalone/scripts/sshkey/id_dsa: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | MIIBuwIBAAKBgQCG+zSeymTENzJtrzJzmB0ZLbCxk7013Cq0yTS/quRZrl30hH8O 3 | vqFmrue7Diz8SSAnNFh5WA6T2RgmFybdHt/GiqvWKypnoaezceNKp8tgC1ie0s7K 4 | WAkErmdXVkNwcpcs5La/Yb4YzTYg1Pgv1WnUQetZrr2sLsAT/Gh8nlakuQIVAPGr 5 | uz4Q9Bu1hHC41yxQuBETIQ+dAoGBAIYqRNMFcYPEL+Scoy+ZYy0eSE1bYJDy7dXg 6 | Rhj7/6VnfwAMH7tUMX6ey0CCxrL9CRe1M3phYzmlexIyZ6S9r/elMeHDk4oETbmG 7 | kiaGBB48M5eg8mKm5jGNEKrJh5Kv0Bk3Sexzk+vVfDkUgA+i/h3V++6zecKY+oDR 8 | psS5LU7wAoGAcOo4Y5uAd+Xp7YOAxXxjeOal+SZp2KkbUCpAx2oyju2JpgOWi/sA 9 | pZ8Zo6tHkP0rmYP195Ud1x/gJ1M1HUMqX9Or1/+2mtq3eufPObbyGgeAklthoO6Y 10 | R0U8HqadaGqVXc4xXY41bNnBUY7LCUbB1JI5IdEc2feHlGSSBPYu1JACFDgenGnF 11 | D2jR7yUCCs/TcC2iyRtc 12 | -----END DSA PRIVATE KEY----- 13 | -------------------------------------------------------------------------------- /standalone/scripts/sshkey/id_dsa.pub: -------------------------------------------------------------------------------- 1 | ssh-dss AAAAB3NzaC1kc3MAAACBAIb7NJ7KZMQ3Mm2vMnOYHRktsLGTvTXcKrTJNL+q5FmuXfSEfw6+oWau57sOLPxJICc0WHlYDpPZGCYXJt0e38aKq9YrKmehp7Nx40qny2ALWJ7SzspYCQSuZ1dWQ3Bylyzktr9hvhjNNiDU+C/VadRB61muvawuwBP8aHyeVqS5AAAAFQDxq7s+EPQbtYRwuNcsULgREyEPnQAAAIEAhipE0wVxg8Qv5JyjL5ljLR5ITVtgkPLt1eBGGPv/pWd/AAwfu1Qxfp7LQILGsv0JF7UzemFjOaV7EjJnpL2v96Ux4cOTigRNuYaSJoYEHjwzl6DyYqbmMY0QqsmHkq/QGTdJ7HOT69V8ORSAD6L+HdX77rN5wpj6gNGmxLktTvAAAACAcOo4Y5uAd+Xp7YOAxXxjeOal+SZp2KkbUCpAx2oyju2JpgOWi/sApZ8Zo6tHkP0rmYP195Ud1x/gJ1M1HUMqX9Or1/+2mtq3eufPObbyGgeAklthoO6YR0U8HqadaGqVXc4xXY41bNnBUY7LCUbB1JI5IdEc2feHlGSSBPYu1JA= omura@Shingo-no-MacBook-Pro.local 2 | --------------------------------------------------------------------------------