├── .gitignore ├── README.md ├── playbooks ├── base.yml ├── compute.yml ├── glusterfs.yml ├── library │ └── docker_pull ├── mesos.yml ├── openvpn.yml ├── papertrail.yml ├── procedures │ ├── consul-bootstrap.yml │ ├── dist-upgrade.yml │ ├── reboot.all.yml │ ├── reboot.compute_nodes.yml │ └── registrator-restart.yml └── weave.yml └── roles ├── common ├── defaults │ └── main.yml ├── handlers │ └── main.yml ├── tasks │ └── main.yml └── templates │ ├── gmond.conf.j2 │ ├── hosts.j2 │ ├── nameservers.j2 │ ├── ntp.conf.j2 │ ├── postfix-generic.j2 │ ├── postfix-main.cf.j2 │ ├── postfix-passwd.j2 │ ├── private_lan.j2 │ └── resolv.conf.j2 ├── compute ├── defaults │ └── main.yml ├── files │ └── bamboo_1.0.0-1_all.deb ├── handlers │ └── main.yml ├── tasks │ └── main.yml └── templates │ ├── bamboo-config.json.j2 │ └── haproxy_template.cfg.j2 ├── consul ├── files │ ├── 10-dns.json │ └── consul.conf ├── handlers │ └── main.yml ├── tasks │ └── main.yml └── templates │ ├── 10-consul.j2 │ └── default.j2 ├── docker ├── defaults │ └── main.yml ├── files │ ├── docker-cleanup │ └── docker-enter ├── handlers │ └── main.yml ├── tasks │ └── main.yml └── templates │ ├── dockercfg.j2 │ ├── logspout.conf.j2 │ └── registrator.conf.j2 ├── glusterfs ├── tasks │ ├── client.yml │ ├── main.yml │ ├── server.yml │ └── server_client.yml └── vars │ └── main.yml ├── mesos ├── defaults │ └── main.yml ├── files │ ├── logrotate-marathon │ └── rsyslog-marathon ├── handlers │ └── main.yml ├── tasks │ ├── main.yml │ ├── master.yml │ ├── master_slave.yml │ └── slave.yml └── templates │ ├── zk.j2 │ └── zoo.cfg.j2 ├── openvpn_gateway ├── defaults │ └── main.yml ├── handlers │ └── main.yml ├── tasks │ └── main.yml └── templates │ └── server.conf.j2 ├── papertrail ├── handlers │ └── main.yml ├── tasks │ └── main.yml └── templates │ └── papertrail.conf.j2 └── weave ├── defaults └── main.yml ├── files └── weave.conf ├── handlers └── main.yml ├── tasks └── main.yml └── templates └── interface.j2 /.gitignore: -------------------------------------------------------------------------------- 1 | hosts 2 | *.sublime-* 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | compute-platform 2 | ================ 3 | 4 | A mesos based compute platform deployed with ansible 5 | -------------------------------------------------------------------------------- /playbooks/base.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | roles: 3 | - role: ../roles/common 4 | tags: common_role 5 | 6 | - hosts: mesos_masters 7 | roles: 8 | - role: ../roles/consul 9 | consul_role: server 10 | tags: consul_role 11 | serial: "20%" 12 | 13 | - hosts: all:!mesos_masters 14 | roles: 15 | - role: ../roles/consul 16 | consul_role: client 17 | tags: consul_role 18 | 19 | - hosts: all 20 | roles: 21 | - role: ../../roles/docker 22 | tags: docker_role 23 | serial: "20%" 24 | -------------------------------------------------------------------------------- /playbooks/compute.yml: -------------------------------------------------------------------------------- 1 | - hosts: compute_nodes 2 | roles: 3 | - role: ../../roles/compute 4 | serial: 1 5 | -------------------------------------------------------------------------------- /playbooks/glusterfs.yml: -------------------------------------------------------------------------------- 1 | - hosts: gluster_nodes 2 | roles: 3 | - role: ../../roles/glusterfs 4 | glusterfs_peer_group: gluster_nodes 5 | glusterfs_volume: cluster 6 | glusterfs_brick_dir: /var/lib/cluster 7 | glusterfs_role: server 8 | tags: gluster_server_role 9 | 10 | - hosts: compute_nodes 11 | roles: 12 | - role: ../../roles/glusterfs 13 | glusterfs_peer_group: gluster_nodes 14 | glusterfs_mountpoint: /cluster 15 | glusterfs_volume: cluster 16 | glusterfs_role: client 17 | tags: gluster_client_role -------------------------------------------------------------------------------- /playbooks/library/docker_pull: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # vim:fileencoding=utf-8 3 | 4 | DOCUMENTATION = """ 5 | --- 6 | """ 7 | 8 | EXAMPLES = """ 9 | """ 10 | 11 | from hashlib import md5 12 | 13 | 14 | class DockerPuller(object): 15 | 16 | def __init__(self, module): 17 | self.module = module 18 | self.repo = module.params['repo'] 19 | self.tag = module.params['tag'] 20 | 21 | def pull_repo(self, docker='docker'): 22 | checksum = self._get_images_checksum(docker) 23 | cmd = [self._docker(docker), 'pull'] 24 | 25 | repo = self.repo 26 | if self.tag: 27 | repo += ':' + self.tag 28 | 29 | cmd += [repo] 30 | 31 | rc, out, err = self._run(cmd) 32 | 33 | if rc is not None and rc != 0: 34 | self._fail(err, rc) 35 | 36 | if out.strip().startswith('Usage:'): 37 | self._fail( 38 | ('Got usage output for cmd=%r:\n' % (cmd,)) + out + err, rc 39 | ) 40 | 41 | return ( 42 | (rc, out, err), 43 | self._get_images_checksum(docker) != checksum 44 | ) 45 | 46 | def _get_images_checksum(self, docker='docker'): 47 | cmd = [self._docker(docker), 'images', '-q'] 48 | rc, out, err = self._run(cmd) 49 | 50 | if rc is not None and rc != 0: 51 | self._fail(err, rc) 52 | 53 | return _md5sum(out.strip()) 54 | 55 | def _run(self, cmd): 56 | return self.module.run_command(cmd) 57 | 58 | def _docker(self, docker): 59 | return self.module.get_bin_path(docker, True) 60 | 61 | def _fail(self, err, rc): 62 | self.module.fail_json( 63 | repo=self.repo, tag=self.tag, msg=err, rc=rc 64 | ) 65 | 66 | 67 | def _md5sum(string): 68 | return md5(string).hexdigest() 69 | 70 | 71 | def main(): 72 | module = AnsibleModule( 73 | argument_spec=dict( 74 | state=dict(default='present', choices=['present']), 75 | repo=dict(required=True), 76 | tag=dict(default='', required=False), 77 | ), 78 | supports_check_mode=True 79 | ) 80 | 81 | puller = DockerPuller(module) 82 | 83 | rc = None 84 | out = '' 85 | err = '' 86 | result = {} 87 | 88 | if module.check_mode: 89 | module.exit_json(changed=False) 90 | 91 | (rc, out, err), changed = puller.pull_repo() 92 | 93 | if rc is None: 94 | result['changed'] = False 95 | else: 96 | result['changed'] = changed 97 | 98 | if out: 99 | result['stdout'] = out 100 | if err: 101 | result['stderr'] = err 102 | 103 | module.exit_json(**result) 104 | 105 | 106 | # include magic from lib/ansible/module_common.py 107 | #<> 108 | main() 109 | -------------------------------------------------------------------------------- /playbooks/mesos.yml: -------------------------------------------------------------------------------- 1 | - hosts: mesos_masters:!compute_nodes 2 | roles: 3 | - role: ../../roles/mesos 4 | mesos_role: master 5 | tags: mesos_masters 6 | serial: 1 7 | 8 | - hosts: compute_nodes:&mesos_masters 9 | roles: 10 | - role: ../../roles/mesos 11 | mesos_role: master_slave 12 | tags: 13 | - mesos_masters 14 | - mesos_slaves 15 | serial: 1 16 | 17 | - hosts: compute_nodes:!mesos_masters 18 | roles: 19 | - role: ../../roles/mesos 20 | mesos_role: slave 21 | tags: mesos_slaves 22 | serial: 1 -------------------------------------------------------------------------------- /playbooks/openvpn.yml: -------------------------------------------------------------------------------- 1 | - hosts: openvpn_gateways 2 | roles: 3 | - role: ../roles/openvpn_gateway 4 | tags: openvpn_role 5 | openvpn_domain: "{{ domain }}" 6 | openvpn_search_domains: "{{ domain }} service.dc1.consul" 7 | -------------------------------------------------------------------------------- /playbooks/papertrail.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | roles: 3 | - role: ../../roles/papertrail 4 | 5 | -------------------------------------------------------------------------------- /playbooks/procedures/consul-bootstrap.yml: -------------------------------------------------------------------------------- 1 | - hosts: mesos_masters 2 | tasks: 3 | - service: name=consul state=stopped 4 | - file: name=/var/lib/consul/raft/peers.json state=absent 5 | # - lineinfile: 'dest=/etc/default/consul regexp="CONSUL_FLAGS=" line="CONSUL_FLAGS=\"-bootstrap-expect {{ groups["mesos_masters"] | length }}\""' 6 | - lineinfile: 'dest=/etc/default/consul regexp="CONSUL_FLAGS=" line="CONSUL_FLAGS=\"-bootstrap\""' 7 | when: inventory_hostname == groups['mesos_masters'][0] 8 | - service: name=consul state=started 9 | - shell: consul join {%for host in groups['mesos_masters']%} {%if host != inventory_hostname%}{{host}}{%endif%}{%endfor%} 10 | when: inventory_hostname == groups['mesos_masters'][0] 11 | - lineinfile: 'dest=/etc/default/consul regexp="CONSUL_FLAGS=" line="#CONSUL_FLAGS="' 12 | - service: name=consul state=restarted 13 | when: inventory_hostname == groups['mesos_masters'][0] 14 | -------------------------------------------------------------------------------- /playbooks/procedures/dist-upgrade.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | tasks: 3 | - name: updates a server 4 | apt: update_cache=yes 5 | - name: upgrade a server 6 | apt: upgrade=full 7 | serial: 1 -------------------------------------------------------------------------------- /playbooks/procedures/reboot.all.yml: -------------------------------------------------------------------------------- 1 | - hosts: "all" 2 | serial: 1 3 | roles: 4 | - role: ../../roles/reboot 5 | -------------------------------------------------------------------------------- /playbooks/procedures/reboot.compute_nodes.yml: -------------------------------------------------------------------------------- 1 | - hosts: "compute_nodes" 2 | serial: 1 3 | roles: 4 | - role: ../../roles/reboot 5 | rolling_reboot_pause: 2 -------------------------------------------------------------------------------- /playbooks/procedures/registrator-restart.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | tasks: 3 | - shell: docker restart registrator 4 | -------------------------------------------------------------------------------- /playbooks/weave.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | roles: 3 | - role: ../roles/weave 4 | tags: weave_role 5 | -------------------------------------------------------------------------------- /roles/common/defaults/main.yml: -------------------------------------------------------------------------------- 1 | private_netdev: eth1 2 | private_netmask: 255.255.255.0 3 | private_broadcast: 10.0.0.255 4 | domain: example.com 5 | nameservers: ["8.8.8.8", "8.8.4.4"] 6 | -------------------------------------------------------------------------------- /roles/common/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: reload dnsmasq 2 | shell: killall -HUP dnsmaq || true 3 | 4 | - name: restart dnsmasq 5 | service: name=dnsmasq state=restarted 6 | 7 | - name: start private LAN 8 | shell: ifdown {{ private_netdev }} || true && ifup {{ private_netdev }} 9 | 10 | - name: reload ganglia-monitor 11 | service: name=ganglia-monitor state=reloaded 12 | 13 | - name: reload sshd 14 | service: name=ssh state=reloaded 15 | 16 | - name: rebuild postfix passwd map 17 | command: postmap /etc/postfix/sasl/passwd 18 | 19 | - name: rebuild postfix generic map 20 | command: postmap /etc/postfix/generic 21 | 22 | - name: restart postfix 23 | service: name=postfix state=restarted 24 | 25 | - name: update timezone 26 | command: dpkg-reconfigure --frontend noninteractive tzdata 27 | 28 | - name: restart ntp 29 | service: name=ntp state=restarted 30 | 31 | - name: restart rsyslog 32 | service: name=rsyslog state=restarted 33 | -------------------------------------------------------------------------------- /roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: apt-get update 2 | apt: update_cache=yes 3 | 4 | # install public ssh key 5 | - name: install SSH keys 6 | copy: dest=/root/.ssh/authorized_keys mode=600 content="{{root_authorized_keys}}" 7 | 8 | # network config 9 | - hostname: name={{ inventory_hostname }} 10 | 11 | - name: Load network interfaces from /etc/network/interfaces.d 12 | action: lineinfile dest=/etc/network/interfaces line="source-directory interfaces.d" state=present insertbefore=BOF 13 | 14 | - name: Configure private network interface 15 | template: src=private_lan.j2 dest=/etc/network/interfaces.d/private_lan 16 | notify: start private LAN 17 | - meta: flush_handlers 18 | 19 | # setup dns with local dnsmasq 20 | - apt: pkg=dnsmasq 21 | 22 | - name: remove google 8.8.8.8 server from dnsmasq 23 | file: dest=/etc/dnsmasq.d/20-google state=absent 24 | notify: restart dnsmasq 25 | - name: remove google 8.8.4.4 server from dnsmasq 26 | file: dest=/etc/dnsmasq.d/21-google state=absent 27 | notify: restart dnsmasq 28 | - name: set nameserver upstreams for dnsmasq 29 | template: src=nameservers.j2 dest=/etc/dnsmasq.d/20-nameservers 30 | notify: restart dnsmasq 31 | - name: make dnsmasq ignore resolvconf to find upstream servers 32 | lineinfile: name=/etc/default/dnsmasq regexp="IGNORE_RESOLVCONF=" line="IGNORE_RESOLVCONF=yes" 33 | notify: restart dnsmasq 34 | - service: name=dnsmasq state=started enabled=true 35 | 36 | - name: Create the hosts file for all machines 37 | template: src=hosts.j2 dest=/etc/hosts 38 | notify: reload dnsmasq 39 | 40 | - shell: chattr -i /etc/resolv.conf 41 | - template: src=resolv.conf.j2 dest=/etc/resolv.conf 42 | - shell: chattr +i /etc/resolv.conf 43 | 44 | - meta: flush_handlers 45 | 46 | # install ntp and set timezone to UTC 47 | - name: set timezone to UTC 48 | copy: content='UTC' dest=/etc/timezone 49 | notify: update timezone 50 | - template: src=ntp.conf.j2 dest=/etc/ntp.conf 51 | notify: restart ntp 52 | - apt: pkg=ntp 53 | - service: name=ntp state=started enabled=true 54 | 55 | # do security upgrades 56 | - name: Install unattended-upgrades 57 | action: apt pkg={{item}} state=present 58 | with_items: 59 | - unattended-upgrades 60 | - update-notifier-common 61 | - name: Make sure unattended-upgrades only installs from $ubuntu_release-security 62 | lineinfile: dest=/etc/apt/apt.conf.d/50unattended-upgrades regexp="$ubuntu_release-updates" state=absent 63 | - name: Mail root on unattended-upgrades 64 | lineinfile: dest=/etc/apt/apt.conf.d/50unattended-upgrades regexp=Unattended-Upgrade::Mail line='Unattended-Upgrade::Mail "root";' 65 | - name: Set unattended-upgrade period 66 | lineinfile: dest=/etc/apt/apt.conf.d/10periodic regexp=APT::Periodic::Unattended-Upgrade line='APT::Periodic::Unattended-Upgrade "1";' 67 | - name: Set apt-get cleanup period 68 | lineinfile: dest=/etc/apt/apt.conf.d/10periodic regexp=APT::Periodic::AutocleanInterval line='APT::Periodic::AutocleanInterval "7";' 69 | - name: Set apt-get download period 70 | lineinfile: dest=/etc/apt/apt.conf.d/10periodic regexp=APT::Periodic::Download-Upgradeable-Packages line='APT::Periodic::Download-Upgradeable-Packages "1";' 71 | 72 | # send mails to smarthost 73 | - name: install postfix 74 | apt: pkg={{item}} 75 | with_items: 76 | - postfix 77 | - mailutils 78 | - template: src=postfix-main.cf.j2 dest=/etc/postfix/main.cf 79 | notify: restart postfix 80 | - template: src=postfix-passwd.j2 dest=/etc/postfix/sasl/passwd mode=0600 81 | notify: rebuild postfix passwd map 82 | - template: src=postfix-generic.j2 dest=/etc/postfix/generic 83 | notify: rebuild postfix generic map 84 | - name: give root a speaking name 85 | user: name=root comment="root@{{ inventory_hostname }}.{{ domain }}" 86 | 87 | # send out logs to install server's fluentd 88 | - apt: pkg=rsyslog 89 | #- copy: dest=/etc/rsyslog.d/00-fluentd.conf content="*.* @{{ groups['install_servers'][0] }}:42185" 90 | # notify: restart rsyslog 91 | - service: name=rsyslog state=started enabled=true 92 | 93 | #- name: Install logwatch 94 | # action: apt pkg=logwatch state=installed 95 | #- name: Make logwatch mail {{ logwatch_email }} daily 96 | # action: lineinfile dest=/etc/cron.daily/00logwatch regexp="^/usr/sbin/logwatch" line="/usr/sbin/logwatch --output mail --mailto {{ logwatch_email }} --detail low" state=present create=yes 97 | 98 | # general firewall rules 99 | - apt: pkg=ufw 100 | - ufw: rule=allow name=OpenSSH 101 | - ufw: state=enabled policy=reject 102 | - ufw: rule=allow src={{ item }} 103 | with_items: 104 | - 10.0.0.0/8 105 | - 172.16.0.0/12 106 | - 192.168.0.0/16 107 | 108 | - name: disable SSH password root logins 109 | action: lineinfile dest=/etc/ssh/sshd_config regexp=^#?PasswordAuthentication line="PasswordAuthentication no" 110 | notify: reload sshd 111 | 112 | - name: disable DNS lookup on SSH login 113 | lineinfile: dest=/etc/ssh/sshd_config line="UseDNS no" 114 | notify: reload sshd 115 | 116 | # install ganglia monitor 117 | #- apt: pkg={{ item }} state=present 118 | # with_items: 119 | # - ganglia-monitor 120 | # - ganglia-monitor-python 121 | # - ganglia-modules-linux 122 | #- service: name=ganglia-monitor state=started enabled=yes 123 | #- template: src=gmond.conf.j2 dest=/etc/ganglia/gmond.conf 124 | # notify: reload ganglia-monitor 125 | 126 | # default packages 127 | - apt: pkg={{item}} state=present 128 | with_items: 129 | - glances 130 | - zile 131 | - mc 132 | - openjdk-7-jre-headless 133 | - sysbench 134 | - iotop 135 | - sysstat 136 | - haveged # for better entropy 137 | - redis-tools # needed for health checks of redis 138 | 139 | # remove misc 140 | - apt: pkg={{item}} state=absent 141 | with_items: 142 | - mlocate # sucks IO heavily 143 | -------------------------------------------------------------------------------- /roles/common/templates/gmond.conf.j2: -------------------------------------------------------------------------------- 1 | /* This configuration is as close to 2.5.x default behavior as possible 2 | The values closely match ./gmond/metric.h definitions in 2.5.x */ 3 | globals { 4 | daemonize = yes 5 | setuid = yes 6 | user = ganglia 7 | debug_level = 0 8 | max_udp_msg_len = 1472 9 | mute = no 10 | {% if inventory_hostname in groups['ganglia_servers'] %} 11 | deaf = no 12 | {% else %} 13 | deaf = yes 14 | {% endif %} 15 | host_dmax = 0 /*secs */ 16 | cleanup_threshold = 300 /*secs */ 17 | gexec = no 18 | send_metadata_interval = 0 19 | } 20 | 21 | /* If a cluster attribute is specified, then all gmond hosts are wrapped inside 22 | * of a tag. If you do not specify a cluster tag, then all will 23 | * NOT be wrapped inside of a tag. */ 24 | cluster { 25 | name = "{{ ganglia_clustername }}" 26 | owner = "{{ ganglia_clusterowner }}" 27 | } 28 | 29 | /* The host section describes attributes of the host, like the location */ 30 | host { 31 | location = "ams2" 32 | } 33 | 34 | /* Feel free to specify as many udp_send_channels as you like. Gmond 35 | used to only support having a single channel */ 36 | udp_send_channel { 37 | host = {{ groups['ganglia_servers'][0] }} 38 | port = 8649 39 | ttl = 1 40 | } 41 | 42 | /* You can specify as many udp_recv_channels as you like as well. */ 43 | {% if inventory_hostname in groups['ganglia_servers'] %} 44 | udp_recv_channel { 45 | port = 8649 46 | } 47 | {% endif %} 48 | 49 | /* You can specify as many tcp_accept_channels as you like to share 50 | an xml description of the state of the cluster */ 51 | tcp_accept_channel { 52 | port = 8649 53 | } 54 | 55 | /* Each metrics module that is referenced by gmond must be specified and 56 | loaded. If the module has been statically linked with gmond, it does not 57 | require a load path. However all dynamically loadable modules must include 58 | a load path. */ 59 | modules { 60 | module { 61 | name = "core_metrics" 62 | } 63 | module { 64 | name = "cpu_module" 65 | path = "/usr/lib/ganglia/modcpu.so" 66 | } 67 | module { 68 | name = "disk_module" 69 | path = "/usr/lib/ganglia/moddisk.so" 70 | } 71 | module { 72 | name = "load_module" 73 | path = "/usr/lib/ganglia/modload.so" 74 | } 75 | module { 76 | name = "mem_module" 77 | path = "/usr/lib/ganglia/modmem.so" 78 | } 79 | module { 80 | name = "net_module" 81 | path = "/usr/lib/ganglia/modnet.so" 82 | } 83 | module { 84 | name = "proc_module" 85 | path = "/usr/lib/ganglia/modproc.so" 86 | } 87 | module { 88 | name = "sys_module" 89 | path = "/usr/lib/ganglia/modsys.so" 90 | } 91 | } 92 | 93 | include ('/etc/ganglia/conf.d/*.conf') 94 | 95 | 96 | /* The old internal 2.5.x metric array has been replaced by the following 97 | collection_group directives. What follows is the default behavior for 98 | collecting and sending metrics that is as close to 2.5.x behavior as 99 | possible. */ 100 | 101 | /* This collection group will cause a heartbeat (or beacon) to be sent every 102 | 20 seconds. In the heartbeat is the GMOND_STARTED data which expresses 103 | the age of the running gmond. */ 104 | collection_group { 105 | collect_once = yes 106 | time_threshold = 20 107 | metric { 108 | name = "heartbeat" 109 | } 110 | } 111 | 112 | /* This collection group will send general info about this host every 1200 secs. 113 | This information doesn't change between reboots and is only collected once. */ 114 | collection_group { 115 | collect_once = yes 116 | time_threshold = 1200 117 | metric { 118 | name = "cpu_num" 119 | title = "CPU Count" 120 | } 121 | metric { 122 | name = "cpu_speed" 123 | title = "CPU Speed" 124 | } 125 | metric { 126 | name = "mem_total" 127 | title = "Memory Total" 128 | } 129 | /* Should this be here? Swap can be added/removed between reboots. */ 130 | metric { 131 | name = "swap_total" 132 | title = "Swap Space Total" 133 | } 134 | metric { 135 | name = "boottime" 136 | title = "Last Boot Time" 137 | } 138 | metric { 139 | name = "machine_type" 140 | title = "Machine Type" 141 | } 142 | metric { 143 | name = "os_name" 144 | title = "Operating System" 145 | } 146 | metric { 147 | name = "os_release" 148 | title = "Operating System Release" 149 | } 150 | metric { 151 | name = "location" 152 | title = "Location" 153 | } 154 | } 155 | 156 | /* This collection group will send the status of gexecd for this host every 300 secs */ 157 | /* Unlike 2.5.x the default behavior is to report gexecd OFF. */ 158 | collection_group { 159 | collect_once = yes 160 | time_threshold = 300 161 | metric { 162 | name = "gexec" 163 | title = "Gexec Status" 164 | } 165 | } 166 | 167 | /* This collection group will collect the CPU status info every 20 secs. 168 | The time threshold is set to 90 seconds. In honesty, this time_threshold could be 169 | set significantly higher to reduce unneccessary network chatter. */ 170 | collection_group { 171 | collect_every = 20 172 | time_threshold = 90 173 | /* CPU status */ 174 | metric { 175 | name = "cpu_user" 176 | value_threshold = "1.0" 177 | title = "CPU User" 178 | } 179 | metric { 180 | name = "cpu_system" 181 | value_threshold = "1.0" 182 | title = "CPU System" 183 | } 184 | metric { 185 | name = "cpu_idle" 186 | value_threshold = "5.0" 187 | title = "CPU Idle" 188 | } 189 | metric { 190 | name = "cpu_nice" 191 | value_threshold = "1.0" 192 | title = "CPU Nice" 193 | } 194 | metric { 195 | name = "cpu_aidle" 196 | value_threshold = "5.0" 197 | title = "CPU aidle" 198 | } 199 | metric { 200 | name = "cpu_wio" 201 | value_threshold = "1.0" 202 | title = "CPU wio" 203 | } 204 | /* The next two metrics are optional if you want more detail... 205 | ... since they are accounted for in cpu_system. 206 | metric { 207 | name = "cpu_intr" 208 | value_threshold = "1.0" 209 | title = "CPU intr" 210 | } 211 | metric { 212 | name = "cpu_sintr" 213 | value_threshold = "1.0" 214 | title = "CPU sintr" 215 | } 216 | */ 217 | } 218 | 219 | collection_group { 220 | collect_every = 20 221 | time_threshold = 90 222 | /* Load Averages */ 223 | metric { 224 | name = "load_one" 225 | value_threshold = "1.0" 226 | title = "One Minute Load Average" 227 | } 228 | metric { 229 | name = "load_five" 230 | value_threshold = "1.0" 231 | title = "Five Minute Load Average" 232 | } 233 | metric { 234 | name = "load_fifteen" 235 | value_threshold = "1.0" 236 | title = "Fifteen Minute Load Average" 237 | } 238 | } 239 | 240 | /* This group collects the number of running and total processes */ 241 | collection_group { 242 | collect_every = 80 243 | time_threshold = 950 244 | metric { 245 | name = "proc_run" 246 | value_threshold = "1.0" 247 | title = "Total Running Processes" 248 | } 249 | metric { 250 | name = "proc_total" 251 | value_threshold = "1.0" 252 | title = "Total Processes" 253 | } 254 | } 255 | 256 | /* This collection group grabs the volatile memory metrics every 40 secs and 257 | sends them at least every 180 secs. This time_threshold can be increased 258 | significantly to reduce unneeded network traffic. */ 259 | collection_group { 260 | collect_every = 40 261 | time_threshold = 180 262 | metric { 263 | name = "mem_free" 264 | value_threshold = "1024.0" 265 | title = "Free Memory" 266 | } 267 | metric { 268 | name = "mem_shared" 269 | value_threshold = "1024.0" 270 | title = "Shared Memory" 271 | } 272 | metric { 273 | name = "mem_buffers" 274 | value_threshold = "1024.0" 275 | title = "Memory Buffers" 276 | } 277 | metric { 278 | name = "mem_cached" 279 | value_threshold = "1024.0" 280 | title = "Cached Memory" 281 | } 282 | metric { 283 | name = "swap_free" 284 | value_threshold = "1024.0" 285 | title = "Free Swap Space" 286 | } 287 | } 288 | 289 | collection_group { 290 | collect_every = 40 291 | time_threshold = 300 292 | metric { 293 | name = "bytes_out" 294 | value_threshold = 4096 295 | title = "Bytes Sent" 296 | } 297 | metric { 298 | name = "bytes_in" 299 | value_threshold = 4096 300 | title = "Bytes Received" 301 | } 302 | metric { 303 | name = "pkts_in" 304 | value_threshold = 256 305 | title = "Packets Received" 306 | } 307 | metric { 308 | name = "pkts_out" 309 | value_threshold = 256 310 | title = "Packets Sent" 311 | } 312 | } 313 | 314 | /* Different than 2.5.x default since the old config made no sense */ 315 | collection_group { 316 | collect_every = 1800 317 | time_threshold = 3600 318 | metric { 319 | name = "disk_total" 320 | value_threshold = 1.0 321 | title = "Total Disk Space" 322 | } 323 | } 324 | 325 | collection_group { 326 | collect_every = 40 327 | time_threshold = 180 328 | metric { 329 | name = "disk_free" 330 | value_threshold = 1.0 331 | title = "Disk Space Available" 332 | } 333 | metric { 334 | name = "part_max_used" 335 | value_threshold = 1.0 336 | title = "Maximum Disk Space Used" 337 | } 338 | } 339 | 340 | -------------------------------------------------------------------------------- /roles/common/templates/hosts.j2: -------------------------------------------------------------------------------- 1 | 127.0.0.1 localhost 2 | {% for host in groups['all'] %} 3 | {{ hostvars[host]['private_ip'] }} {{ hostvars[host]['inventory_hostname'] }} {{ hostvars[host]['inventory_hostname'] }}.{{ domain }} {{ hostvars[host]['host_aliases'] | default('') }} {% if host == inventory_hostname %}host host.{{ domain }}{% endif %} 4 | 5 | {% endfor %} 6 | -------------------------------------------------------------------------------- /roles/common/templates/nameservers.j2: -------------------------------------------------------------------------------- 1 | {% for host in nameservers %} 2 | server={{host}} 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /roles/common/templates/ntp.conf.j2: -------------------------------------------------------------------------------- 1 | driftfile /var/lib/ntp/ntp.drift 2 | statistics loopstats peerstats clockstats 3 | filegen loopstats file loopstats type day enable 4 | filegen peerstats file peerstats type day enable 5 | filegen clockstats file clockstats type day enable 6 | 7 | {% if inventory_hostname in groups['mesos_masters'] %} 8 | server ptbtime1.ptb.de 9 | server ptbtime2.ptb.de 10 | server ptbtime3.ptb.de 11 | 12 | {% for host in groups['mesos_masters'] -%} 13 | {% if host != inventory_hostname %} 14 | peer {{host}}.{{ domain }} 15 | {% endif -%} 16 | {% endfor %} 17 | 18 | {% else %} 19 | 20 | {% for host in groups['mesos_masters'] -%} 21 | server {{host}}.{{ domain }} 22 | {% endfor %} 23 | 24 | {% endif %} 25 | 26 | restrict -4 default kod notrap nomodify nopeer noquery 27 | restrict -6 default kod notrap nomodify nopeer noquery 28 | 29 | restrict 127.0.0.1 30 | restrict ::1 31 | -------------------------------------------------------------------------------- /roles/common/templates/postfix-generic.j2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sttts/compute-platform/4cb9c62365023dc6f4aed0133ffdfcb1eb36f04f/roles/common/templates/postfix-generic.j2 -------------------------------------------------------------------------------- /roles/common/templates/postfix-main.cf.j2: -------------------------------------------------------------------------------- 1 | smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) 2 | biff = no 3 | append_dot_mydomain = no 4 | readme_directory = no 5 | myhostname = {{ domain }} 6 | mydomain = {{ domain }} 7 | relay_domains = {{ domain }} 8 | alias_maps = hash:/etc/aliases 9 | alias_database = hash:/etc/aliases 10 | 11 | # restrictions 12 | smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination 13 | mydestination = {{ inventory_hostname }}, {{ inventory_hostname }}.{{ domain }}, localhost.localdomain, localhost 14 | mynetworks = 127.0.0.0/8 172.16.0.0/12 [::ffff:127.0.0.0]/104 [::1]/128 15 | mailbox_size_limit = 0 16 | recipient_delimiter = + 17 | inet_interfaces = all 18 | 19 | # SMTP relay 20 | relayhost = [{{postfix_smarthost}}]:587 21 | smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt 22 | smtp_use_tls = yes 23 | smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache 24 | smtp_tls_note_starttls_offer = yes 25 | tls_random_source = dev:/dev/urandom 26 | 27 | smtp_sasl_auth_enable = yes 28 | smtp_sasl_password_maps = hash:/etc/postfix/sasl/passwd 29 | smtp_sasl_security_options = noanonymous 30 | smtp_sasl_tls_security_options = noanonymous 31 | smtp_connection_cache_destinations = {{postfix_smarthost}} 32 | 33 | default_transport = smtp 34 | default_destination_concurrency_limit = 5 35 | -------------------------------------------------------------------------------- /roles/common/templates/postfix-passwd.j2: -------------------------------------------------------------------------------- 1 | {{postfix_smarthost}} {{postfix_smartuser}}:{{postfix_smartpass}} 2 | -------------------------------------------------------------------------------- /roles/common/templates/private_lan.j2: -------------------------------------------------------------------------------- 1 | auto {{ private_netdev }} 2 | iface {{ private_netdev }} inet static 3 | address {{ private_ip }} 4 | netmask {{ private_netmask }} 5 | broadcast {{ private_broadcast }} -------------------------------------------------------------------------------- /roles/common/templates/resolv.conf.j2: -------------------------------------------------------------------------------- 1 | nameserver 127.0.0.1 2 | search {{ domain }} service.dc1.consul 3 | -------------------------------------------------------------------------------- /roles/compute/defaults/main.yml: -------------------------------------------------------------------------------- 1 | haproxy_certificate_files: {} 2 | -------------------------------------------------------------------------------- /roles/compute/files/bamboo_1.0.0-1_all.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sttts/compute-platform/4cb9c62365023dc6f4aed0133ffdfcb1eb36f04f/roles/compute/files/bamboo_1.0.0-1_all.deb -------------------------------------------------------------------------------- /roles/compute/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart bamboo 2 | service: name=bamboo-server state=restarted 3 | 4 | - name: install bamboo deb 5 | shell: dpkg -i /tmp/bamboo_1.0.0-1_all.deb 6 | notify: restart bamboo 7 | 8 | - name: reload haproxy 9 | service: name=haproxy state=reloaded -------------------------------------------------------------------------------- /roles/compute/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # install bamboo 2 | - copy: src=bamboo_1.0.0-1_all.deb dest=/tmp 3 | notify: install bamboo deb 4 | tags: bamboo 5 | - meta: flush_handlers 6 | - file: name=/etc/bamboo state=directory 7 | tags: bamboo 8 | - name: install bamboo haproxy config template 9 | template: src=haproxy_template.cfg.j2 dest=/etc/bamboo/haproxy_template.cfg mode=0600 10 | notify: restart bamboo 11 | tags: bamboo 12 | - name: install bamboo configuration 13 | template: src=bamboo-config.json.j2 dest=/etc/bamboo/config.json 14 | notify: restart bamboo 15 | tags: bamboo 16 | - service: name=bamboo-server state=started enabled=true 17 | tags: bamboo 18 | - name: link bamboo configuration to /var/bamboo/production.json 19 | file: dest=/var/bamboo/production.json src=/etc/bamboo/config.json force=yes state=link 20 | notify: restart bamboo 21 | tags: bamboo 22 | 23 | # install haproxy 24 | - name: add Debian proxy team haproxy 1.5 repository 25 | apt_repository: repo=ppa:vbernat/haproxy-1.5 26 | - apt: pkg=haproxy 27 | notify: restart bamboo 28 | - service: name=haproxy state=started enabled=true 29 | - lineinfile: dest=/etc/default/haproxy regexp="^ENABLED=" line="ENABLED=1" 30 | 31 | # install certificates 32 | - name: install haproxy ssl certificates 33 | copy: src=../../../{{item}} dest=/etc/ssl/private/{{item | basename}} 34 | with_items: haproxy_certificate_files 35 | tags: 36 | - ssl 37 | notify: reload haproxy 38 | - file: dest=/etc/ssl/private/default.pem src=/etc/ssl/private/{{ haproxy_certificate_files[0] | basename }} state=link 39 | when: (haproxy_certificate_files | length) > 0 40 | tags: 41 | - ssl 42 | notify: reload haproxy 43 | 44 | # open firewall ports 45 | - ufw: rule=allow port=443 proto=tcp 46 | - ufw: rule=allow port=80 proto=tcp 47 | 48 | # install misc 49 | - apt: pkg={{item}} 50 | with_items: 51 | - hatop 52 | - sysstat 53 | - iotop 54 | -------------------------------------------------------------------------------- /roles/compute/templates/bamboo-config.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "Marathon": { 3 | "Endpoint": " 4 | {%- for host in groups['mesos_masters'] -%} 5 | http://{{ host }}:5080{% if not loop.last %},{% endif %} 6 | {%- endfor -%} 7 | " 8 | }, 9 | 10 | "Bamboo": { 11 | "Endpoint": "http://{{private_ip}}:8000", 12 | "Zookeeper": { 13 | "Host": " 14 | {%- for host in groups['mesos_masters'] -%} 15 | {{ host }}:2181{% if not loop.last %},{% endif %} 16 | {%- endfor -%} 17 | ", 18 | "Path": "/bamboo", 19 | "ReportingDelay": 5 20 | } 21 | }, 22 | 23 | "HAProxy": { 24 | "TemplatePath": "/etc/bamboo/haproxy_template.cfg", 25 | "OutputPath": "/etc/haproxy/haproxy.cfg", 26 | "ReloadCommand": "read PIDS < /var/run/haproxy.pid; haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $PIDS && while ps -p $PIDS; do sleep 0.2; done" 27 | }, 28 | 29 | "StatsD": { 30 | "Enabled": false, 31 | "Host": "localhost:8125", 32 | "Prefix": "bamboo-server.development." 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /roles/compute/templates/haproxy_template.cfg.j2: -------------------------------------------------------------------------------- 1 | global 2 | log /dev/log local0 3 | log /dev/log local1 notice 4 | 5 | daemon 6 | maxconn 4096 7 | spread-checks 3 8 | chroot /var/lib/haproxy 9 | user haproxy 10 | group haproxy 11 | pidfile /var/run/haproxy.pid 12 | stats socket /run/haproxy/admin.sock mode 660 level admin 13 | 14 | ca-base /etc/ssl/certs 15 | crt-base /etc/ssl/private 16 | 17 | # 18 | # Ciphers following https://wiki.mozilla.org/Security/Server_Side_TLS 19 | # 20 | # Without backwards compatibility: 21 | ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK 22 | 23 | # With backwards compatibility: 24 | # ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK 25 | 26 | defaults 27 | log global 28 | mode http 29 | 30 | option dontlognull 31 | option redispatch 32 | option log-separate-errors 33 | option forceclose 34 | option tcp-smart-accept 35 | option tcp-smart-connect 36 | 37 | retries 3 38 | 39 | timeout connect 5s 40 | timeout client 1m 41 | timeout server 1m 42 | timeout check 3s 43 | timeout queue 3s 44 | 45 | errorfile 400 /etc/haproxy/errors/400.http 46 | errorfile 403 /etc/haproxy/errors/403.http 47 | errorfile 408 /etc/haproxy/errors/408.http 48 | errorfile 500 /etc/haproxy/errors/500.http 49 | errorfile 502 /etc/haproxy/errors/502.http 50 | errorfile 503 /etc/haproxy/errors/503.http 51 | errorfile 504 /etc/haproxy/errors/504.http 52 | 53 | frontend http-stats 54 | mode http 55 | bind *:3380 56 | 57 | stats enable 58 | stats uri / 59 | 60 | frontend http-in 61 | bind *:80 62 | 63 | tcp-request inspect-delay 5s 64 | tcp-request content accept if { req_ssl_hello_type 1 } 65 | 66 | option httplog 67 | option forwardfor 68 | 69 | http-request set-header X-Forwarded-Port %[dst_port] 70 | http-request add-header X-Forwarded-Proto https if { ssl_fc } 71 | 72 | log-format %ID\ %ci:%cp\ [%t]\ %ft\ %b/%s\ %Tq/%Tw/%Tc/%Tr/%Tt\ %ST\ %B\ %CC\ %CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %sq/%bq\ %hr\ %hs\ %{+Q}r\ %sslv\ %sslc 73 | unique-id-format %{+X}o\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid 74 | unique-id-header X-Request-ID 75 | 76 | {% raw %} 77 | {{ $services := .Services }}{{ range $index, $app := .Apps }}{{ if hasKey $services $app.Id }}{{ $service := getService $services $app.Id }} 78 | acl {{ $app.EscapedId }}-aclrule {{ $service.Acl}} 79 | use_backend {{ $app.EscapedId }}-cluster if {{ $app.EscapedId }}-aclrule 80 | {{ end }}{{ end }} 81 | {% endraw %} 82 | 83 | {% if (haproxy_certificate_files | length) > 0 %} 84 | {% raw %} 85 | frontend https-in 86 | bind *:443 ssl crt /etc/ssl/private/default.pem no-sslv3 87 | 88 | tcp-request inspect-delay 5s 89 | tcp-request content accept if { req_ssl_hello_type 1 } 90 | 91 | option httplog 92 | option forwardfor 93 | 94 | http-request set-header X-Forwarded-Port %[dst_port] 95 | http-request add-header X-Forwarded-Proto https if { ssl_fc } 96 | 97 | log-format %ID\ %ci:%cp\ [%t]\ %ft\ %b/%s\ %Tq/%Tw/%Tc/%Tr/%Tt\ %ST\ %B\ %CC\ %CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %sq/%bq\ %hr\ %hs\ %{+Q}r\ %sslv\ %sslc 98 | unique-id-format %{+X}o\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid 99 | unique-id-header X-Request-ID 100 | {% endraw %} 101 | {% endif %} 102 | 103 | {% raw %} 104 | {{ $services := .Services }}{{ range $index, $app := .Apps }}{{ if hasKey $services $app.Id }}{{ $service := getService $services $app.Id }} 105 | acl {{ $app.EscapedId }}-aclrule {{ $service.Acl}} 106 | use_backend {{ $app.EscapedId }}-cluster if {{ $app.EscapedId }}-aclrule 107 | {{ end }}{{ end }} 108 | {% endraw %} 109 | 110 | {% raw %} 111 | {{ range $index, $app := .Apps }} {{ if $app.Env.BAMBOO_TCP_PORT }} 112 | listen {{ $app.EscapedId }}-cluster-tcp :{{ $app.Env.BAMBOO_TCP_PORT }} 113 | mode tcp 114 | option tcplog 115 | balance roundrobin 116 | {{ range $page, $task := .Tasks }} 117 | server {{ $app.EscapedId}}-{{ $task.Host }}-{{ $task.Port }} {{ $task.Host }}:{{ $task.Port }} {{ if $app.HealthCheckPath }} check inter 30000 {{ end }} {{ end }} 118 | {{ end }} 119 | {{ if hasKey $services $app.Id }} 120 | backend {{ $app.EscapedId }}-cluster{{ if $app.HealthCheckPath }} 121 | option httpchk GET {{ $app.HealthCheckPath }} 122 | {{ end }} 123 | balance source 124 | option httpclose 125 | option forwardfor 126 | {{ range $page, $task := .Tasks }} 127 | server {{ $app.EscapedId }}-{{ $task.Host }}-{{ $task.Port }} {{ $task.Host }}:{{ $task.Port }}{{ if $app.HealthCheckPath }} check inter 10000{{ end }}{{ end }} 128 | {{ end }}{{ end }} 129 | {% endraw %} -------------------------------------------------------------------------------- /roles/consul/files/10-dns.json: -------------------------------------------------------------------------------- 1 | { 2 | "dns_config": { 3 | "allow_stale": true, 4 | "max_stale": "10s", 5 | "service_ttl": { 6 | "*": "2s" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /roles/consul/files/consul.conf: -------------------------------------------------------------------------------- 1 | description "Consul agent" 2 | 3 | start on runlevel [2345] 4 | stop on runlevel [!2345] 5 | 6 | respawn 7 | 8 | script 9 | # Make sure to use all our CPUs, because Consul can block a scheduler thread 10 | export GOMAXPROCS=`nproc` 11 | 12 | # Get the public IP of the first ethernet interface 13 | BIND=`ifconfig eth0 | grep "inet addr" | awk '{ print substr($2,6) }'` 14 | 15 | # Allow overriding env vars in /etc/default/consul 16 | if [ -f "/etc/default/consul" ]; then 17 | . /etc/default/consul 18 | fi 19 | 20 | exec /usr/local/bin/consul agent \ 21 | -config-dir="/etc/consul.d" \ 22 | -bind=$BIND \ 23 | ${CONSUL_FLAGS} 24 | end script -------------------------------------------------------------------------------- /roles/consul/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart consul 2 | service: name=consul state=restarted 3 | 4 | - name: restart dnsmasq 5 | service: name=dnsmasq state=restarted 6 | notify: restart registrator 7 | 8 | - name: restart registrator 9 | service: name=registrator state=restarted 10 | 11 | - name: run resolvconf 12 | shell: resolvconf -u 13 | -------------------------------------------------------------------------------- /roles/consul/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - apt_repository: repo='ppa:bcandrea/consul' state=absent 2 | - apt: pkg={{item}} state=absent 3 | with_items: 4 | - consul 5 | - consul-web-ui 6 | 7 | - file: name=/etc/consul state=directory 8 | - name: start consul in server mode 9 | copy: dest=/etc/consul.d/10-server.json content='{"server":true}' 10 | notify: restart consul 11 | when: consul_role == "server" 12 | - name: allow stale dns replies 13 | copy: src=10-dns.json dest=/etc/consul.d/10-dns.json 14 | notify: restart consul 15 | - name: disable server mode 16 | file: name=/etc/consul.d/10-server.json state=absent 17 | notify: restart consul 18 | when: consul_role != "server" 19 | - name: set data dir to /var/lib/consul 20 | copy: 'dest=/etc/consul.d/20-agent.json content={"data_dir":"/var/lib/consul"}' 21 | notify: restart consul 22 | - name: install consul upstart job 23 | copy: src=consul.conf dest=/etc/init/consul.conf 24 | notify: restart consul 25 | - name: install consul default 26 | template: src=default.j2 dest=/etc/default/consul 27 | notify: restart consul 28 | - name: install consul binary 29 | get_url: url=https://s3.amazonaws.com/hc-public/consul/0.5.0rc1/consul_linux_amd64_0.5.0rc1 dest=/usr/local/bin/consul mode=755 sha256sum=7d84fba71cc564fa46fcbea4888393aeb9a63b2ccba36ba3cecb82004c59540e 30 | notify: restart consul 31 | - service: name=consul state=started enabled=yes 32 | - meta: flush_handlers 33 | - name: join cluster in client mode 34 | shell: consul join {%for host in groups['mesos_masters']%} {%if host != inventory_hostname%}{{host}}{%endif%}{%endfor%} 35 | when: consul_role != "server" 36 | 37 | # redirect dns to consul 38 | - name: add consul forwarding to dnsmasq 39 | template: src=10-consul.j2 dest=/etc/dnsmasq.d/10-consul 40 | notify: restart dnsmasq 41 | 42 | -------------------------------------------------------------------------------- /roles/consul/templates/10-consul.j2: -------------------------------------------------------------------------------- 1 | server=/consul/127.0.0.1#8600 2 | {% for host in groups['mesos_masters'] %} 3 | {% if host != inventory_hostname %}server=/consul/{{ hostvars[host]['private_ip'] }}#8600{% endif %} 4 | 5 | {% endfor %} 6 | -------------------------------------------------------------------------------- /roles/consul/templates/default.j2: -------------------------------------------------------------------------------- 1 | # This file can be used to change the arguments 2 | # passed to the consul agent. 3 | 4 | # The default value for GOMAXPROCS (# of CPUs) can be 5 | # overridden explicitly here. 6 | #export GOMAXPROCS=2 7 | 8 | # The BIND variable can be used to specify the IP address 9 | # to be used for cluster communication. It defaults to the 10 | # IP address of eth0. 11 | BIND={{private_ip}} 12 | 13 | # Additional flags can be passed to the consul agent. It is 14 | # however preferable to edit configuration files under 15 | # /etc/consul.d instead. 16 | #CONSUL_FLAGS= 17 | -------------------------------------------------------------------------------- /roles/docker/defaults/main.yml: -------------------------------------------------------------------------------- 1 | docker_credentials: {} -------------------------------------------------------------------------------- /roles/docker/files/docker-cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # clean up containers > 24h old 4 | # taken from: https://forums.docker.com/t/tip-cleaning-up-old-containers/122 5 | docker inspect -f '{{.Id}},{{.State.Running}},{{.State.FinishedAt}}' $(docker ps -qa) | \ 6 | awk -F, 'BEGIN { TIME=strftime("%FT%T.000000000Z",systime()-60*60*24); } $2=="false" && $3 < TIME {print $1;}' | \ 7 | while read F; do docker rm $F >/dev/null || true; done 8 | 9 | # remove temporary built images 10 | docker images -f dangling=true --no-trunc | egrep '^' | awk '{print $3}' | while read F; do docker rmi $F >/dev/null || true; done 11 | 12 | # remove old volumes 13 | # taken from https://github.com/chadoe/docker-cleanup-volumes 14 | set -eo pipefail 15 | 16 | dockerdir=/var/lib/docker 17 | volumesdir=${dockerdir}/volumes 18 | vfsdir=${dockerdir}/vfs/dir 19 | allvolumes=() 20 | dryrun=false 21 | 22 | function delete_volumes() { 23 | targetdir=$1 24 | echo 25 | if [[ ! -d ${targetdir} ]]; then 26 | echo "Directory ${targetdir} does not exist, skipping." 27 | return 28 | fi 29 | echo "Delete unused volume directories from $targetdir" 30 | for dir in $(ls -d ${targetdir}/* 2>/dev/null) 31 | do 32 | dir=$(basename $dir) 33 | if [[ "${dir}" =~ [0-9a-f]{64} ]]; then 34 | if [[ ${allvolumes[@]} =~ "${dir}" ]]; then 35 | echo In use ${dir} 36 | else 37 | if [ "${dryrun}" = false ]; then 38 | echo Deleting ${dir} 39 | rm -rf ${targetdir}/${dir} 40 | else 41 | echo Would have deleted ${dir} 42 | fi 43 | fi 44 | else 45 | echo Not a volume ${dir} 46 | fi 47 | done 48 | } 49 | 50 | if [ $UID != 0 ]; then 51 | echo "You need to be root to use this script." 52 | exit 1 53 | fi 54 | 55 | docker_bin=$(which docker.io || which docker) 56 | if [ -z "$docker_bin" ] ; then 57 | echo "Please install docker. You can install docker by running \"wget -qO- https://get.docker.io/ | sh\"." 58 | exit 1 59 | fi 60 | 61 | if [ "$1" = "--dry-run" ]; then 62 | dryrun=true 63 | else if [ -n "$1" ]; then 64 | echo "Cleanup docker volumes: remove unused volumes." 65 | echo "Usage: ${0##*/} [--dry-run]" 66 | echo " --dry-run: dry run: display what would get removed." 67 | exit 1 68 | fi 69 | fi 70 | 71 | # Make sure that we can talk to docker daemon. If we cannot, we fail here. 72 | docker info >/dev/null 73 | 74 | #All volumes from all containers 75 | for container in `${docker_bin} ps -a -q --no-trunc`; do 76 | #add container id to list of volumes, don't think these 77 | #ever exists in the volumesdir but just to be safe 78 | allvolumes+=${container} 79 | #add all volumes from this container to the list of volumes 80 | for vid in `${docker_bin} inspect --format='{{range $vol, $path := .Volumes}}{{$path}}{{"\n"}}{{end}}' ${container}`; do 81 | if [[ "${vid##*/}" =~ [0-9a-f]{64} ]]; then 82 | allvolumes+=("${vid##*/}") 83 | fi 84 | done 85 | done 86 | 87 | delete_volumes ${volumesdir} 88 | delete_volumes ${vfsdir} -------------------------------------------------------------------------------- /roles/docker/files/docker-enter: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sttts/compute-platform/4cb9c62365023dc6f4aed0133ffdfcb1eb36f04f/roles/docker/files/docker-enter -------------------------------------------------------------------------------- /roles/docker/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart docker 2 | service: name=docker state=restarted 3 | 4 | - name: restart registrator 5 | service: name=registrator state=restarted 6 | 7 | - name: restart logspout 8 | service: name=logspout state=restarted 9 | 10 | - name: restart rsyslog 11 | service: name=rsyslog state=restarted 12 | -------------------------------------------------------------------------------- /roles/docker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - apt_key: id=A88D21E9 keyserver=hkp://keyserver.ubuntu.com:80 state=present 2 | - apt_repository: repo='deb http://get.docker.io/ubuntu docker main' state=present 3 | - apt: pkg=lxc-docker state=present 4 | - apt: pkg=python-pip state=present 5 | - pip: name=docker-py 6 | 7 | # install docker credential 8 | - template: src=dockercfg.j2 dest=/etc/.dockercfg mode=0600 9 | 10 | # needed for Docker plugin in Jenkins: 11 | - name: Listen for docker on localhost and point dns to local dnsmasq 12 | action: lineinfile dest=/etc/default/docker regexp=^#?DOCKER_OPTS=.* line='DOCKER_OPTS="${DOCKER_NETWORK_OPTS:---ip={{private_ip}}} -H 127.0.0.1:4243 -H unix:///var/run/docker.sock --dns {{private_ip}}"' 13 | notify: restart docker 14 | - meta: flush_handlers 15 | 16 | # install logspout to send docker log messages to the local rsyslog 17 | - name: load udp rsyslog module 18 | copy: content="$ModLoad imudp\n$UDPServerRun 514\n" dest=/etc/rsyslog.d/00-receive-udp.conf 19 | notify: restart rsyslog 20 | - meta: flush_handlers 21 | - docker_pull: repo=progrium/logspout 22 | notify: restart logspout 23 | - name: install logspout upstart job to send docker logs to fluentd 24 | template: src=logspout.conf.j2 dest=/etc/init/logspout.conf 25 | notify: restart logspout 26 | - service: name=logspout state=started enabled=true 27 | 28 | # start registrator to register every service in consul 29 | - docker_pull: repo=sttts/registrator 30 | notify: restart registrator 31 | - name: install registrator upstart job 32 | template: src=registrator.conf.j2 dest=/etc/init/registrator.conf 33 | notify: restart registrator 34 | - service: name=registrator state=started enabled=true 35 | 36 | # install cron-job to delete old containers and images 37 | - copy: src=docker-cleanup dest=/usr/local/sbin/docker-cleanup mode=0755 38 | - name: install cronjob to call /usr/local/sbin/docker-cleanup daily 39 | cron: name=docker-cleanup special_time=daily job=/usr/local/sbin/docker-cleanup 40 | 41 | # install docker-enter 42 | - copy: src=docker-enter dest=/usr/local/bin mode=0755 43 | -------------------------------------------------------------------------------- /roles/docker/templates/dockercfg.j2: -------------------------------------------------------------------------------- 1 | { 2 | {% for host, values in docker_credentials.iteritems() %} 3 | "{{ host }}": { 4 | "auth" : "{{ values['auth'] }}", 5 | "email" : "{{ values['email'] }}" 6 | }{% if not loop.last %},{% endif %} 7 | {% endfor %} 8 | } 9 | -------------------------------------------------------------------------------- /roles/docker/templates/logspout.conf.j2: -------------------------------------------------------------------------------- 1 | description "logspout container" 2 | author "Dr. Stefan Schimanski" 3 | start on filesystem and started docker 4 | stop on runlevel [!2345] 5 | respawn 6 | script 7 | /usr/bin/docker rm logspout || true 8 | trap "docker stop logspout; docker rm logspout" INT TERM 9 | /usr/bin/docker run \ 10 | -d -h {{inventory_hostname}} \ 11 | -v /var/run/docker.sock:/tmp/docker.sock \ 12 | --name logspout \ 13 | progrium/logspout syslog://172.17.42.1:514 14 | /usr/bin/docker start -a logspout 15 | end script 16 | -------------------------------------------------------------------------------- /roles/docker/templates/registrator.conf.j2: -------------------------------------------------------------------------------- 1 | description "registrator container" 2 | author "Dr. Stefan Schimanski" 3 | start on filesystem and started docker and started consul 4 | stop on runlevel [!2345] 5 | respawn 6 | script 7 | /usr/bin/docker rm registrator || true 8 | trap "docker stop registrator; docker rm registrator" INT TERM 9 | /usr/bin/docker run \ 10 | -d -h {{inventory_hostname}} \ 11 | -v /var/run/docker.sock:/tmp/docker.sock \ 12 | --name registrator \ 13 | sttts/registrator -internal consul://{{private_ip}}:8500 14 | /usr/bin/docker start -a registrator 15 | end script 16 | -------------------------------------------------------------------------------- /roles/glusterfs/tasks/client.yml: -------------------------------------------------------------------------------- 1 | - name: Install GlusterFS client 2 | apt: name=glusterfs-client 3 | 4 | - file: dest={{ glusterfs_mountpoint }} state=directory 5 | 6 | - name: Mount GlusterFS from localhost 7 | mount: name={{ glusterfs_mountpoint }} src={{ inventory_hostname }}:{{ glusterfs_volume }} fstype=glusterfs opts=defaults,_netdev,backupvolfile-server={{ groups[glusterfs_peer_group] | difference([inventory_hostname]) | first }} state=mounted 8 | when: inventory_hostname in groups[glusterfs_peer_group] 9 | 10 | - name: Mount GlusterFS from {{ glusterfs_volume }} 11 | mount: name={{ glusterfs_mountpoint }} src={{ groups[glusterfs_peer_group][0] }}:{{ glusterfs_volume }} fstype=glusterfs opts=defaults,_netdev,backupvolfile-server={{ groups[glusterfs_peer_group][1] }},noatime,nodiratime state=mounted 12 | when: not inventory_hostname in groups[glusterfs_peer_group] 13 | 14 | # following http://serverfault.com/questions/611462/glusterfs-failing-to-mount-at-boot-with-ubuntu-14-04 15 | - name: hotfix mount-glusterfs upstart job 16 | replace: dest=/etc/init/mounting-glusterfs.conf regexp='WAIT_FOR=static-network-up' replace='WAIT_FOR=networking' 17 | -------------------------------------------------------------------------------- /roles/glusterfs/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - apt_repository: repo='ppa:gluster/glusterfs-3.6' 2 | 3 | - include: "{{glusterfs_role}}.yml" -------------------------------------------------------------------------------- /roles/glusterfs/tasks/server.yml: -------------------------------------------------------------------------------- 1 | - name: Install GlusterFS server 2 | apt: name=glusterfs-server 3 | 4 | - name: Create GlusterFS brick 5 | file: path={{ glusterfs_brick_dir }} state=directory 6 | 7 | - name: Start GlusterFS server 8 | service: name=glusterfs-server state=started enabled=true 9 | 10 | - name: Configure peers from the first host 11 | command: gluster peer probe {{ item }} 12 | with_items: groups[glusterfs_peer_group] 13 | when: inventory_hostname == "{{ groups[glusterfs_peer_group][0] }}" 14 | ignore_errors: yes 15 | 16 | - name: Create {{glusterfs_volume}} glusterfs_volume 17 | shell: gluster volume info {{glusterfs_volume}} || (gluster volume create {{glusterfs_volume}} replica 3 transport tcp {{ groups[glusterfs_peer_group] | join(':' + glusterfs_brick_dir + ' ') }}:{{glusterfs_brick_dir}} force && gluster volume start {{glusterfs_volume}}) 18 | when: inventory_hostname == "{{ groups[glusterfs_peer_group][0] }}" 19 | -------------------------------------------------------------------------------- /roles/glusterfs/tasks/server_client.yml: -------------------------------------------------------------------------------- 1 | - include: server.yml 2 | - include: client.yml -------------------------------------------------------------------------------- /roles/glusterfs/vars/main.yml: -------------------------------------------------------------------------------- 1 | glusterfs_mountpoint: "/cluster" 2 | glusterfs_brick_dir: "/var/lib/cluster" 3 | glusterfs_volume: "cluster" 4 | glusterfs_peer_group: all 5 | glusterfs_role: "master_client" -------------------------------------------------------------------------------- /roles/mesos/defaults/main.yml: -------------------------------------------------------------------------------- 1 | mesos_cluster_name: cluster 2 | -------------------------------------------------------------------------------- /roles/mesos/files/logrotate-marathon: -------------------------------------------------------------------------------- 1 | /var/log/marathon.log { 2 | daily 3 | rotate 52 4 | missingok 5 | notifempty 6 | compress 7 | delaycompress 8 | postrotate 9 | invoke-rc.d rsyslog rotate >/dev/null 2>&1 || true 10 | endscript 11 | } 12 | -------------------------------------------------------------------------------- /roles/mesos/files/rsyslog-marathon: -------------------------------------------------------------------------------- 1 | if $programname == 'marathon' then { 2 | action(type="omfile" asyncWriting="on" file="/var/log/marathon.log") 3 | stop 4 | } -------------------------------------------------------------------------------- /roles/mesos/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart zookeeper 2 | service: name=zookeeper state=restarted 3 | 4 | - name: reload mesos-master 5 | service: name=mesos-master state=reloaded 6 | when: mesos_role == "master" or mesos_role == "master_slave" 7 | 8 | - name: restart mesos-master 9 | service: name=mesos-master state=restarted 10 | when: mesos_role == "master" or mesos_role == "master_slave" 11 | 12 | - name: reload mesos-slave 13 | service: name=mesos-slave state=reloaded 14 | when: mesos_role == "slave" or mesos_role == "master_slave" 15 | 16 | - name: restart mesos-slave 17 | service: name=mesos-slave state=restarted 18 | when: mesos_role == "slave" or mesos_role == "master_slave" 19 | 20 | - name: restart marathon 21 | service: name=marathon state=restarted 22 | 23 | - name: restart rsyslog 24 | service: name=rsyslog state=restarted 25 | -------------------------------------------------------------------------------- /roles/mesos/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: install mesosphere.io repository key 2 | apt_key: keyserver=keyserver.ubuntu.com id=e56151bf state=present 3 | - name: add mesosphere.io apt testing repository 4 | apt_repository: repo="deb http://repos.mesosphere.io/ubuntu trusty-testing main" state=present 5 | - name: add mesosphere.io apt repository 6 | apt_repository: repo="deb http://repos.mesosphere.io/ubuntu trusty main" state=present 7 | - apt: pkg=mesos 8 | 9 | - name: point mesos to all zookeeper instances 10 | template: src=zk.j2 dest=/etc/mesos/zk 11 | notify: reload mesos-slave 12 | notify: reload mesos-master 13 | - name: set mesos IP to private_ip 14 | lineinfile: dest=/etc/default/mesos regexp="IP=" line="IP={{private_ip}}" 15 | notify: restart mesos-slave 16 | notify: restart mesos-master 17 | 18 | - include: "{{mesos_role}}.yml" 19 | -------------------------------------------------------------------------------- /roles/mesos/tasks/master.yml: -------------------------------------------------------------------------------- 1 | - apt: pkg=marathon 2 | 3 | # setup zookeeper 4 | - name: set zoo_id to last digit of private IP 5 | copy: content="{{zoo_id}}" dest=/etc/zookeeper/conf/myid 6 | notify: restart zookeeper 7 | - template: src=zoo.cfg.j2 dest=/etc/zookeeper/conf/zoo.cfg 8 | notify: restart zookeeper 9 | - service: name=zookeeper state=started enabled=true 10 | 11 | # setup mesos-master 12 | - name: set mesos-master quorum to n/2+1 13 | copy: content="{{ (groups['mesos_masters'] | length) // 2 + 1 }}" dest=/etc/mesos-master/quorum 14 | notify: reload mesos-master 15 | - name: set mesos master hostname to public facing host address 16 | copy: dest=/etc/mesos-master/hostname content="{{public_host}}" 17 | notify: restart mesos-master 18 | - name: set mesos-master cluster name 19 | lineinfile: dest=/etc/default/mesos-master regexp="CLUSTER=" line="CLUSTER={{ mesos_cluster_name }}" 20 | notify: restart mesos-master 21 | - service: name=mesos-master state=started enabled=true 22 | 23 | # setup marathon 24 | - file: dest=/etc/marathon/conf state=directory 25 | - name: remove marathon master hostname setting 26 | file: name=/etc/marathon/conf/hostname state=absent 27 | notify: restart marathon 28 | - name: set marathon port to 5080 29 | copy: dest=/etc/marathon/conf/http_port content="5080" 30 | notify: restart marathon 31 | 32 | - name: set reconciliation_initial_delay to 30sec 33 | copy: dest=/etc/marathon/conf/reconciliation_initial_delay content="30000" 34 | notify: restart marathon 35 | 36 | - name: set reconciliation_interval to 30sec 37 | copy: dest=/etc/marathon/conf/reconciliation_interval content="30000" 38 | notify: restart marathon 39 | 40 | - name: enabled marathon task checkpoints 41 | copy: dest=/etc/marathon/conf/?checkpoint content="" 42 | notify: restart marathon 43 | - name: enable marathon http event_subscribers 44 | copy: dest=/etc/marathon/conf/event_subscriber content=http_callback 45 | notify: restart marathon 46 | - service: name=marathon state=started enabled=true 47 | - name: redirect logs to /var/log/marathon.log 48 | copy: src=rsyslog-marathon dest=/etc/rsyslog.d/30-marathon.conf 49 | notify: restart rsyslog 50 | - name: logrotate /var/log/marathon.log 51 | copy: src=logrotate-marathon dest=/etc/logrotate.d/marathon -------------------------------------------------------------------------------- /roles/mesos/tasks/master_slave.yml: -------------------------------------------------------------------------------- 1 | - include: master.yml 2 | - include: slave.yml -------------------------------------------------------------------------------- /roles/mesos/tasks/slave.yml: -------------------------------------------------------------------------------- 1 | - name: set docker as default mesos-slave containerizer 2 | copy: content="docker,mesos" dest=/etc/mesos-slave/containerizers 3 | notify: restart mesos-slave 4 | - name: set executor registration timeout for docker 5 | copy: content="5mins" dest=/etc/mesos-slave/executor_registration_timeout 6 | notify: restart mesos-slave 7 | - name: set slave node id 8 | copy: content="node_id:{{inventory_hostname}}" dest=/etc/mesos-slave/attributes 9 | notify: restart mesos-slave 10 | - name: enabled mesos-slave task checkpoints 11 | copy: dest=/etc/mesos-slave/?checkpoint content="" 12 | notify: restart mesos-slave 13 | - name: set the mesos task port range 14 | copy: dest=/etc/mesos-slave/resources content="ports(*):[{{ mesos_slave_ports | default(["31000-32000"]) | join(',') }}]" 15 | notify: restart mesos-slave 16 | - service: name=mesos-slave state=started enabled=true 17 | -------------------------------------------------------------------------------- /roles/mesos/templates/zk.j2: -------------------------------------------------------------------------------- 1 | zk:// 2 | {%- for host in groups['mesos_masters'] -%} 3 | {{ hostvars[host]['private_ip'] }}:2181{% if not loop.last %},{% endif %} 4 | {%- endfor -%} 5 | /mesos 6 | -------------------------------------------------------------------------------- /roles/mesos/templates/zoo.cfg.j2: -------------------------------------------------------------------------------- 1 | tickTime=2000 2 | dataDir=/var/lib/zookeeper/ 3 | clientPort=2181 4 | initLimit=5 5 | syncLimit=2 6 | {% for host in groups['mesos_masters'] %} 7 | server.{{ hostvars[host].zoo_id }}={{ host }}:2888:3888 8 | {% endfor %} 9 | -------------------------------------------------------------------------------- /roles/openvpn_gateway/defaults/main.yml: -------------------------------------------------------------------------------- 1 | openvpn_domain: example.com 2 | openvpn_search_domains: example.com 3 | openvpn_nameserver: "{{ private_ip }}" 4 | openvpn_route_netdev: eth0:0 5 | openvpn_route_netmask: "{{ private_netmask }}" 6 | openvpn_route_network: "{{ private_network }}" 7 | openvpn_cidr: 10.0.1.0/24 8 | openvpn_client_network: 10.128.0.0 9 | openvpn_client_netmask: 255.255.255.0 10 | -------------------------------------------------------------------------------- /roles/openvpn_gateway/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart openvpn 2 | service: name=openvpn state=restarted 3 | 4 | - name: restart ufw 5 | service: name=ufw state=restarted 6 | -------------------------------------------------------------------------------- /roles/openvpn_gateway/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - apt: pkg=openvpn 2 | - name: install openvpn server key 3 | copy: src=server.key dest=/etc/openvpn/ mode=0600 4 | notify: restart openvpn 5 | - name: install openvpn server certificate 6 | copy: src=server.crt dest=/etc/openvpn/ mode=0600 7 | notify: restart openvpn 8 | - name: install openvpn ca certificate 9 | copy: src=ca.crt dest=/etc/openvpn/ mode=0600 10 | notify: restart openvpn 11 | - name: install openvpn Diffie Hellmann key 12 | copy: src=dh2048.pem dest=/etc/openvpn/ mode=0600 13 | notify: restart openvpn 14 | - template: src=server.conf.j2 dest=/etc/openvpn/server.conf 15 | notify: restart openvpn 16 | - service: name=openvpn state=started enabled=true 17 | - name: open openvpn port 1194 in the firewall 18 | ufw: rule=allow port=1194 proto=tcp 19 | 20 | # setup NAT on openvpn subnet 21 | - name: enable ip forwarding 22 | lineinfile: name=/etc/ufw/sysctl.conf regexp="net/ipv4/ip_forward=1" line="net/ipv4/ip_forward=1" 23 | notify: restart ufw 24 | - name: enable ip forwarding in the firewall 25 | lineinfile: name=/etc/default/ufw regexp='DEFAULT_FORWARD_POLICY=' line='DEFAULT_FORWARD_POLICY="ACCEPT"' 26 | notify: restart ufw 27 | - name: enable masquerading from openvpn tun device to private lan 28 | shell: grep '*nat' /etc/ufw/before.rules || (echo "*nat\n:POSTROUTING ACCEPT - [0:0]\n-A POSTROUTING -s {{openvpn_cidr}} ! -o {{openvpn_route_netdev}} -j MASQUERADE\nCOMMIT\n" >> /etc/ufw/before.rules; ufw reload) 29 | notify: restart ufw -------------------------------------------------------------------------------- /roles/openvpn_gateway/templates/server.conf.j2: -------------------------------------------------------------------------------- 1 | port 1194 2 | proto tcp 3 | ;proto udp 4 | dev tun 5 | ca ca.crt 6 | cert server.crt 7 | key server.key 8 | dh dh2048.pem 9 | server {{openvpn_client_network}} {{openvpn_client_netmask}} 10 | ifconfig-pool-persist ipp.txt 11 | keepalive 10 120 12 | comp-lzo 13 | persist-key 14 | persist-tun 15 | status /var/log/openvpn-status.log 16 | verb 3 17 | 18 | push "dhcp-option DNS {{ openvpn_nameserver }}" 19 | push "dhcp-option DOMAIN {{ openvpn_domain }}" 20 | push "dhcp-option DOMAIN-SEARCH {{ openvpn_search_domains }}" 21 | push "dhcp-option DOMAIN-SEARCH {{ openvpn_domain }}" 22 | {% for route in openvpn_route_network %} 23 | push "route {{ route }} {{ openvpn_route_netmask[loop.index0] }}" 24 | {% endfor %} -------------------------------------------------------------------------------- /roles/papertrail/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart rsyslog 2 | service: name=rsyslog state=restarted 3 | -------------------------------------------------------------------------------- /roles/papertrail/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - get_url: url=https://papertrailapp.com/tools/papertrail-bundle.pem dest=/etc/papertrail-bundle.pem sha256sum=c03a504397dc45b4fc05f978dbf02129793cbd2a0b64856c2ba1bb49a3b9aacb mode=0644 2 | - apt: pkg=rsyslog-gnutls 3 | - template: src=papertrail.conf.j2 dest=/etc/rsyslog.d/10-papertrail.conf 4 | notify: restart rsyslog -------------------------------------------------------------------------------- /roles/papertrail/templates/papertrail.conf.j2: -------------------------------------------------------------------------------- 1 | $DefaultNetstreamDriverCAFile /etc/papertrail-bundle.pem # trust these CAs 2 | $ActionSendStreamDriver gtls # use gtls netstream driver 3 | $ActionSendStreamDriverMode 1 # require TLS 4 | $ActionSendStreamDriverAuthMode x509/name # authenticate by hostname 5 | $ActionSendStreamDriverPermittedPeer *.papertrailapp.com 6 | 7 | *.* @{{ papertrail_host }}.papertrailapp.com{% if papertrail_port %}:{{ papertrail_port }}{% endif %} 8 | -------------------------------------------------------------------------------- /roles/weave/defaults/main.yml: -------------------------------------------------------------------------------- 1 | weave_network_width: 8 2 | weave_cidr: "{{weave_ip}}/{{weave_network_width}}" 3 | weave_group: "all" -------------------------------------------------------------------------------- /roles/weave/files/weave.conf: -------------------------------------------------------------------------------- 1 | description "weave container" 2 | author "Dr. Stefan Schimanski" 3 | start on filesystem and started docker 4 | stop on runlevel [!2345] 5 | respawn 6 | script 7 | /usr/local/bin/weave launch 8 | docker wait weave 9 | end script 10 | -------------------------------------------------------------------------------- /roles/weave/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: start weave interface 2 | shell: ifdown weave || true && ifup weave 3 | 4 | - name: restart docker 5 | service: name=docker state=restarted 6 | 7 | - name: restart weave 8 | service: name=weave state=restarted 9 | -------------------------------------------------------------------------------- /roles/weave/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: install weave script from github 2 | get_url: url=https://raw.githubusercontent.com/sttts/weave/d77e3a4c226ab7803a947927a61da084de5162ca/weave force=yes dest=/usr/local/bin/weave sha256sum=cbd625236ce9e11db70cbf4ed209f2e83ba2d9df8bd34aecc271575ed736ad18 mode=755 3 | notify: start weave interface 4 | - name: setup weave network bridge and interface on boot 5 | template: src=interface.j2 dest=/etc/network/interfaces.d/weave 6 | notify: start weave interface 7 | - meta: flush_handlers 8 | 9 | - name: setup weave bridge in docker 10 | lineinfile: dest=/etc/default/docker regexp=^DOCKER_NETWORK_OPTS=.* insertbefore=^DOCKER_OPTS=.* line='DOCKER_NETWORK_OPTS="--bridge weave --fixed-cidr={{weave_container_cidr}}"' 11 | notify: restart docker 12 | - meta: flush_handlers 13 | 14 | - name: download weave router 15 | shell: /usr/local/bin/weave setup 16 | - name: install weave router upstart script 17 | copy: src=weave.conf dest=/etc/init/weave.conf 18 | notify: restart weave 19 | - name: start weave router 20 | service: name=weave state=started 21 | - meta: flush_handlers 22 | 23 | - name: connect weave to peers 24 | shell: /usr/local/bin/weave connect {{item}} || true 25 | when: inventory_hostname != item 26 | with_items: groups[weave_group] 27 | -------------------------------------------------------------------------------- /roles/weave/templates/interface.j2: -------------------------------------------------------------------------------- 1 | auto weave 2 | iface weave inet manual 3 | pre-up /usr/local/bin/weave create-bridge 4 | post-up ip addr add dev weave {{weave_cidr}} 5 | pre-down ifconfig weave down 6 | post-down brctl delbr weave 7 | --------------------------------------------------------------------------------