├── .github
└── CODEOWNERS
├── .gitignore
├── LICENSE
├── README.md
├── Vagrantfile
├── bootstrap
├── bootstrap_test
├── app_ctl.py
├── config.py
├── config.yaml
├── conftest.py
├── distribute_ssh_key.yaml
├── host_vars
│ └── test-nodes
├── pip-req.txt
├── prepare_demo_images.sh
├── test_bootstrap.py
└── test_ipaddr.py
├── download-consul.sh
├── playbooks
├── bootstrap-hosts
├── bootstrap.yaml
├── cluster
├── dep-graph.py
├── dep-graph2.py
├── host_vars
│ └── bootstrap-node
├── role.yaml
├── roles
│ ├── ansible_plugins
│ │ ├── files
│ │ │ └── plugins
│ │ │ │ └── callback
│ │ │ │ └── timestamp.py
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── backupd
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── backupd.service.j2
│ ├── binary
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-binary-stop
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-console-deploy
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-console-start
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-console-stop
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-console
│ │ └── meta
│ │ │ └── main.yaml
│ ├── bootstrap-docker
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-etcd
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── etcd.cron.j2
│ ├── bootstrap-firewall
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-images
│ │ └── vars
│ │ │ └── main.yaml
│ ├── bootstrap-layer0
│ │ └── meta
│ │ │ └── main.yaml
│ ├── bootstrap-layer1
│ │ └── meta
│ │ │ └── main.yaml
│ ├── bootstrap-registry-push
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-registry-start
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ ├── main.yaml
│ │ │ └── start.yaml
│ ├── bootstrap-registry-stop
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-registry
│ │ └── meta
│ │ │ └── main.yaml
│ ├── bootstrap-tinydns
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-webrouter-start
│ │ ├── files
│ │ │ └── nginx
│ │ │ │ ├── default.conf
│ │ │ │ ├── nginx.conf
│ │ │ │ └── proxy.conf
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── nginx
│ │ │ ├── console.conf.j2
│ │ │ └── registry.conf.j2
│ ├── bootstrap-webrouter-stop
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── bootstrap-webrouter
│ │ └── meta
│ │ │ └── main.yaml
│ ├── bootstrap
│ │ └── meta
│ │ │ └── main.yaml
│ ├── calico
│ │ ├── files
│ │ │ ├── calico.conf
│ │ │ ├── calico
│ │ │ │ ├── confd
│ │ │ │ │ ├── conf.d
│ │ │ │ │ │ ├── bird.toml.toml
│ │ │ │ │ │ ├── bird6.toml.toml
│ │ │ │ │ │ ├── bird6_ipam.toml
│ │ │ │ │ │ ├── custom_filters.toml
│ │ │ │ │ │ ├── custom_filters6.toml
│ │ │ │ │ │ └── tunl-ip.toml
│ │ │ │ │ ├── config
│ │ │ │ │ │ └── .gitkeep
│ │ │ │ │ └── templates
│ │ │ │ │ │ ├── bird6_ipam.cfg.template
│ │ │ │ │ │ ├── bird_aggr.cfg.template
│ │ │ │ │ │ ├── custom_filters.cfg.template
│ │ │ │ │ │ ├── custom_filters6.cfg.template
│ │ │ │ │ │ └── tunl-ip.template
│ │ │ │ └── profile.yml
│ │ │ └── service
│ │ │ │ ├── calico-bird.service
│ │ │ │ ├── calico-bird6.service
│ │ │ │ ├── calico-felix.service
│ │ │ │ └── calico-libnetwork.service
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── bird.cfg.mesh.template.j2
│ │ │ ├── bird.cfg.no-mesh.template.j2
│ │ │ ├── bird.toml.template.j2
│ │ │ ├── bird6.cfg.mesh.template.j2
│ │ │ ├── bird6.cfg.no-mesh.template.j2
│ │ │ ├── bird6.toml.template.j2
│ │ │ ├── bird6_aggr.toml.j2
│ │ │ ├── bird_aggr.toml.j2
│ │ │ ├── bird_ipam.cfg.template.j2
│ │ │ ├── bird_ipam.toml.j2
│ │ │ ├── calico-confd.service.j2
│ │ │ ├── calico.env.j2
│ │ │ ├── calicoctl.cfg.j2
│ │ │ ├── felix.cfg.j2
│ │ │ └── ippool.yml.j2
│ ├── ceph-fuse-new
│ │ ├── files
│ │ │ └── plugins
│ │ │ │ └── ceph_mon.py
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── ceph.client.lain.keyring.j2
│ │ │ └── ceph.conf.j2
│ ├── ceph-fuse
│ │ ├── files
│ │ │ └── plugins
│ │ │ │ └── ceph_mon.py
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── ceph.client.lain.keyring.j2
│ │ │ ├── ceph.conf.j2
│ │ │ └── cephmon.service.j2
│ ├── collectd
│ │ ├── files
│ │ │ ├── plugins
│ │ │ │ └── lain
│ │ │ │ │ ├── cluster_monitor.py
│ │ │ │ │ ├── deployd_monitor.py
│ │ │ │ │ ├── docker_daemon_monitor.py
│ │ │ │ │ ├── lain_docker.py
│ │ │ │ │ ├── lainlet_monitor.py
│ │ │ │ │ ├── node_monitor.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── procutils.py
│ │ │ │ │ └── rebellion_monitor.py
│ │ │ └── types
│ │ │ │ └── lain.db
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── collectd.conf.j2
│ │ │ ├── docker_daemon_monitor.conf.j2
│ │ │ ├── lain.conf.j2
│ │ │ ├── node_monitor.conf.j2
│ │ │ └── rebellion_monitor.conf.j2
│ ├── config
│ │ └── defaults
│ │ │ └── main.yaml
│ ├── console-deploy
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── console
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── consul
│ │ ├── files
│ │ │ └── consul.service
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── consul.json.j2
│ ├── cronjob
│ │ ├── files
│ │ │ └── clean_lainnode_image.py
│ │ └── tasks
│ │ │ └── main.yml
│ ├── deployd
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── deployd.service.j2
│ ├── docker-netstat
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── docker-netstat.service.j2
│ ├── docker-upgrade
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── docker-version
│ │ ├── defaults
│ │ │ └── main.yaml
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ ├── devicemapper.yaml
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── docker.j2
│ ├── docker
│ │ ├── files
│ │ │ ├── bootstrap-ubuntu-docker.sh
│ │ │ ├── docker-enter
│ │ │ └── docker-enter-comp
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ ├── devicemapper.yaml
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── daemon.json.j2
│ ├── drift-warm-up
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── drift
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── etcd-backup
│ │ ├── files
│ │ │ └── plugins
│ │ │ │ └── lain
│ │ │ │ └── etcd_backup
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── etcd_backup.service.j2
│ ├── etcd-moosefs
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ ├── build.yaml
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── data-lain-etcd_backup.mount.j2
│ ├── etcd
│ │ ├── files
│ │ │ └── etcdctl_comp
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ ├── etcd-reset.yaml
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── etcd.env.j2
│ │ │ └── etcd.service.j2
│ ├── firewall
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── iptables.save.j2
│ │ │ └── iptables.sh.j2
│ ├── images
│ │ ├── meta
│ │ │ └── main.yml
│ │ └── tasks
│ │ │ └── main.yml
│ ├── lainlet
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── lainlet.cron.j2
│ │ │ └── lainlet.service.j2
│ ├── libraries
│ │ └── library
│ │ │ ├── docker_check_images.py
│ │ │ ├── docker_inspect.py
│ │ │ ├── docker_pull_image.py
│ │ │ ├── docker_push.py
│ │ │ ├── etcd_prepare_update.py
│ │ │ ├── etcd_set_key.py
│ │ │ ├── get_app_proc_ip.py
│ │ │ ├── get_virtual_ip.py
│ │ │ ├── image_clean.py
│ │ │ ├── inspect_docker_network.py
│ │ │ ├── post_json.py
│ │ │ ├── set_config_domain.py
│ │ │ ├── set_tinydns_domain.py
│ │ │ ├── set_virtual_ip.py
│ │ │ └── set_virtual_ip_key.py
│ ├── lvault-app
│ │ └── meta
│ │ │ └── main.yaml
│ ├── manager
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── moosefs-build
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ ├── chunkserver.yaml
│ │ │ ├── main.yaml
│ │ │ ├── master.yaml
│ │ │ └── metalogger.yaml
│ │ └── templates
│ │ │ ├── config
│ │ │ ├── mfschunkserver.cfg.j2
│ │ │ ├── mfshdd.cfg.j2
│ │ │ ├── mfsmaster.cfg.j2
│ │ │ ├── mfsmetalogger.cfg.j2
│ │ │ └── mfsmount.cfg.j2
│ │ │ └── service
│ │ │ ├── mfscgiserv.service.j2
│ │ │ ├── mfschunkserver.service.j2
│ │ │ ├── mfsmaster.service.j2
│ │ │ └── mfsmetalogger.service.j2
│ ├── moosefs
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── mysql
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── network-recover
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── networkd-preupgrade
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── networkd-rollback
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── networkd-update
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── networkd-upgrade
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── networkd.service.j2
│ ├── networkd
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── networkd.service.j2
│ ├── node-change-labels
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── docker-daemon.json.j2
│ ├── node-clean
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ ├── image-clean.yaml
│ │ │ ├── log-clean.yaml
│ │ │ └── main.yaml
│ ├── node-disable-log-driver
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── docker-daemon.json.j2
│ ├── node
│ │ └── meta
│ │ │ └── main.yaml
│ ├── os-dependent-vars
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── vars
│ │ │ ├── CentOS.yml
│ │ │ └── Ubuntu.yml
│ ├── packages
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── prepare
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── rebellion-upgrade-2.0.x-to-v2.3.0
│ │ ├── files
│ │ │ └── clean_logs.py
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── rebellion.service.j2
│ ├── rebellion-upgrade
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── rebellion.service.j2
│ ├── rebellion
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── 10-docker-rsyslog.conf.j2
│ │ │ └── rebellion.service.j2
│ ├── registry-moosefs
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ ├── build.yaml
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ └── var-lib-registry.mount.j2
│ ├── registry
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ ├── main.yaml
│ │ │ └── push.yml
│ │ └── templates
│ │ │ ├── registry.j2
│ │ │ └── var-lib-registry.mount.j2
│ ├── remove-node
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── rsync
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── rsyncd.conf.j2
│ │ │ ├── rsyncd.secrets.j2
│ │ │ └── rsyncd.service.j2
│ ├── rsyslog-relocate
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── syslog-messages.conf.j2
│ │ │ └── syslog-messages.j2
│ ├── rsyslog
│ │ ├── files
│ │ │ └── rsyslog.conf
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── ssl
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ ├── ca.yaml
│ │ │ └── main.yaml
│ ├── swarm-manage
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ ├── main.yaml
│ │ │ └── swarm-manager.yaml
│ │ └── templates
│ │ │ ├── swarm-agent.service.j2
│ │ │ └── swarm-manager.service.j2
│ ├── swarm-upgrade
│ │ ├── handlers
│ │ │ └── main.yaml
│ │ ├── meta
│ │ │ └── main.yaml
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ │ ├── swarm-agent.service.j2
│ │ │ └── swarm-manager.service.j2
│ ├── swarm
│ │ └── meta
│ │ │ └── main.yaml
│ ├── systemd
│ │ ├── files
│ │ │ └── journald.conf.d
│ │ │ │ └── lain.conf
│ │ └── tasks
│ │ │ └── main.yaml
│ ├── webrouter-start
│ │ ├── meta
│ │ │ └── main.yaml
│ │ └── tasks
│ │ │ └── main.yaml
│ └── webrouter
│ │ ├── files
│ │ └── nginx
│ │ │ ├── default.conf
│ │ │ ├── nginx.conf
│ │ │ └── proxy.conf
│ │ └── tasks
│ │ └── main.yaml
└── site.yaml
└── prepare.sh
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # https://help.github.com/articles/about-codeowners/
2 | #
3 | * @bibaijin
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .DS_Store
4 | *.swp
5 | *.pyc
6 | env/
7 | lain_box/centos7
8 | lain_box/lain.box
9 | .ropeproject/
10 | examples/hello/Dockerfile
11 | playbooks/roles/binary/files/*
12 | */**/.gitignore
13 | **/.coverage
14 | /site/
15 | **/unittest.xml
16 | **/htmlcov
17 | *.gz
18 | *.bz2
19 | *.tar
20 | **/build
21 | **/dist
22 | **/*.egg-info
23 | venv/
24 | playbooks/bootstrap.retry
25 | playbooks/roles/calico-upgrade/files/bin
26 | playbooks/roles/calico/files/bin
27 | playbooks/roles/etcd/files/etcd
28 | playbooks/roles/etcd/files/etcdctl
29 | playbooks/roles/networkd-upgrade/files
30 | playbooks/roles/networkd/files
31 | playbooks/roles/lainlet/files
32 | playbooks/roles/deployd/files
33 | playbooks/roles/consul/files/bin
34 | playbooks/roles/etcd2consul/files/bin
35 | playbooks/roles/docker-netstat/files/bin
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 LAIN Cloud
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LAIN
2 |
3 | [](https://opensource.org/licenses/MIT)
4 | [](https://gitter.im/laincloud/opensource)
5 | [](https://waffle.io/laincloud/lain/metrics/throughput)
6 |
7 | Lain 是一个基于 Docker 的 PaaS 系统。
8 |
9 | 其面向技术栈多样寻求高效运维方案的高速发展中的组织,DevOps 人力缺乏的 startup ,个人开发者。
10 |
11 | 统一高效的开发工作流,降低应用运维复杂度;在 IaaS / 私有 IDC 裸机的基础上直接提供应用开发,集成,部署,运维的一揽子解决方案。
12 |
13 | 设计目标包括但不限于:
14 |
15 | - 降低系统管理复杂度
16 | - 简化服务的部署管理
17 | - 优化基础服务的调配
18 | - 提高资源的使用效率
19 | - 统一开发测试生产三环境
20 | - 持续交付工作流的良好支持
21 |
22 | ## Latest Release
23 |
24 | 最新版是2.1.1。
25 |
26 | - [下载](https://github.com/laincloud/lain/archive/v2.1.1.tar.gz)
27 | - [Release note](https://github.com/laincloud/lain/releases/tag/v2.1.1)
28 |
29 | ## Quick Start
30 |
31 | ```shell
32 | curl -fsSL https://github.com/laincloud/lain/archive/v2.1.1.tar.gz | tar xf -
33 | cd lain-2.1.1
34 | vagrant up
35 | # Config DNS in local shell
36 | sudo bash -c 'echo "192.168.77.201 console.lain.local" >> /etc/hosts'
37 | ```
38 |
39 | 初始化完成后即可在浏览器访问console:
40 | ```
41 | http://console.lain.local
42 | ```
43 |
44 | 完整的文档在[这里](https://laincloud.gitbooks.io/white-paper/content/),其中:
45 | - [Install](https://laincloud.gitbooks.io/white-paper/install/cluster.html) 展示了如何从头开始构建 Lain 集群
46 | - [LAIN App Demo](https://laincloud.gitbooks.io/white-paper/tutorial/first-lain-app.html) 展示了如何在 Lain 集群上部署应用
47 |
48 | ## Contributors
49 |
50 | - @[Qiangning Hong](https://github.com/hongqn)
51 | - @[Jia Mi](https://github.com/mijia)
52 | - @[flex](https://github.com/frostynova)
53 | - @[Tachikoma](https://github.com/sunyi00)
54 | - @[cloudfly](https://github.com/cloudfly)
55 | - @[BaiJian](https://github.com/ericpai)
56 | - @[Pan Li](https://github.com/panli889)
57 | - @[Meng Wenbin](https://github.com/supermeng)
58 | - @[chaoyiwang](https://github.com/wchaoyi)
59 | - @[Zhuoyun Wei](https://github.com/wzyboy)
60 | - @[Xu Tao](https://github.com/xtao)
61 | - @[Chang Cheng](https://github.com/uronce-cc)
62 | - @[Xu Yunnan](https://github.com/XuYunnan)
63 | - @[Zhang Kai](https://github.com/bibaijin)
64 | - @[Xu Zhuofu](https://github.com/ipush)
65 | - @[Luo Libin](https://github.com/onlymellb)
66 |
67 | ## LICENSE
68 |
69 | Lain is licensed under the [MIT license](LICENSE).
70 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | os_type = (ENV['OS_TYPE'] || "centos").downcase
2 |
3 | case os_type
4 | when "centos"
5 | Vagrant.configure(2) do |config|
6 | (1..3).each do |i|
7 | nodename = "node#{i}"
8 | config.vm.define nodename, primary: i == 1, autostart: i == 1 do |node|
9 | node.vm.box = "laincloud/centos-lain"
10 | node.vm.hostname = nodename
11 | node.vm.provider "virtualbox" do |v|
12 | v.memory = i == 1 ? 1536 : 768
13 | end
14 | if i == 1
15 | node.vm.provision "shell",
16 | inline: "sudo /vagrant/bootstrap "\
17 | "-m https://l2ohopf9.mirror.aliyuncs.com "\
18 | "-r docker.io/laincloud --vip=192.168.77.201"
19 | end
20 | node.vm.network "private_network", ip: "192.168.77.2#{i}"
21 | end
22 | end
23 | end
24 |
25 | when "ubuntu"
26 | ENV["LC_ALL"] = "C"
27 |
28 | unless Vagrant.has_plugin?("vagrant-disksize")
29 | puts "please install disksize plugin first."
30 | puts "cmd: vagrant plugin install vagrant-disksize"
31 | raise "vagrant-disksize is not isntalled."
32 | end
33 |
34 | Vagrant.configure(2) do |config|
35 | (1..3).each do |i|
36 | nodename = "node#{i}"
37 | config.vm.define nodename, primary: i == 1, autostart: i == 1 do |node|
38 | node.vm.box = "ubuntu/xenial64"
39 | node.vm.hostname = nodename
40 | node.disksize.size = '30GB'
41 | node.vm.provider "virtualbox" do |v|
42 | v.memory = i == 1 ? 1536 : 768
43 | end
44 |
45 | if i == 1
46 | node.vm.provision "shell",
47 | inline: "sudo python3 /vagrant/bootstrap "\
48 | "-m https://l2ohopf9.mirror.aliyuncs.com "\
49 | "-r docker.io/laincloud --vip=192.168.77.201"
50 | else
51 | node.vm.provision "shell",
52 | inline: "sed -i 's/^PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config && "\
53 | "systemctl restart sshd &&" \
54 | "echo 'root:vagrant' | chpasswd &&" \
55 | "sed -i s/archive.ubuntu.com/mirrors.ustc.edu.cn/g /etc/apt/sources.list && " \
56 | "apt update && apt install -y python"
57 | end
58 | node.vm.network "private_network", ip: "192.168.77.2#{i}"
59 | end
60 | end
61 | end
62 | else
63 | puts "invalid os type"
64 | end
65 |
--------------------------------------------------------------------------------
/bootstrap_test/app_ctl.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | # -*- coding: UTF-8 -*-
3 |
4 | import requests
5 | from config import CONFIG
6 |
7 |
8 | def reposit(app_name):
9 | url = "http://" + CONFIG.vip + CONFIG.console_api_repos
10 | payload = {"appname": app_name}
11 | headers = {
12 | "Host": CONFIG.console_hostname,
13 | "Content-Type": "application/json"
14 | }
15 | return requests.post(url, json=payload, headers=headers)
16 |
17 |
18 | def deploy(app_name):
19 | url = "http://" + CONFIG.vip + CONFIG.console_api_apps
20 | payload = {"appname": app_name}
21 | headers = {
22 | "Host": CONFIG.console_hostname,
23 | "Content-Type": "application/json"
24 | }
25 | return requests.post(url, json=payload, headers=headers)
26 |
27 |
28 | def delete(app_name):
29 | url = "http://" + CONFIG.vip + CONFIG.console_api_apps + app_name + "/"
30 | headers = {"Host": CONFIG.console_hostname}
31 | return requests.delete(url, headers=headers)
32 |
33 |
34 | def scale(app_name, proc_name, num_instances):
35 | url = "http://" + CONFIG.vip + CONFIG.console_api_apps + app_name + \
36 | "/procs/" + proc_name + "/"
37 | payload = {"num_instances": num_instances}
38 | headers = {
39 | "Host": CONFIG.console_hostname,
40 | "Content-Type": "application/json"
41 | }
42 | return requests.patch(url, json=payload, headers=headers)
43 |
44 |
45 | def get_proc_info(app_name, proc_name):
46 | url = "http://" + CONFIG.vip + CONFIG.console_api_apps + app_name + \
47 | "/procs/" + proc_name + "/"
48 | headers = {"Host": CONFIG.console_hostname}
49 | return requests.get(url, headers=headers)
50 |
--------------------------------------------------------------------------------
/bootstrap_test/config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | # -*- coding: UTF-8 -*-
3 |
4 | import os
5 | import yaml
6 |
7 |
8 | class Config(object):
9 | def __init__(self):
10 | config_file_path = os.path.join(os.path.dirname(__file__),
11 | 'config.yaml')
12 | with open(config_file_path, 'r') as f:
13 | self._config = yaml.safe_load(f)
14 |
15 | @property
16 | def vip(self):
17 | return self._config["vip"]
18 |
19 | @property
20 | def domain(self):
21 | return self._config["domain"]
22 |
23 | @property
24 | def console_hostname(self):
25 | return "console." + self.domain
26 |
27 | @property
28 | def registry_hostname(self):
29 | return "registry." + self.domain
30 |
31 | @property
32 | def console_api_repos(self):
33 | return self._config["console_api"]["repos"]
34 |
35 | @property
36 | def console_api_apps(self):
37 | return self._config["console_api"]["apps"]
38 |
39 | @property
40 | def ipaddr(self):
41 | return self._config["ipaddr"]
42 |
43 | @property
44 | def ipaddr_service_appname(self):
45 | return self.ipaddr["service"]["appname"]
46 |
47 | @property
48 | def ipaddr_resource_appname(self):
49 | return self.ipaddr["resource"]["appname"]
50 |
51 | @property
52 | def ipaddr_client_appname(self):
53 | return self.ipaddr["client"]["appname"]
54 |
55 | @property
56 | def ipaddr_client_procname(self):
57 | return self.ipaddr["client"]["procname"]
58 |
59 | @property
60 | def ipaddr_client_num_instances(self):
61 | return self.ipaddr["client"]["num_instances"]
62 |
63 | @property
64 | def ipaddr_client_hostname(self):
65 | return self.ipaddr_client_appname + "." + self.domain
66 |
67 |
68 | CONFIG = Config()
69 |
--------------------------------------------------------------------------------
/bootstrap_test/config.yaml:
--------------------------------------------------------------------------------
1 | vip: 192.168.77.201
2 | domain: lain.local
3 | console_api:
4 | repos: /api/v1/repos/
5 | apps: /api/v1/apps/
6 |
7 | ipaddr:
8 | resource:
9 | appname: ipaddr-resource
10 | service:
11 | appname: ipaddr-service
12 | client:
13 | appname: ipaddr-client
14 | procname: web
15 | num_instances: 2
16 |
--------------------------------------------------------------------------------
/bootstrap_test/distribute_ssh_key.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localhost
3 | tasks:
4 | - name: install sshpass
5 | package: name=sshpass state=latest
6 |
7 | - hosts: test_nodes
8 | gather_facts: no
9 | tasks:
10 | - name: examine whether new nodes in known_hosts
11 | local_action: command grep '{{ ansible_ssh_host }}' /root/.ssh/known_hosts
12 | register: exists
13 | ignore_errors: True
14 | changed_when: False
15 | - name: collect the public keys of new nodes
16 | local_action: shell ssh-keyscan -p {{ ansible_ssh_port|default(22) }} {{ ansible_ssh_host }}
17 | register: result
18 | when: exists|failed
19 | - name: add the public keys of new nodes to known_hosts
20 | local_action: known_hosts path='/root/.ssh/known_hosts' host={{ ansible_ssh_host }} key="{{ result.stdout }}"
21 | when: exists|failed
22 |
23 | - hosts: test_nodes
24 | tasks:
25 | - name: upload public key to new nodes
26 | authorized_key: user=root key="{{ lookup('file', '/root/.ssh/lain.pub') }}"
27 |
--------------------------------------------------------------------------------
/bootstrap_test/host_vars/test-nodes:
--------------------------------------------------------------------------------
1 | [test_nodes]
2 | node2 ansible_ssh_port=22 ansible_ssh_host=192.168.77.22 ansible_ssh_pass=vagrant
3 | node3 ansible_ssh_port=22 ansible_ssh_host=192.168.77.23 ansible_ssh_pass=vagrant
4 |
--------------------------------------------------------------------------------
/bootstrap_test/pip-req.txt:
--------------------------------------------------------------------------------
1 | pytest==3.0.5
2 | requests==2.12.4
3 | subprocess32==3.2.6
4 | pyyaml==3.12
5 | retrying==1.3.3
6 |
--------------------------------------------------------------------------------
/bootstrap_test/prepare_demo_images.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DOMAIN=$1
4 |
5 | [[ -n "$DOMAIN" ]] || DOMAIN=lain.local
6 |
7 | BOOTSTRAP_REG=$2
8 |
9 | [[ -n "$BOOTSTRAP_REG" ]] || BOOTSTRAP_REG=registry.aliyuncs.com
10 |
11 |
12 | IMAGES=(
13 | ipaddr-service:meta-1462790282-60f77d22799d8823ef771faef97897d60ca9c4b1
14 | ipaddr-service:release-1462790282-60f77d22799d8823ef771faef97897d60ca9c4b1
15 | ipaddr-resource:meta-1462784153-944220ca13e9aae08412875990686e18b71bff9e
16 | ipaddr-resource:release-1462784153-944220ca13e9aae08412875990686e18b71bff9e
17 | ipaddr-client:meta-1481187933-05da018887e967144f7d481b7ef160cb173973de
18 | ipaddr-client:release-1481187933-05da018887e967144f7d481b7ef160cb173973de
19 | );
20 |
21 |
22 | function pull_push()
23 | {
24 | IMAGE=$1
25 | BOOTSTRAP_IMAGE="${BOOTSTRAP_REG}/laincloud/${IMAGE}"
26 | TARGET_IMAGE="registry.${DOMAIN}/${IMAGE}"
27 | sudo docker pull ${BOOTSTRAP_IMAGE}
28 | sudo docker tag ${BOOTSTRAP_IMAGE} ${TARGET_IMAGE}
29 | sudo docker push ${TARGET_IMAGE}
30 | sudo docker rmi ${BOOTSTRAP_IMAGE}
31 | }
32 |
33 | for i in "${IMAGES[@]}"
34 | do
35 | pull_push $i
36 | done
37 |
--------------------------------------------------------------------------------
/bootstrap_test/test_bootstrap.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | # -*- coding: UTF-8 -*-
3 |
4 | import requests
5 |
6 | from config import CONFIG
7 |
8 |
9 | def test_registry_service(bootstrap):
10 | # verify return 200
11 | url = "http://" + CONFIG.vip + "/v2/"
12 | headers = {"Host": CONFIG.registry_hostname}
13 | req = requests.get(url, headers=headers)
14 | assert req.status_code == 200
15 |
16 | # verify there is something in registry
17 | url += "_catalog"
18 | req = requests.get(url, headers=headers)
19 | assert len(req.json()["repositories"]) > 0
20 |
21 |
22 | def test_console_service(bootstrap):
23 | url = "http://" + CONFIG.vip + CONFIG.console_api_apps + "console/"
24 | headers = {"Host": CONFIG.console_hostname}
25 | req = requests.get(url, headers=headers)
26 | assert req.status_code == 200
27 |
--------------------------------------------------------------------------------
/bootstrap_test/test_ipaddr.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | # -*- coding: UTF-8 -*-
3 |
4 | import requests
5 | import app_ctl
6 | from config import CONFIG
7 | from retrying import retry
8 |
9 | @retry(stop_max_attempt_number=20, wait_fixed=10000)
10 | def test_client_is_working(deploy_ipaddr):
11 | url = "http://" + CONFIG.vip
12 | headers = {"Host": CONFIG.ipaddr_client_hostname}
13 | req = requests.get(url, headers=headers)
14 | assert req.status_code == 200
15 |
16 | @retry(stop_max_attempt_number=20, wait_fixed=10000)
17 | def test_client_is_scaled(scale_ipaddr_client):
18 | req = app_ctl.get_proc_info(CONFIG.ipaddr_client_appname,
19 | CONFIG.ipaddr_client_procname)
20 | assert len(req.json()['proc']['pods']) == CONFIG.ipaddr_client_num_instances
21 |
--------------------------------------------------------------------------------
/download-consul.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | mkdir -p playbooks/roles/consul/files/bin
4 |
5 | mkdir -p playbooks/roles/etcd2consul/files/bin
6 |
7 | wget -c https://releases.hashicorp.com/consul/0.8.5/consul_0.8.5_linux_amd64.zip -O playbooks/roles/consul/files/bin/consul_0.8.5_linux_amd64.zip
8 |
9 | wget -c https://github.com/laincloud/etcd2consul/releases/download/v0.0.1/etcd2consul.xz -O playbooks/roles/etcd2consul/files/bin/etcd2consul.xz
10 |
11 | unzip -o playbooks/roles/consul/files/bin/consul_0.8.5_linux_amd64.zip -d playbooks/roles/consul/files/bin
12 |
13 | unxz -kf playbooks/roles/etcd2consul/files/bin/etcd2consul.xz
14 |
--------------------------------------------------------------------------------
/playbooks/bootstrap-hosts:
--------------------------------------------------------------------------------
1 | bootstrap-node ansible_connection=local
2 |
--------------------------------------------------------------------------------
/playbooks/bootstrap.yaml:
--------------------------------------------------------------------------------
1 | - hosts: bootstrap-node
2 | vars:
3 | bootstrapping: yes
4 |
5 | roles:
6 | - "{{ role|default('bootstrap') }}"
7 |
--------------------------------------------------------------------------------
/playbooks/dep-graph.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Draw a dependency graph for all the roles."""
4 |
5 | import sys
6 | import os
7 | import yaml
8 |
9 | here = os.path.abspath(os.path.dirname(__file__))
10 |
11 |
12 | def main():
13 | roles = os.listdir(os.path.join(here, 'roles'))
14 | print("digraph G {")
15 |
16 | for role in roles:
17 | meta_paths = [os.path.join(here, 'roles', role, 'meta', x)
18 | for x in ['main.yaml', 'main.yml']]
19 | for meta_path in meta_paths:
20 | if os.path.exists(meta_path):
21 | meta = yaml.safe_load(open(meta_path).read())
22 | for dependency in meta.get('dependencies', []):
23 | dep = dependency if isinstance(dependency, str) else dependency['role']
24 | print('"{}" -> "{}"'.format(role, dep))
25 | break
26 | print("}")
27 |
28 |
29 | if __name__ == '__main__':
30 | sys.exit(main())
31 |
--------------------------------------------------------------------------------
/playbooks/dep-graph2.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Draw a dependency graph for all the roles."""
4 |
5 | import sys
6 | import os
7 | import yaml
8 |
9 | CWD = os.path.abspath(os.path.dirname(__file__))
10 | ENTRY = 'bootstrap'
11 | SEEN = set()
12 | HIDE_SEEN = True
13 |
14 |
15 | def get_dep_roles(role_name):
16 | meta_paths = [
17 | os.path.join(CWD, 'roles', role_name, 'meta', main_yaml)
18 | for main_yaml in ['main.yaml', 'main.yml']
19 | ]
20 | meta_path = next((mp for mp in meta_paths if os.path.exists(mp)), None)
21 | if not meta_path:
22 | return None
23 | meta = yaml.safe_load(open(meta_path).read())
24 | deps = meta.get('dependencies', [])
25 | dep_roles = [
26 | d if isinstance(d, str)
27 | else d['role']
28 | for d in deps
29 | ]
30 | return dep_roles
31 |
32 |
33 | def draw_dep_roles(dep_roles, level, hide_seen=HIDE_SEEN):
34 | for dep_role in dep_roles:
35 | if hide_seen and dep_role in SEEN:
36 | continue
37 | print('{}- {}'.format(' ' * (level + 1), dep_role))
38 | SEEN.add(dep_role)
39 | next_dep_roles = get_dep_roles(dep_role)
40 | if not next_dep_roles:
41 | continue
42 | draw_dep_roles(next_dep_roles, level + 1)
43 |
44 |
45 | def main(entry=ENTRY):
46 | print(ENTRY)
47 | dep_roles = get_dep_roles(entry)
48 | draw_dep_roles(dep_roles, 0)
49 |
50 |
51 | if __name__ == '__main__':
52 | sys.exit(main())
53 |
--------------------------------------------------------------------------------
/playbooks/host_vars/bootstrap-node:
--------------------------------------------------------------------------------
1 | is_lain_manager: true
2 | is_swarm_manager: true
3 | is_deployd_node: true
4 |
5 | is_etcd_member: true
6 | is_consul_server: true
7 | etcd_members:
8 | - name: "{{ node_name }}"
9 | ip: "{{ node_ip }}"
10 | consul_servers:
11 | - "{{ node_ip }}"
12 |
13 | allow_restart_docker: yes
14 |
--------------------------------------------------------------------------------
/playbooks/role.yaml:
--------------------------------------------------------------------------------
1 | - hosts: "{{ target|default('nodes') }}"
2 | roles:
3 | - "{{ role }}"
4 |
--------------------------------------------------------------------------------
/playbooks/roles/ansible_plugins/files/plugins/callback/timestamp.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from ansible.plugins.callback import CallbackBase
4 |
5 |
6 | class CallbackModule(CallbackBase):
7 | """Show timestamp and time cost for each task run."""
8 |
9 | def __init__(self):
10 | super(CallbackModule, self).__init__()
11 |
12 | self.timestamp = datetime.now()
13 |
14 | def playbook_on_task_start(self, name, is_conditional):
15 | now = datetime.now()
16 | self._display.display("{} (last task costs {})".format(now, now - self.timestamp))
17 | self.timestamp = now
18 |
--------------------------------------------------------------------------------
/playbooks/roles/ansible_plugins/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - copy: src=plugins/ dest=/usr/share/ansible/plugins/
2 |
--------------------------------------------------------------------------------
/playbooks/roles/backupd/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for backupd
2 | command: systemctl daemon-reload
3 |
4 | - name: restart backupd
5 | service: name=backupd state=restarted
6 |
--------------------------------------------------------------------------------
/playbooks/roles/backupd/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 | - role: images
5 | images:
6 | - backupctl
7 | - role: console-deploy
8 | app: backupctl
9 | when: is_lain_manager
10 |
--------------------------------------------------------------------------------
/playbooks/roles/backupd/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - fail: msg="moosefs not exist yet"
2 | when: mfsmaster=="" and backupd_driver=="moosefs"
3 |
4 | - name: check if backupd container exists
5 | command: docker inspect backupd-binary
6 | register: result
7 | ignore_errors: yes
8 | changed_when: False
9 |
10 | - name: create backupd binary container
11 | command: docker create --name backupd-binary {{ backupd_image }} /bin/bash
12 | when: result|failed
13 |
14 | - name: copy backupd binary to local /usr/bin
15 | command: docker cp backupd-binary:/usr/bin/backupd /tmp/backupd
16 |
17 | - name: remove the backupd-binary container
18 | command: docker rm -f backupd-binary
19 |
20 | - name: get stat of old backupd
21 | stat: path=/usr/bin/backupd
22 | register: ostat
23 | ignore_errors: yes
24 |
25 | - name: get stat of new backupd
26 | stat: path=/tmp/backupd
27 | register: nstat
28 | ignore_errors: yes
29 |
30 | - name: stop backupd service
31 | service: name=backupd state=stopped
32 | when: ostat.stat.exists
33 |
34 | - name: update backupd
35 | shell: cp /tmp/backupd /usr/bin/backupd && chmod +x /usr/bin/backupd
36 | register: binary_result
37 | when: ostat|failed or nstat|failed or "{{ostat.stat.md5|default('old')}}" != "{{nstat.stat.md5|default('new')}}"
38 |
39 | - name: install rsync
40 | package: name=rsync state=present
41 |
42 | - name: create backup directory
43 | file: path="{{ backup_dir }}/{{ node_ip }}" state=directory
44 | when: backupd_driver == "moosefs" and is_lain_manager
45 |
46 | - name: set the backup dir's trashtimeout on moosefs
47 | command: mfssettrashtime -r 3600 {{ backup_dir }}
48 | when: backupd_driver == "moosefs" and is_lain_manager
49 |
50 | - name: add backupd to service
51 | template: src=backupd.service.j2 dest=/etc/systemd/system/backupd.service
52 | register: service_result
53 | notify:
54 | - reload systemd for backupd
55 |
56 | - meta: flush_handlers
57 |
58 | - name: restart backupd
59 | service: name=backupd state=restarted
60 | when: (binary_result is defined and binary_result|success) or service_result|success
61 |
62 | - name: ensure backupd service started
63 | service: name=backupd enabled=yes state=started
64 |
65 | - name: config etcd to tag backup_enabled
66 | command: etcdctl set /lain/config/backup_enabled True
67 | when: is_lain_manager
68 |
--------------------------------------------------------------------------------
/playbooks/roles/backupd/templates/backupd.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=backupd
3 | After=network.target
4 |
5 | [Service]
6 | User=root
7 | ExecStart=/usr/bin/backupd daemon \
8 | -addr :{{ backupd_port }} \
9 | -ip {{ node_ip }} \
10 | -backup-driver {{ backupd_driver }} \
11 | -backup-moosefs-dir {{ backup_dir }}
12 | Restart=always
13 |
14 | [Install]
15 | WantedBy=multi-user.target
16 |
--------------------------------------------------------------------------------
/playbooks/roles/binary/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: copy bootstrap binary to /tmp
2 | copy: src=lain dest=/tmp/
3 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-binary-stop/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: get stat of old lainlet
2 | stat: path=/usr/bin/lainlet
3 | register: lainlet
4 | ignore_errors: yes
5 |
6 | - name: stop lainlet service
7 | service: name=lainlet state=stopped
8 | when: lainlet.stat.exists
9 |
10 | - name: get stat of old deployd
11 | stat: path=/usr/bin/deployd
12 | register: deployd
13 | ignore_errors: yes
14 |
15 | - name: stop deployd service
16 | service: name=deployd state=stopped
17 | when: deployd.stat.exists
18 |
19 | - name: test if networkd binary path exists
20 | stat: path=/usr/bin/networkd
21 | register: networkd
22 | ignore_errors: yes
23 |
24 | - name: stop networkd service
25 | service: name=networkd enabled=yes state=stopped
26 | when: networkd.stat.exists
27 |
28 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-console-deploy/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-console
3 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-console-deploy/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: check if app already deployed
2 | command: etcdctl ls /lain/deployd/pod_groups/{{ app }}
3 | register: result
4 | ignore_errors: yes
5 | changed_when: False
6 |
7 | - name: reposit app
8 | post_json:
9 | url: http://localhost:{{ bootstrap_console_port }}/api/v1/repos/
10 | body:
11 | appname: "{{ app }}"
12 | when: result|failed
13 |
14 | - name: deploy app
15 | post_json:
16 | url: http://localhost:{{ bootstrap_console_port }}/api/v1/apps/
17 | body:
18 | appname: "{{ app }}"
19 | when: result|failed
20 |
21 | - name: check app deployed
22 | shell: "curl -s console.lain/api/v1/apps/{{ app }}/ | python -c \"import json, sys; print json.load(sys.stdin)['app']['procs'][0]['pods'][0]['containerid']\""
23 | register: container_id
24 | until: container_id|success
25 | retries: 50
26 | delay: 5
27 | changed_when: False
28 |
29 | - name: remove bootstrap-webrouter nginx config
30 | file: path={{ bootstrap_volumes_dir }}/webrouter/nginx/etc/nginx/bootstrap/{{ app }}.lain.conf state=absent
31 | register: result
32 |
33 | - name: reload bootstrap-webrouter
34 | command: docker exec bootstrap-webrouter nginx -s reload
35 | when: result|changed
36 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-console-start/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-console
3 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-console-start/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: prepare volume dirs
2 | file: path={{ bootstrap_volumes_dir }}/console/{{ item }} state=directory
3 | with_items:
4 | - web/externalbin
5 | - web/lain/app/logs
6 |
7 | - name: copy volume files
8 | copy: src={{ item.src }} dest={{ bootstrap_volumes_dir }}/console/{{ item.dest }} mode={{ item.mode }}
9 | with_items:
10 | - src: /usr/bin/calicoctl
11 | dest: web/externalbin/calicoctl
12 | mode: "0755"
13 |
14 | - name: inspect bootstrap-console
15 | docker_inspect: name=bootstrap-console
16 | register: inspect_console
17 | ignore_errors: yes
18 |
19 | - name: remove deprected bootstrap-console
20 | command: docker rm -f bootstrap-console
21 | when: inspect_console|success and not inspect_console.State.Running
22 |
23 | - name: run bootstrap-console
24 | command: >
25 | docker run -d
26 | --name bootstrap-console
27 | -p {{ bootstrap_console_port }}:8000
28 | -v {{ bootstrap_volumes_dir }}/console/web/externalbin:/externalbin
29 | -v {{ bootstrap_volumes_dir }}/console/web/lain/app/logs:/lain/app/logs
30 | {{ bootstrap_console_image }}
31 | ./entry.sh
32 | when: inspect_console|failed or not inspect_console.State.Running
33 |
34 | - name: wait for console ready
35 | wait_for: host=localhost port={{ bootstrap_console_port }} timeout=10
36 |
37 | # vim: set filetype=ansible.yaml:
38 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-console-stop/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-console
3 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-console-stop/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: stop bootstrap-console
2 | docker:
3 | image: "{{ bootstrap_console_image }}"
4 | name: bootstrap-console
5 | state: absent
6 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-console/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 | - role: docker
5 | - role: packages
6 | - role: etcd
7 | - role: bootstrap-registry
8 | action: start
9 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-docker/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: bootstrap-images
4 | - role: libraries
5 | - role: docker
6 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-docker/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: check if all images exist
2 | docker_check_images:
3 | images: "{{ bootstrap_images.values() }}"
4 | register: check
5 | ignore_errors: yes
6 | changed_when: False
7 |
8 | - name: load saved images (this may take minutes...)
9 | shell: xz -d -c {{ saved_images }} | docker load
10 | when: check|failed and saved_images is defined
11 | register: load
12 |
13 | - name: check if all images exist, again
14 | docker_check_images:
15 | images: "{{ bootstrap_images.values() }}"
16 | register: check
17 | ignore_errors: yes
18 | changed_when: False
19 |
20 | - name: pull images if not exists (use --saved-images option if your connection to DockerHub is very slow)
21 | docker_pull_image: image={{ item }} registry={{ registry_bootstrap|default('') }}
22 | with_items: "{{ bootstrap_images.values() }}"
23 | when: check|failed
24 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-etcd/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-binary-stop
3 | - role: etcd
4 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-etcd/templates/etcd.cron.j2:
--------------------------------------------------------------------------------
1 | 1 7,12,20,23 * * * root /bin/systemctl restart etcd 2>&1 > /dev/null
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-firewall/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: firewall
4 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-firewall/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: clean lain-PREROUTING
2 | shell: "iptables -t nat -F lain-PREROUTING"
3 |
4 | - name: clean lain-OUTPUT
5 | shell: "iptables -t nat -F lain-OUTPUT"
6 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-images/vars/main.yaml:
--------------------------------------------------------------------------------
1 | # vim: set filetype=json:
2 | # This file is also used by bootstrap python script. Please keep JSON format for this file.
3 | {
4 | "bootstrap_images": {
5 | "swarm": "swarm:1.2.8",
6 | "rebellion": "rebellion:v2.3.3",
7 | "mysql": "mysql-server:5.6.30",
8 | "registry": "registry:release-1498029368-2c74d73cef3f020dd1dd6fcf9e1933112a2c67cc",
9 | "registry-meta": "registry:meta-1498029368-2c74d73cef3f020dd1dd6fcf9e1933112a2c67cc",
10 | "tinydns": "tinydns:release-1497423817-5c5982f1e53476478b74a28877bd878a30605b49",
11 | "tinydns-meta": "tinydns:meta-1497423817-5c5982f1e53476478b74a28877bd878a30605b49",
12 | "webrouter": "webrouter:release-1497430313-fa743a7d70301660065d6e636a18dab5fda3173c",
13 | "webrouter-meta": "webrouter:meta-1497430313-fa743a7d70301660065d6e636a18dab5fda3173c",
14 | "console": "console:release-1500017557-5eb4e8b77fa3a7a5545150b4309a37bee3158c33",
15 | "console-meta": "console:meta-1500017557-5eb4e8b77fa3a7a5545150b4309a37bee3158c33",
16 | "backupctl-meta": "backupctl:meta-1498032948-eb5dc315425981a4ab59e7515627b8b34ef8ed5c",
17 | "backupctl": "backupctl:release-1498032948-eb5dc315425981a4ab59e7515627b8b34ef8ed5c",
18 | "lvault-meta": "lvault:meta-1485154203-73072c92b1862ab470b8d872b278f734747b0739",
19 | "lvault": "lvault:release-1485154203-73072c92b1862ab470b8d872b278f734747b0739"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-layer0/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-firewall
3 |
4 | # store cluster configs in etcd
5 | - role: bootstrap-etcd
6 |
7 | - role: consul
8 |
9 | # load all required images
10 | - role: bootstrap-docker
11 |
12 | - role: prepare
13 |
14 | - role: lainlet
15 |
16 | - role: networkd
17 |
18 | - role: calico
19 |
20 | - role: swarm
21 |
22 | - role: deployd
23 |
24 | - role: binary
25 |
26 | - role: rsync
27 |
28 | - role: mysql
29 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-layer1/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 |
3 | # start layer1 apps using docker directly
4 |
5 | - role: bootstrap-registry-start
6 |
7 | - role: bootstrap-webrouter-start
8 |
9 | - role: bootstrap-console-start
10 |
11 | # deploy registry using bootstrap-console
12 |
13 | - role: bootstrap-registry-push
14 | images_to_push:
15 | - registry
16 | - registry-meta
17 |
18 | - role: bootstrap-console-deploy
19 | app: registry
20 |
21 | # we have registry.lain.local now, no need for bootstrap-registry
22 |
23 | - role: bootstrap-registry-stop
24 |
25 | # prepare to deploy other layer1 apps
26 |
27 | - role: registry
28 | action: push
29 | images_to_push: "{{ bootstrap_images.keys() }}"
30 |
31 | # deploy dns app
32 | - role: bootstrap-tinydns
33 |
34 | # deploy console app
35 | - role: console
36 | - role: bootstrap-console-deploy
37 | app: console
38 |
39 | - role: bootstrap-console-stop
40 |
41 | # deploy webrouter
42 | - role: webrouter-start
43 |
44 | - role: bootstrap-webrouter-stop
45 |
46 | - role: lvault-app
47 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-registry-push/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-registry
3 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-registry-push/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: wait_for registry ready
2 | command: curl -m 2 http://registry.lain.local/v2/
3 | register: result
4 | until: "result.stdout.startswith('{')"
5 | retries: 50
6 | delay: 5
7 | changed_when: False
8 |
9 | - name: push image to registry (may take minutes)
10 | docker_push:
11 | image: "{{ bootstrap_images[item] }}"
12 | registry: registry.lain.local
13 | with_items: "{{images_to_push|default([])}}"
14 |
15 | # vim: set filetype=ansible.yaml:
16 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-registry-start/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-registry
3 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-registry-start/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: check if registry app is deployed
2 | command: etcdctl ls /lain/deployd/pod_groups/registry
3 | register: result
4 | ignore_errors: yes
5 | changed_when: False
6 |
7 | - include: start.yaml
8 | when: result|failed
9 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-registry-start/tasks/start.yaml:
--------------------------------------------------------------------------------
1 | - name: inspect existing bootstrap registry
2 | docker_inspect: name=bootstrap-registry type=container
3 | register: inspect
4 | ignore_errors: yes
5 |
6 | - name: run bootstrap-registry
7 | command: >
8 | docker run -d
9 | --name bootstrap-registry
10 | -p {{ bootstrap_registry_port }}:5000
11 | {{ bootstrap_registry_image }}
12 | ./entry.sh
13 | when: inspect|failed or not inspect.State.Running
14 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-registry-stop/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-registry
3 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-registry-stop/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: stop bootstrap-registry
2 | docker:
3 | image: "{{ bootstrap_registry_image }}"
4 | name: bootstrap-registry
5 | state: absent
6 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-registry/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 | - role: packages
5 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-tinydns/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: binary
3 | - role: firewall
4 | - role: bootstrap-console-deploy
5 | app: tinydns
6 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-tinydns/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: set tinydns vip port config
2 | set_virtual_ip_key: ip="0.0.0.0" port="{{ dns_port }}" container_app="tinydns" container_proc="worker" container_proto="udp" container_port="53"
3 |
4 | - name: set tinydns domain lain
5 | set_tinydns_domain: domain="lain" record=".lain:{{ node_ip }}:a:300"
6 |
7 | - name: set tinydns domain .20.172.in-addr.arpa
8 | set_tinydns_domain: domain=".20.172.in-addr.arpa" record=".20.172.in-addr.arpa:{{ node_ip }}:a:300"
9 |
10 | - name: set tinydns domain DOMAIN
11 | set_tinydns_domain: domain="{{ domain }}" record=".{{ domain }}:{{ node_ip }}:a:300"
12 | when: domain == 'lain.local'
13 |
14 | - name: set tinydns wildcard domain lain
15 | set_tinydns_domain: domain="webrouter.lain" record="+webrouter.lain:{{ vip }}:300"
16 | when: vip != '0.0.0.0'
17 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter-start/files/nginx/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80 default_server;
3 | server_name _;
4 |
5 | #charset koi8-r;
6 | access_log /var/log/nginx/default.access.log main;
7 |
8 | location / {
9 | root /usr/share/nginx/html;
10 | index index.html index.htm;
11 | }
12 |
13 | #error_page 404 /404.html;
14 |
15 | # redirect server error pages to the static page /50x.html
16 | #
17 | error_page 500 502 503 504 /50x.html;
18 | location = /50x.html {
19 | root /usr/share/nginx/html;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter-start/files/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | user nginx;
3 | worker_processes 1;
4 |
5 | error_log /var/log/nginx/error.log warn;
6 | pid /var/run/nginx.pid;
7 |
8 |
9 | events {
10 | worker_connections 1024;
11 | }
12 |
13 |
14 | http {
15 | include /etc/nginx/mime.types;
16 | default_type application/octet-stream;
17 | server_names_hash_bucket_size 512;
18 |
19 | log_format main '$remote_addr - $remote_user [$time_local] "$Host" "$request" '
20 | '$status $body_bytes_sent "$http_referer" '
21 | '"$http_user_agent" "$http_x_forwarded_for" '
22 | 'upstream_response_time "$upstream_response_time" request_time "$request_time"';
23 | client_max_body_size 0;
24 | chunked_transfer_encoding on;
25 |
26 | access_log /var/log/nginx/access.log main;
27 |
28 | sendfile on;
29 | #tcp_nopush on;
30 |
31 | keepalive_timeout 65;
32 |
33 | #gzip on;
34 |
35 | include /etc/nginx/upstreams/*.upstreams;
36 | include /etc/nginx/conf.d/*.conf;
37 | include /etc/nginx/bootstrap/*.conf;
38 | include /etc/nginx/default.conf;
39 | }
40 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter-start/files/nginx/proxy.conf:
--------------------------------------------------------------------------------
1 | proxy_next_upstream error timeout invalid_header http_500 http_502 http_504;
2 |
3 | proxy_redirect off;
4 | proxy_set_header Host $host;
5 | proxy_set_header X-Real-IP $remote_addr;
6 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
7 | proxy_set_header X-Original-URI $request_uri;
8 | proxy_set_header REQUEST_URI $request_uri;
9 |
10 | set $xproto $scheme;
11 | if ($http_x_forwarded_proto ~* "^http") {
12 | set $xproto $http_x_forwarded_proto;
13 | }
14 | proxy_set_header X-Forwarded-Proto $xproto;
15 |
16 | #client_max_body_size 10m;
17 | client_body_buffer_size 128k;
18 | proxy_connect_timeout 90;
19 | proxy_send_timeout 90;
20 | proxy_read_timeout 900;
21 | proxy_buffer_size 4k;
22 | proxy_buffers 4 32k;
23 | proxy_busy_buffers_size 64k;
24 | proxy_temp_file_write_size 64k;
25 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter-start/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: bootstrap-webrouter
4 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter-start/templates/nginx/console.conf.j2:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | listen 443 ssl;
4 | server_name .console.{{ domain }} .console.lain;
5 | ssl_certificate /etc/nginx/ssl/web.crt;
6 | ssl_certificate_key /etc/nginx/ssl/web.key;
7 | include proxy.conf;
8 |
9 | location / {
10 |
11 | proxy_pass http://{{ node_ip }}:{{ bootstrap_console_port }};
12 |
13 | }
14 | access_log /var/log/nginx/web.console.access.log main;
15 | }
16 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter-start/templates/nginx/registry.conf.j2:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | listen 443 ssl;
4 | server_name .registry.{{ domain }};
5 | ssl_certificate /etc/nginx/ssl/web.crt;
6 | ssl_certificate_key /etc/nginx/ssl/web.key;
7 | include proxy.conf;
8 |
9 | location / {
10 |
11 | proxy_pass http://{{ node_ip }}:{{ bootstrap_registry_port }};
12 |
13 | }
14 | access_log /var/log/nginx/web.registry.access.log main;
15 | }
16 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter-stop/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: bootstrap-webrouter
3 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter-stop/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: stop bootstrap-webrouter
2 | docker:
3 | image: "{{ bootstrap_webrouter_image }}"
4 | name: bootstrap-webrouter
5 | state: absent
6 |
7 | - name: remove console.lain
8 | set_config_domain: domain="console.lain" record=""
9 |
10 | - name: remove console.DOMAIN
11 | set_config_domain: domain="console.{{ domain }}" record=""
12 |
13 | - name: remove registry.DOMAIN
14 | set_config_domain: domain="registry.{{ domain }}" record=""
15 |
16 | - name: wait for DNS resolution ready
17 | pause: seconds=2
18 |
19 | - name: check new webrouter works well
20 | shell: "curl -s registry.lain.local/v2/"
21 | register: result
22 | until: result|success
23 | retries: 50
24 | delay: 5
25 | changed_when: False
26 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap-webrouter/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 | - role: bootstrap-registry
5 | - role: bootstrap-console
6 | - role: etcd
7 | - role: ssl
8 | - role: packages
9 | - role: networkd
10 |
--------------------------------------------------------------------------------
/playbooks/roles/bootstrap/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 | - role: systemd
5 | - role: bootstrap-layer0
6 | - role: bootstrap-layer1
7 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico.conf:
--------------------------------------------------------------------------------
1 | xt_set
2 | ip6_tables
3 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/conf.d/bird.toml.toml:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "bird.toml.template"
3 | dest = "/etc/calico/confd/conf.d/bird.toml"
4 | prefix = "/calico/bgp/v1/global"
5 | keys = [
6 | "/node_mesh",
7 | ]
8 | reload_cmd = "systemctl restart calico-confd"
9 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/conf.d/bird6.toml.toml:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "bird6.toml.template"
3 | dest = "/etc/calico/confd/conf.d/bird6.toml"
4 | prefix = "/calico/bgp/v1/global"
5 | keys = [
6 | "/node_mesh"
7 | ]
8 | reload_cmd = "systemctl restart calico-confd"
9 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/conf.d/bird6_ipam.toml:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "bird6_ipam.cfg.template"
3 | dest = "/etc/calico/confd/config/bird6_ipam.cfg"
4 | prefix = "/calico/v1/ipam/v6"
5 | keys = [
6 | "/pool",
7 | ]
8 | reload_cmd = "pkill -HUP bird6 || true"
9 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/conf.d/custom_filters.toml:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "custom_filters.cfg.template"
3 | dest = "/etc/calico/confd/config/custom_filters.cfg"
4 | prefix = "/calico/bgp/v1/global/custom_filters"
5 | keys = [
6 | "/v4",
7 | ]
8 | reload_cmd = "pkill -HUP bird || true"
9 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/conf.d/custom_filters6.toml:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "custom_filters6.cfg.template"
3 | dest = "/etc/calico/confd/config/custom_filters6.cfg"
4 | prefix = "/calico/bgp/v1/global/custom_filters"
5 | keys = [
6 | "/v6",
7 | ]
8 | reload_cmd = "pkill -HUP bird || true"
9 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/conf.d/tunl-ip.toml:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "tunl-ip.template"
3 | dest = "/tmp/tunl-ip"
4 | prefix = "/calico/v1/ipam/v4"
5 | keys = [
6 | "/pool",
7 | ]
8 | reload_cmd = "allocate-ipip-addr"
9 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/config/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laincloud/lain/0fe5f93d06540300c5dafb94d81b3b69d2c8f1da/playbooks/roles/calico/files/calico/confd/config/.gitkeep
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/templates/bird6_ipam.cfg.template:
--------------------------------------------------------------------------------
1 | # Generated by confd
2 | filter calico_pools {
3 | calico_aggr();
4 | custom_filters();
5 | {{range ls "/pool"}}{{$data := json (getv (printf "/pool/%s" .))}}
6 | if ( net ~ {{$data.cidr}} ) then {
7 | accept;
8 | }
9 | {{end}}
10 | reject;
11 | }
12 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/templates/bird_aggr.cfg.template:
--------------------------------------------------------------------------------
1 | # Generated by confd
2 | # ------------- Static black hole addresses -------------
3 | {{if ls "/"}}
4 | protocol static {
5 | {{range ls "/"}}
6 | {{$parts := split . "-"}}
7 | {{$cidr := join $parts "/"}}
8 | route {{$cidr}} blackhole;
9 | {{end}}
10 | }
11 | {{else}}# No static routes configured.{{end}}
12 |
13 | # Aggregation of routes on this host; export the block, nothing beneath it.
14 | function calico_aggr ()
15 | {
16 | {{range ls "/"}}
17 | {{$parts := split . "-"}}
18 | {{$cidr := join $parts "/"}}
19 | if ( net = {{$cidr}} ) then { accept; }
20 | if ( net ~ {{$cidr}} ) then { reject; }
21 | {{end}}
22 | }
23 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/templates/custom_filters.cfg.template:
--------------------------------------------------------------------------------
1 | # Generated by confd
2 | function custom_filters ()
3 | {
4 | {{range ls "/v4"}}{{$data := getv (printf "/v4/%s" .)}}
5 | {{ $data }}
6 | {{end}}
7 | }
8 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/templates/custom_filters6.cfg.template:
--------------------------------------------------------------------------------
1 | # Generated by confd
2 | function custom_filters ()
3 | {
4 | {{range ls "/v6"}}{{$data := getv (printf "/v6/%s" .)}}
5 | {{ $data }}
6 | {{end}}
7 | }
8 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/calico/confd/templates/tunl-ip.template:
--------------------------------------------------------------------------------
1 | We must dump all pool data to this file to trigger a resync.
2 | Otherwise, confd notices the file hasn't changed and won't
3 | run our python update script.
4 |
5 | {{range ls "/pool"}}{{$data := json (getv (printf "/pool/%s" .))}}
6 | {{if $data.ipip}}{{if not $data.disabled}}{{$data.cidr}}{{end}}{{end}}
7 | {{end}}
8 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/service/calico-bird.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Calico bird
3 | Requires=network-online.target
4 | After=network-online.target
5 |
6 | [Service]
7 | Restart=on-failure
8 | ExecStartPre=/usr/bin/env mkdir -p /var/run/calico
9 | ExecStart=/usr/bin/bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg
10 |
11 | [Install]
12 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/service/calico-bird6.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Calico bird6
3 | Requires=network-online.target
4 | After=network-online.target
5 |
6 | [Service]
7 | Restart=on-failure
8 | ExecStartPre=/usr/bin/env mkdir -p /var/run/calico
9 | ExecStart=/usr/bin/bird6 -R -s /var/run/calico/bird6.ctl -d -c /etc/calico/confd/config/bird6.cfg
10 |
11 | [Install]
12 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/service/calico-felix.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Calico Felix agent
3 | After=syslog.target network.target
4 |
5 | [Service]
6 | User=root
7 | ExecStartPre=/usr/bin/env mkdir -p /var/run/calico
8 | ExecStart=/usr/bin/calico-felix
9 | KillMode=process
10 | Restart=on-failure
11 | LimitNOFILE=32000
12 |
13 | [Install]
14 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/playbooks/roles/calico/files/service/calico-libnetwork.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Calico libnetwork plugin
3 | Requires=network-online.target
4 | After=network-online.target
5 |
6 | [Service]
7 | EnvironmentFile=/etc/calico/calico.env
8 | Restart=on-failure
9 | ExecStart=/usr/bin/libnetwork-plugin
10 |
11 | [Install]
12 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/playbooks/roles/calico/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: os-dependent-vars
3 | - role: config
4 | - role: firewall
5 | - role: etcd
6 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/bird.toml.template.j2:
--------------------------------------------------------------------------------
1 | {% raw %}
2 | [template]
3 | src = "bird.cfg.{{if (json (getv "/node_mesh")).enabled}}mesh{{else}}no-mesh{{end}}.template"
4 | dest = "/etc/calico/confd/config/bird.cfg"
5 | prefix = "/calico/bgp/v1"
6 | keys = [
7 | {% endraw %}
8 | {{ '{{if (json (getv "/node_mesh")).enabled}}"/host"{{else}}"/host/' }}{{ ansible_nodename }}{{ '"{{end}},' }}
9 | {% raw %}
10 | "/global"
11 | ]
12 | check_cmd = "bird -p -c {{"{{"}}.src{{"}}"}}"
13 | reload_cmd = "pkill -HUP bird || true"
14 | {% endraw %}
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/bird6.toml.template.j2:
--------------------------------------------------------------------------------
1 | {% raw %}
2 | [template]
3 | src = "bird6.cfg.{{if (json (getv "/node_mesh")).enabled}}mesh{{else}}no-mesh{{end}}.template"
4 | dest = "/etc/calico/confd/config/bird6.cfg"
5 | prefix = "/calico/bgp/v1"
6 | keys = [
7 | {% endraw %}
8 | {{ '{{if (json (getv "/node_mesh")).enabled}}"/host"{{else}}"/host/' }}{{ ansible_nodename }}{{ '"{{end}},' }}
9 | {% raw %}
10 | "/global"
11 | ]
12 | check_cmd = "bird6 -p -c {{"{{"}}.src{{"}}"}}"
13 | reload_cmd = "pkill -HUP bird6 || true"
14 | {% endraw %}
15 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/bird6_aggr.toml.j2:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "bird_aggr.cfg.template"
3 | dest = "/etc/calico/confd/config/bird6_aggr.cfg"
4 | prefix = "/calico/ipam/v2/host/{{ ansible_nodename }}/ipv6/block"
5 | keys = [
6 | "/",
7 | ]
8 | reload_cmd = "pkill -HUP bird || true"
9 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/bird_aggr.toml.j2:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "bird_aggr.cfg.template"
3 | dest = "/etc/calico/confd/config/bird_aggr.cfg"
4 | prefix = "/calico/ipam/v2/host/{{ ansible_nodename }}/ipv4/block"
5 | keys = [
6 | "/",
7 | ]
8 | reload_cmd = "pkill -HUP bird || true"
9 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/bird_ipam.cfg.template.j2:
--------------------------------------------------------------------------------
1 | {% raw %}
2 | #Generated by confd
3 | filter calico_pools {
4 | calico_aggr();
5 | custom_filters();
6 | {{range ls "/v1/ipam/v4/pool"}}{{$data := json (getv (printf "/v1/ipam/v4/pool/%s" .))}}
7 | if ( net ~ {{$data.cidr}} ) then {
8 | accept;
9 | }
10 | {{end}}
11 | reject;
12 | }
13 |
14 | {% endraw %}
15 | {{ '{{$network_key := "/bgp/v1/host/' }}{{ ansible_nodename }}{{ '/network_v4"}}{{$network := getv $network_key}}' }}
16 | {% raw %}
17 | filter calico_ipip {
18 | {{range ls "/v1/ipam/v4/pool"}}{{$data := json (getv (printf "/v1/ipam/v4/pool/%s" .))}}
19 | if ( net ~ {{$data.cidr}} ) then {
20 | {{if $data.ipip_mode}}{{if eq $data.ipip_mode "cross-subnet"}}
21 | if ( from ~ {{$network}} ) then
22 | krt_tunnel = ""; {{/* Destination in ipPool, mode is cross sub-net, route from-host on subnet, do not use IPIP */}}
23 | else
24 | krt_tunnel = "{{$data.ipip}}"; {{/* Destination in ipPool, mode is cross sub-net, route from-host off subnet, set the tunnel (if IPIP not enabled, value will be "") */}}
25 | accept;
26 | } {{else}}
27 | krt_tunnel = "{{$data.ipip}}"; {{/* Destination in ipPool, mode not cross sub-net, set the tunnel (if IPIP not enabled, value will be "") */}}
28 | accept;
29 | } {{end}} {{else}}
30 | krt_tunnel = "{{$data.ipip}}"; {{/* Destination in ipPool, mode field is not present, set the tunnel (if IPIP not enabled, value will be "") */}}
31 | accept;
32 | } {{end}}
33 | {{end}}
34 | accept; {{/* Destination is not in any ipPool, accept */}}
35 | }
36 | {% endraw %}
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/bird_ipam.toml.j2:
--------------------------------------------------------------------------------
1 | [template]
2 | src = "bird_ipam.cfg.template"
3 | dest = "/etc/calico/confd/config/bird_ipam.cfg"
4 | prefix = "/calico"
5 | keys = [
6 | "/v1/ipam/v4/pool",
7 | "/bgp/v1/host/{{ ansible_nodename }}"
8 | ]
9 | reload_cmd = "pkill -HUP bird || true"
10 |
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/calico-confd.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Calico confd
3 | Requires=network-online.target
4 | After=network-online.target
5 |
6 | [Service]
7 | Restart=on-failure
8 | ExecStart=/usr/bin/confd -confdir=/etc/calico/confd -interval=5 -watch -no-discover --log-level=debug -node=http://127.0.0.1:{{ etcd_client_port }}
9 |
10 | [Install]
11 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/calico.env.j2:
--------------------------------------------------------------------------------
1 | ETCD_AUTHORITY=127.0.0.1:{{ etcd_client_port }}
2 | DOCKER_API_VERSION=1.24
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/calicoctl.cfg.j2:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: calicoApiConfig
3 | metadata: {}
4 | spec:
5 | datastoreType: etcdv2
6 | etcdAuthority: ""
7 | etcdCACertFile: ""
8 | etcdCertFile: ""
9 | etcdEndpoints: http://127.0.0.1:{{ etcd_client_port }}
10 | etcdKeyFile: ""
11 | etcdPassword: ""
12 | etcdScheme: ""
13 | etcdUsername: ""
14 | k8sAPIEndpoint: ""
15 | k8sAPIToken: ""
16 | k8sCAFile: ""
17 | k8sCertFile: ""
18 | k8sDisableNodePoll: false
19 | k8sInsecureSkipTLSVerify: false
20 | k8sKeyFile: ""
21 | kubeconfig: ""
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/felix.cfg.j2:
--------------------------------------------------------------------------------
1 | [global]
2 | FelixHostname = "{{ ansible_nodename }}"
3 | EtcdEndpoints = "http://127.0.0.1:{{ etcd_client_port }}"
--------------------------------------------------------------------------------
/playbooks/roles/calico/templates/ippool.yml.j2:
--------------------------------------------------------------------------------
1 | - apiVersion: v1
2 | kind: ipPool
3 | metadata:
4 | cidr: {{ calico_default_network }}
5 | spec:
6 | {% if calico_ipip|bool %}
7 | ipip:
8 | enabled: true
9 | mode: always
10 | {% endif %}
11 | nat-outgoing: true
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse-new/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse-new/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: install ceph-fuse
2 | yum:
3 | name: ceph-fuse-{{ ceph_version }}
4 | state: present
5 |
6 | - name: create ceph conf dir
7 | file: path=/etc/ceph state=directory
8 |
9 | - name: create ceph client_mountpoint dir
10 | file: path={{client_mountpoint}} state=directory
11 |
12 | - name: copy keyring
13 | template: src=ceph.client.lain.keyring.j2 dest=/etc/ceph/ceph.{{ceph_account}}.keyring
14 |
15 | - name: chmod 0600 keyring
16 | file: path=/etc/ceph/ceph.{{ceph_account}}.keyring mode=0600
17 |
18 | - name: copy ceph.conf
19 | template: src=ceph.conf.j2 dest=/etc/ceph/ceph.conf
20 |
21 | - name: mount ceph
22 | command: ceph-fuse -n client.lain -r /lain /data/lain/cloud-volumes/
23 | ignore_errors: yes
24 |
25 | - name: chmod 755 rc.local
26 | file: path=/etc/rc.d/rc.local mode=0755
27 |
28 | - name: edit rc.local
29 | lineinfile: dest=/etc/rc.local line="ceph-fuse -n {{ceph_account}} -r {{ceph_mountpoint}} {{client_mountpoint}}" insertafter=EOF
30 |
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse-new/templates/ceph.client.lain.keyring.j2:
--------------------------------------------------------------------------------
1 | [{{ceph_account}}]
2 | key = {{ceph_password}}
3 |
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse-new/templates/ceph.conf.j2:
--------------------------------------------------------------------------------
1 | [global]
2 | mon_host = {{ceph_mon_address}}
3 |
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse/files/plugins/ceph_mon.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | import argparse
3 | import time
4 | import gevent
5 | import logging
6 | import sys
7 | from gevent import monkey
8 | monkey.patch_socket()
9 |
10 | CEPH_FUSE_MOUNT_TYPE = 'ceph-fuse'
11 | CHECK_INTERVAL_SEC = 60
12 |
13 | log = logging.getLogger("cephmon")
14 | log.setLevel(logging.INFO)
15 |
16 | ch = logging.StreamHandler(sys.stdout)
17 | formatter = logging.Formatter(
18 | '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
19 | ch.setFormatter(formatter)
20 | log.addHandler(ch)
21 |
22 |
23 | def check_mountpoint(mount_point):
24 | if mount_point.strip(' ') == '':
25 | return
26 | check_cmd = ['df', '-P', mount_point]
27 | check_pipe = subprocess.Popen(check_cmd, stdout=subprocess.PIPE)
28 | filter_pipe = subprocess.Popen(
29 | ["tail", "-n", "+2"], stdin=check_pipe.stdout, stdout=subprocess.PIPE)
30 | result_pipe = subprocess.Popen(
31 | ["awk", "{print $1}"], stdin=filter_pipe.stdout, stdout=subprocess.PIPE)
32 | filter_pipe.stdout.close()
33 | check_pipe.stdout.close()
34 | result, err = result_pipe.communicate()
35 | return result.strip()
36 |
37 |
38 | def monitor(mount_point):
39 | while True:
40 | if check_mountpoint(mount_point) == CEPH_FUSE_MOUNT_TYPE:
41 | log.debug(mount_point + ' Successed')
42 | else:
43 | log.error(mount_point + ' Failed')
44 | remount(mount_point)
45 | time.sleep(CHECK_INTERVAL_SEC)
46 |
47 |
48 | def start_monitors(mount_points):
49 | greenlets = []
50 | for mp in mount_points:
51 | greenlet = gevent.spawn(monitor, mp)
52 | greenlet.start()
53 | greenlets.append(greenlet)
54 | gevent.joinall(greenlets)
55 |
56 |
57 | def fetch_mount_points(conf):
58 | with open(conf) as mps_file:
59 | lines = mps_file.readlines()
60 | mps = []
61 | for line in lines:
62 | mps.append(line.strip())
63 | return mps
64 |
65 | def remount(mount_point):
66 | umount_cmd = ['umount', mount_point]
67 | try:
68 | subprocess.check_output(umount_cmd)
69 | except Exception as e:
70 | log.error(e)
71 | log.error('unmount '+ mount_point + ' Failed')
72 | mount_cmd = ['mount', mount_point]
73 | try:
74 | subprocess.check_output(mount_cmd)
75 | log.info('remount '+ mount_point + ' Successed')
76 | except Exception as e:
77 | log.error(e)
78 | log.error('mount '+ mount_point + ' Failed')
79 |
80 | if __name__ == "__main__":
81 | parser = argparse.ArgumentParser()
82 | parser.add_argument("--conf", help="Ceph fuse mountpoint",
83 | default="/etc/ceph/fuse.conf", type=str)
84 | args = parser.parse_args()
85 | mount_points = fetch_mount_points(args.conf)
86 | start_monitors(mount_points)
87 |
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: install ceph-fuse
2 | yum:
3 | name: ceph-fuse-{{ ceph_version }}
4 | state: present
5 |
6 | # 在centos7里, /etc/fstab 不支持 '=', 所以我们用 ':' 替代
7 | # 但是在用 ':' 替代之后需要修改ceph-fuse mount的代码,使其先将 ':' 替换成 '='
8 |
9 | - name: backup /sbin/mount.fuse.ceph
10 | command: mv /sbin/mount.fuse.ceph /sbin/mount.fuse.ceph.bak
11 | when: ansible_distribution_major_version == "7"
12 |
13 | - name: update ceph mount file,
14 | shell: sed -e "s/cephargs='--'\`echo \$1 | sed 's\/,\/ --\/g'\`/fs_spec=\`echo \$1 | sed \'s\/:\/=\/g\'\` \ncephargs=\'--\'\`echo \$fs_spec | sed \'s\/,\/ --\/g\'\`/g" /sbin/mount.fuse.ceph.bak >/sbin/mount.fuse.ceph
15 | when: ansible_distribution_major_version == "7"
16 |
17 | - name: chmod mount.fuse.ceph
18 | file: path=/sbin/mount.fuse.ceph state=file mode=755 group=root owner=root
19 |
20 | - name: create ceph conf dir
21 | command: mkdir -p /etc/ceph
22 | ignore_errors: yes
23 |
24 | - name: create ceph client_mountpoint dir
25 | command: mkdir -p {{client_mountpoint}}
26 | ignore_errors: yes
27 |
28 | - name: copy keyring
29 | template: src=ceph.client.lain.keyring.j2 dest=/etc/ceph/ceph.client.{{ceph_account}}.keyring
30 |
31 | - name: copy ceph.conf
32 | template: src=ceph.conf.j2 dest=/etc/ceph/ceph.conf
33 |
34 | - name: edit fstab
35 | lineinfile: dest=/etc/fstab line="id:{{ceph_account}},client_mountpoint:{{ceph_mountpoint}} {{client_mountpoint}} fuse.ceph _netdev 0 0" insertafter=EOF
36 |
37 | - name: mount
38 | command: mount -a
39 |
40 | - name: init fuse.conf if not exist
41 | command: touch /etc/ceph/fuse.conf
42 |
43 | - name: edit fuse.conf
44 | lineinfile: dest=/etc/ceph/fuse.conf line="{{client_mountpoint}}" insertafter=EOF
45 |
46 | - name: install gevent
47 | package: name=python-gevent state=present
48 |
49 | - name: copy cephmon
50 | copy: src=plugins dest=/etc/ceph/ mode=0755
51 |
52 | - name: generate cephmon service
53 | template: src=cephmon.service.j2 dest=/etc/systemd/system/cephmon.service
54 | register: result
55 |
56 | - name: reload systemd
57 | command: systemctl daemon-reload
58 | when: result|changed
59 |
60 | - name: "enable cephmon"
61 | service: name=cephmon enabled=yes
62 |
63 | - name: restart cephmon
64 | service: name=cephmon state=restarted
65 | when: result
66 |
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse/templates/ceph.client.lain.keyring.j2:
--------------------------------------------------------------------------------
1 | [client.{{ceph_account}}]
2 | key = {{ceph_password}}
3 |
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse/templates/ceph.conf.j2:
--------------------------------------------------------------------------------
1 | [global]
2 | mon_host = {{ceph_mon_address}}
3 |
--------------------------------------------------------------------------------
/playbooks/roles/ceph-fuse/templates/cephmon.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=cephmonitor
3 | After=network.target
4 |
5 | [Service]
6 | LimitNOFILE=65535
7 | ExecStart=/usr/bin/python /etc/ceph/plugins/ceph_mon.py
8 | Restart=on-failure
9 |
10 | [Install]
11 | WantedBy=multi-user.target
12 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/files/plugins/lain/deployd_monitor.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import requests
6 | import argparse
7 | import time
8 | import sys
9 | import socket
10 | from plugin import Plugin, GraphiteData
11 | from procutils import get_etcd_value
12 |
13 |
14 | class DeploydPlugin(Plugin):
15 | '''
16 | The monitor plugin for deployd
17 | '''
18 | _endpoint = socket.gethostname()
19 | _result = []
20 |
21 | def __init__(self, step, deployd_port):
22 | self._step = step
23 | self._deployd_port = deployd_port
24 |
25 | def prepare_data(self):
26 | self._result = []
27 | self._collect_deployd_debug_info()
28 | return self._result
29 |
30 | def _collect_deployd_debug_info(self):
31 | is_alive = 0
32 | try:
33 | domain = get_etcd_value("/lain/config/domain")
34 | resp = requests.get(
35 | "http://deployd.lain:%d/debug/vars" % self._deployd_port, timeout=1)
36 | if resp.status_code == 200:
37 | is_alive = 1
38 | except Exception:
39 | pass
40 |
41 | self._result.append(
42 | GraphiteData("lain.cluster.deployd.alive",
43 | self._endpoint, is_alive, self._step, "status"))
44 |
45 |
46 | if __name__ == "__main__":
47 | step = 30
48 | parser = argparse.ArgumentParser()
49 | parser.add_argument('--deployd-port', help="Deploy port", default=9003, type=int)
50 | args = parser.parse_args()
51 | deployd_plugin = DeploydPlugin(step, args.deployd_port)
52 | while True:
53 | deployd_plugin.report()
54 | sys.stdout.flush()
55 | time.sleep(step)
56 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/files/plugins/lain/docker_daemon_monitor.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import collectd
4 | import time
5 | import requests
6 |
7 |
8 | class Plugin(object):
9 | DOCKER_PS_URL = "http://docker.lain:2375/containers/json"
10 | READ_INTERVAL = 60 # 60 seconds
11 | TIMEOUT = 5 # 5 seconds
12 |
13 | def init(self):
14 | collectd.info("docker_daemon_monitor plugin has been initialized.")
15 |
16 | def read(self):
17 | metric = collectd.Values()
18 | metric.plugin = "lain.cluster.docker_daemon"
19 | metric.plugin_instance = "docker_ps_time"
20 | metric.type = "val"
21 | start_at = time.time()
22 | requests.get(
23 | self.DOCKER_PS_URL, params={"limit": 1}, timeout=self.TIMEOUT)
24 | docker_ps_time = time.time() - start_at
25 | metric.values = [docker_ps_time]
26 | metric.dispatch()
27 |
28 | def shutdown(self):
29 | collectd.info("docker_daemon_monitor plugin has been shutdown.")
30 |
31 |
32 | docker_daemon = Plugin()
33 |
34 | if __name__ != "__main__":
35 | collectd.register_init(docker_daemon.init)
36 | collectd.register_read(docker_daemon.read, docker_daemon.READ_INTERVAL)
37 | collectd.register_shutdown(docker_daemon.shutdown)
38 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/files/plugins/lain/lainlet_monitor.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | from plugin import Plugin, GraphiteData
5 | import requests
6 | import socket
7 | import time
8 | import sys
9 | import argparse
10 |
11 |
12 | class LainletPlugin(Plugin):
13 | '''
14 | The monitor plugin for lainlet
15 | '''
16 | _endpoint = socket.gethostname()
17 | _result = []
18 |
19 | def __init__(self, step, lainlet_port):
20 | self._step = step
21 | self._debug_url = "http://lainlet.lain:%d/debug" % (lainlet_port)
22 |
23 | def prepare_data(self):
24 | self._result = []
25 | self._collect_lainlet_debug_info()
26 | return self._result
27 |
28 | def _collect_lainlet_debug_info(self):
29 | connections = 0
30 | goroutines = 0
31 | try:
32 | resp = requests.get(self._debug_url, timeout=1)
33 | data = resp.json()
34 | connections = data['connections']
35 | goroutines = data['goroutines']
36 | except Exception:
37 | pass
38 |
39 | self._result.append(
40 | GraphiteData("lain.cluster.lainlet.goroutines",
41 | self._endpoint, goroutines, self._step, "val"))
42 | self._result.append(
43 | GraphiteData("lain.cluster.lainlet.connections",
44 | self._endpoint, connections, self._step, "val"))
45 |
46 |
47 | if __name__ == "__main__":
48 | parser = argparse.ArgumentParser()
49 | parser.add_argument("--lainlet-port", help="Lainlet port",
50 | default=9001, type=int)
51 | args = parser.parse_args()
52 | step = 30
53 | lainlet_plugin = LainletPlugin(step, args.lainlet_port)
54 | while True:
55 | lainlet_plugin.report()
56 | sys.stdout.flush()
57 | time.sleep(step)
58 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/files/plugins/lain/plugin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | class Plugin(object):
5 | '''
6 | The base class for plugins
7 | All you need is just to extend it, overwrite prepare_data() method,
8 | and call report() method in __main__.
9 | '''
10 |
11 | def report(self):
12 | '''
13 | Report your prepared_data() to destination system
14 | '''
15 | data = self.prepare_data()
16 | self._report_to_graphite(data)
17 |
18 | def verbose(self):
19 | '''
20 | Show the data to the cluster administrators
21 | '''
22 | data = self.prepare_data()
23 | self._report_to_console(data)
24 |
25 | def prepare_data(self):
26 | '''
27 | Prepare your data. Return a list of DataItem(or its subclass) instances
28 | '''
29 | return []
30 |
31 | def _report_to_graphite(self, data):
32 | data_format = 'PUTVAL "%s/%s/%s" interval=%s N:%s'
33 | for item in data:
34 | data_map = item.format_data()
35 | print data_format % (data_map["endpoint"], data_map["metric"],
36 | data_map["type"], data_map["step"],
37 | data_map["value"])
38 |
39 | def _report_to_console(self, data):
40 | data_format = '%s %s %s'
41 | for item in data:
42 | data_map = item.format_data()
43 | val = data_map["value"]
44 | if data_map["type"] == "status":
45 | val = "OK" if data_map["value"] == 1 else "FAILED"
46 | print data_format % (data_map["endpoint"], data_map["metric"], val)
47 |
48 |
49 | class DataItem(object):
50 | '''
51 | The base class of data items.
52 | If new monitor system is applied, we should support both new and old data
53 | format. So extend it and overwrite format_data() to satisfy new system, and
54 | modify old subclasses to make it capatible for old plugins
55 | '''
56 |
57 | def format_data(self):
58 | '''
59 | Formatting the data, return a dict
60 | '''
61 | return {}
62 |
63 |
64 | class GraphiteData(DataItem):
65 | _metric = ""
66 | _endpoint = ""
67 | _value = ""
68 | _step = ""
69 | _type = ""
70 |
71 | def __init__(self, metric, endpoint,
72 | value, step, type):
73 | self._metric = metric
74 | self._endpoint = endpoint
75 | self._value = value
76 | self._step = step
77 | self._type = type
78 |
79 | def format_data(self):
80 | return {
81 | "metric": self._metric,
82 | "endpoint": self._endpoint,
83 | "value": self._value,
84 | "step": self._step,
85 | "type": self._type,
86 | }
87 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/files/plugins/lain/procutils.py:
--------------------------------------------------------------------------------
1 | import psutil
2 | import subprocess
3 |
4 |
5 | SIZE_KB = 1 << 10
6 | SIZE_MB = 1 << 20
7 | SIZE_GB = 1 << 30
8 | SIZE_TB = 1 << 40
9 |
10 | SCALE_MAP = {
11 | "KB": SIZE_KB,
12 | "MB": SIZE_MB,
13 | "GB": SIZE_GB,
14 | "TB": SIZE_TB,
15 | "B": 1,
16 | }
17 |
18 |
19 | def get_proc(proc_name):
20 | '''
21 | Get the process info by name
22 | '''
23 | for p in psutil.process_iter():
24 | if p.name() == proc_name:
25 | return p
26 | return None
27 |
28 |
29 | def get_etcd_value(key):
30 | out = ""
31 | try:
32 | out = subprocess.check_output(['etcdctl', 'get', key])
33 | except subprocess.CalledProcessError:
34 | pass
35 | return out.strip()
36 |
37 |
38 | def convert_to_byte(value, scale):
39 | if scale in SCALE_MAP:
40 | return float(value) * SCALE_MAP[scale]
41 | else:
42 | return 0
43 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/files/plugins/lain/rebellion_monitor.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import collectd
4 | import requests
5 |
6 |
7 | class Plugin(object):
8 | DOCKER_URL_PREFIX = "http://docker.lain:2375"
9 | READ_INTERVAL = 60 # 60 seconds
10 | TIMEOUT = 6 # 6 seconds
11 | NAME = "lain.cluster.node"
12 |
13 | def init(self):
14 | collectd.info("rebellion_monitor plugin has been initialized.")
15 |
16 | def read(self):
17 | try:
18 | params = {"filters": '{"name": ["rebellion.service"]}'}
19 | containers = requests.get(
20 | "{}/containers/json".format(self.DOCKER_URL_PREFIX),
21 | params=params,
22 | timeout=self.TIMEOUT).json()
23 | metric = collectd.Values()
24 | metric.plugin = self.NAME
25 | metric.plugin_instance = "rebellion_service"
26 | metric.type = "val"
27 | metric.values = [len(containers)]
28 | metric.dispatch()
29 | except Exception as e:
30 | collectd.error(
31 | "rebellion_monitor.read() failed, exception: {}".format(e))
32 |
33 | def shutdown(self):
34 | collectd.info("rebellion_monitor plugin has been shutdown.")
35 |
36 |
37 | if __name__ != "__main__":
38 | rebellion_monitor = Plugin()
39 | collectd.register_init(rebellion_monitor.init)
40 | collectd.register_read(rebellion_monitor.read,
41 | rebellion_monitor.READ_INTERVAL)
42 | collectd.register_shutdown(rebellion_monitor.shutdown)
43 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/files/types/lain.db:
--------------------------------------------------------------------------------
1 | net value:COUNTER:0:U
2 | status value:GAUGE:0:1
3 | val value:GAUGE:-1:U
4 | percent value:GAUGE:0:1
5 | time_diff value:COUNTER:0:U
6 | blkio value:COUNTER:0:U
7 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: restart collectd
2 | service: name=collectd state=restarted
3 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: os-dependent-vars
3 | - role: config
4 | - role: libraries
5 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - set_fact: collectd_version="5.5.1"
2 |
3 | - name: install collectd(CentOS)
4 | yum: pkg=collectd-{{ collectd_version }}
5 | when: ansible_distribution=="CentOS"
6 |
7 | - name: install collectd(Ubuntu)
8 | apt: name=collectd=5.5.1-1build2 state=installed
9 | when: ansible_distribution=="Ubuntu"
10 |
11 | - name: install collectd plugins and dependencies
12 | yum: pkg={{ item }}
13 | with_items:
14 | - collectd-ping-{{ collectd_version }}
15 | - gcc
16 | - python-devel
17 | - python-pip
18 | when: ansible_distribution=="CentOS"
19 |
20 | - name: install python libs
21 | command: pip install docker-py psutil==4.1.0
22 | environment:
23 | http_proxy: "{{ http_proxy }}"
24 | https_proxy: "{{ https_proxy }}"
25 |
26 | # lastest collectd without disk pkg
27 | - name: install collectd plugins
28 | yum: pkg={{ item }}
29 | with_items:
30 | - collectd-disk-{{ collectd_version }}
31 | ignore_errors: yes
32 | when: ansible_distribution=="CentOS"
33 |
34 | - name: create collectd user
35 | user: name=collectd createhome=no append=yes groups=docker system=yes
36 |
37 | - name: deploy collectd main config
38 | template: src=collectd.conf.j2 dest={{ collectd_conf_path}}
39 | notify: restart collectd
40 |
41 | - name: ensure plugins dir
42 | file: path=/var/lib/collectd/plugins state=directory
43 |
44 | - name: deploy collectd types
45 | copy: src=types dest=/var/lib/collectd/
46 | notify: restart collectd
47 |
48 | - name: deploy collectd lain plugins
49 | copy: src=plugins dest=/var/lib/collectd/ mode=0755
50 | notify: restart collectd
51 |
52 | - name: ensure conf dir
53 | file: path={{collectd_conf_dir}} state=directory
54 |
55 | - name: deploy collectd plugins config
56 | template: src={{ item }}.j2 dest={{collectd_conf_dir}}/{{ item }}
57 | with_items:
58 | - docker_daemon_monitor.conf
59 | - lain.conf
60 | - node_monitor.conf
61 | - rebellion_monitor.conf
62 | notify: restart collectd
63 |
64 | - name: ensure collectd running
65 | service: name=collectd enabled=yes state=started
66 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/templates/docker_daemon_monitor.conf.j2:
--------------------------------------------------------------------------------
1 | LoadPlugin python
2 | # ...
3 |
4 | ModulePath "/var/lib/collectd/plugins/lain"
5 | LogTraces true
6 | Interactive false
7 | Import "docker_daemon_monitor"
8 |
9 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/templates/lain.conf.j2:
--------------------------------------------------------------------------------
1 | TypesDB "/var/lib/collectd/types/lain.db"
2 |
3 |
4 | Exec "collectd:docker" "/var/lib/collectd/plugins/lain/lain_docker.py" "--domain" "{{domain}}"
5 | Exec "collectd:docker" "/var/lib/collectd/plugins/lain/cluster_monitor.py" "--swarm-manager-port" "{{ swarm_manager_port }}" "--docker-port" "{{ docker_port }}" "--ceph-fuse" "{{ client_mountpoint }}"
6 | Exec "collectd:docker" "/var/lib/collectd/plugins/lain/lainlet_monitor.py" "--lainlet-port" "{{ lainlet_port }}"
7 | Exec "collectd:docker" "/var/lib/collectd/plugins/lain/deployd_monitor.py" "--deployd-port" "{{ deployd_port }}"
8 |
9 |
10 |
11 | ProcessMatch "etcd" "/usr/bin/etcd"
12 | ProcessMatch "lainlet" "/usr/bin/lainlet"
13 | ProcessMatch "networkd" "/usr/bin/networkd"
14 | ProcessMatch "deployd" "/usr/bin/deployd"
15 | ProcessMatch "docker" "dockerd"
16 | ProcessMatch "rebellion" "rebellion"
17 | ProcessMatch "filebeat" "filebeat"
18 | ProcessMatch "rsyslogd" "/usr/sbin/rsyslogd"
19 | ProcessMatch "consul" "/usr/bin/consul"
20 |
21 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/templates/node_monitor.conf.j2:
--------------------------------------------------------------------------------
1 | LoadPlugin python
2 | # ...
3 |
4 | ModulePath "/var/lib/collectd/plugins/lain"
5 | LogTraces true
6 | Interactive false
7 | Import "node_monitor"
8 |
9 |
--------------------------------------------------------------------------------
/playbooks/roles/collectd/templates/rebellion_monitor.conf.j2:
--------------------------------------------------------------------------------
1 | LoadPlugin python
2 | # ...
3 |
4 | ModulePath "/var/lib/collectd/plugins/lain"
5 | LogTraces true
6 | Interactive false
7 | Import "rebellion_monitor"
8 |
9 |
--------------------------------------------------------------------------------
/playbooks/roles/console-deploy/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: check if app already deployed
2 | command: etcdctl ls /lain/deployd/pod_groups/{{ app }}
3 | register: result
4 | ignore_errors: yes
5 | changed_when: False
6 |
7 | - name: waiting for console ready to deploy
8 | shell: "curl -f http://console.lain/api/v1/repos/"
9 | register: console_ready
10 | until: console_ready.rc == 0
11 | retries: 50
12 | delay: 5
13 | changed_when: False
14 | when: result|failed
15 |
16 | - name: reposit app
17 | post_json:
18 | url: http://console.lain/api/v1/repos/
19 | body:
20 | appname: "{{ app }}"
21 | header:
22 | access-token: "{{ access_token|default('unknown') }}"
23 | when: result|failed
24 |
25 | - name: deploy app
26 | post_json:
27 | url: http://console.lain/api/v1/apps/
28 | body:
29 | appname: "{{ app }}"
30 | header:
31 | access-token: "{{ access_token|default('unknown') }}"
32 | when: result|failed
33 |
34 | - name: check app deployed
35 | shell: "curl -s -H \"access-token: {{ access_token|default('unknown') }}\" console.lain/api/v1/apps/{{ app }}/ | python -c \"import json, sys; print json.load(sys.stdin)['app']['procs'][0]['pods'][0]['containerid']\""
36 | register: container_id
37 | until: container_id|success
38 | retries: 50
39 | delay: 5
40 | changed_when: False
41 |
--------------------------------------------------------------------------------
/playbooks/roles/console/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: prepare volume dirs
2 | file: path={{ lain_data_dir }}/volumes/console/console.web.web/1/{{ item }} state=directory
3 | with_items:
4 | - externalbin
5 |
6 | - name: copy volume files
7 | copy: src={{ item.src }} dest={{ lain_data_dir }}/volumes/console/console.web.web/1/{{ item.dest }} mode={{ item.mode }}
8 | with_items:
9 | - src: /usr/bin/calicoctl
10 | dest: externalbin/calicoctl
11 | mode: "0755"
12 |
13 | # vim: set filetype=ansible.yaml:
14 |
--------------------------------------------------------------------------------
/playbooks/roles/consul/files/consul.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Consul Agent
3 | After=network.target
4 |
5 | [Service]
6 | Restart=on-failure
7 | ExecStart=/usr/bin/consul agent -config-file=/etc/consul/consul.json
8 |
9 | [Install]
10 | WantedBy=multi-user.target
11 |
--------------------------------------------------------------------------------
/playbooks/roles/consul/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: copy consul binary file
2 | copy:
3 | src: bin/consul
4 | dest: /usr/bin/consul
5 | force: yes
6 | mode: a+x
7 |
8 | - name: mkdir /etc/consul
9 | file: path=/etc/consul state=directory
10 |
11 | - name: generate consul.json
12 | template:
13 | src: consul.json.j2
14 | dest: /etc/consul/consul.json
15 |
16 | - name: copy consul.service
17 | copy:
18 | src: consul.service
19 | dest: /etc/systemd/system/consul.service
20 |
21 | - name: systemctl daemon-reload
22 | command: systemctl daemon-reload
23 |
24 | - name: systemctl restart consul && systemctl enable consul
25 | service:
26 | name: consul
27 | state: restarted
28 | enabled: yes
29 |
--------------------------------------------------------------------------------
/playbooks/roles/consul/templates/consul.json.j2:
--------------------------------------------------------------------------------
1 | {
2 | {% if is_consul_server %}
3 | "bootstrap_expect": {{consul_servers|length}},
4 | {% endif %}
5 | "retry_join": [{% for ip in consul_servers | difference(ansible_all_ipv4_addresses) %}"{{ ip }}"{% if not loop.last %}, {% endif %}{% endfor %}],
6 | "data_dir": "/var/lib/consul",
7 | "server": {{ "true" if is_consul_server else "false" }},
8 | "bind_addr": "{{ node_ip }}",
9 | "client_addr": "0.0.0.0",
10 | "disable_update_check": true
11 | }
12 |
--------------------------------------------------------------------------------
/playbooks/roles/cronjob/tasks/main.yml:
--------------------------------------------------------------------------------
1 | - name: backup old crontab
2 | shell: crontab -l > ~/backup.cron
3 | ignore_errors: yes
4 |
5 | - name: copy image-clean script
6 | copy:
7 | src: clean_lainnode_image.py
8 | dest: ~/clean_lainnode_image.py
9 | mode: 0777
10 |
11 | - name: add clean lain node docker images cronjob
12 | cron:
13 | name: "clean docker images"
14 | minute: "0"
15 | hour: "1"
16 | job: "~/clean_lainnode_image.py --debug &> /dev/nulll"
17 |
--------------------------------------------------------------------------------
/playbooks/roles/deployd/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
--------------------------------------------------------------------------------
/playbooks/roles/deployd/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: copy deployd binary file
2 | copy:
3 | src: deployd
4 | dest: /usr/bin/deployd
5 | force: yes
6 | mode: a+x
7 |
8 | - name: generate deployd.service
9 | template:
10 | src: deployd.service.j2
11 | dest: /etc/systemd/system/deployd.service
12 |
13 | - name: systemctl daemon-reload
14 | command: systemctl daemon-reload
15 |
16 | - name: systemctl restart deployd && systemctl enable deployd
17 | service:
18 | name: deployd
19 | state: restarted
20 | enabled: yes
21 |
--------------------------------------------------------------------------------
/playbooks/roles/deployd/templates/deployd.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=deployd
3 | After=network.target
4 |
5 | [Service]
6 | LimitNOFILE=65535
7 | ExecStart=/usr/bin/deployd \
8 | -web=:{{ deployd_port }} \
9 | -etcd=http://etcd.lain:{{ etcd_client_port }} \
10 | -swarm=tcp://swarm.lain:{{ swarm_manager_port }} \
11 | -advertise={{ node_ip }}:{{ deployd_port }} \
12 | -debug
13 | Restart=on-failure
14 |
15 | [Install]
16 | WantedBy=multi-user.target
17 |
--------------------------------------------------------------------------------
/playbooks/roles/docker-netstat/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 |
--------------------------------------------------------------------------------
/playbooks/roles/docker-netstat/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: copy docker-netstat
2 | copy:
3 | src: bin/docker-netstat
4 | dest: /usr/bin/docker-netstat
5 | force: yes
6 | mode: a+x
7 |
8 | - name: generate docker-netstat.service
9 | template: src=docker-netstat.service.j2 dest=/lib/systemd/system/docker-netstat.service
10 |
11 | - name: systemctl daemon-reload
12 | command: systemctl daemon-reload
13 |
14 | - name: enable and restart docker-netstat.service
15 | service:
16 | name: docker-netstat.service
17 | state: restarted
18 | enabled: yes
19 |
--------------------------------------------------------------------------------
/playbooks/roles/docker-netstat/templates/docker-netstat.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Docker Netstat
3 | Requires=network-online.target
4 | After=network-online.target
5 |
6 | [Service]
7 | Restart=on-failure
8 | ExecStart=/usr/bin/docker-netstat -graphite {{ graphite_vip }}:{{ graphite_port }}
9 |
10 | [Install]
11 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/playbooks/roles/docker-upgrade/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: docker-version
3 | - role: swarm
4 |
--------------------------------------------------------------------------------
/playbooks/roles/docker-upgrade/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd
2 | command: systemctl daemon-reload
3 |
4 | - name: restart deployd
5 | service: name=deployd state=started
6 |
7 |
8 |
--------------------------------------------------------------------------------
/playbooks/roles/docker-version/defaults/main.yaml:
--------------------------------------------------------------------------------
1 | docker_version: 1.12.1-1.el7.centos
--------------------------------------------------------------------------------
/playbooks/roles/docker-version/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for docker
2 | command: systemctl daemon-reload
3 |
4 | - name: restart docker
5 | service: name=docker state=restarted
6 |
7 | - name: stop docker
8 | service: name=docker enabled=yes state=stopped
--------------------------------------------------------------------------------
/playbooks/roles/docker-version/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: prepare
3 |
--------------------------------------------------------------------------------
/playbooks/roles/docker-version/tasks/devicemapper.yaml:
--------------------------------------------------------------------------------
1 | - shell: lvdisplay -c | grep {{ volume_group }} | grep /data | cut -d ":" -f 1
2 | register: result
3 |
4 | - set_fact:
5 | devicemapper_data_dir: "{{ result.stdout|trim }}"
6 |
7 | - shell: lvdisplay -c | grep {{ volume_group }} | grep /metadata | cut -d ":" -f 1
8 | register: result
9 |
10 | - set_fact:
11 | devicemapper_metadata_dir: "{{ result.stdout|trim }}"
12 |
--------------------------------------------------------------------------------
/playbooks/roles/docker-version/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: get stat of old deployd
2 | stat: path=/usr/bin/deployd
3 | register: deployd
4 | ignore_errors: yes
5 |
6 | - name: stop deployd service
7 | service: name=deployd state=stopped
8 | when: deployd|success
9 |
10 | - name: stop running docker
11 | service: name=docker enabled=yes state=stopped
12 |
13 | - name: uninstall exists docker
14 | yum: name={{ item }} state=absent
15 | with_items:
16 | - docker-engine-selinux.noarch
17 | - docker-engine.x86_64
18 |
19 | # TODO: support more distro
20 | - name: install(update) lvm2 and device-mapper
21 | yum: name=lvm2,device-mapper state=latest
22 | when: ansible_distribution == "CentOS"
23 |
24 | - name: install docker from OS package manage system
25 | yum: pkg={{ item }}
26 | with_items:
27 | - "/tmp/lain/docker-engine-selinux-{{ docker_version }}.noarch.rpm"
28 | - "/tmp/lain/docker-engine-{{ docker_version }}.x86_64.rpm"
29 | register: pkg
30 | when: ansible_distribution == "CentOS"
31 |
32 | - name: install docker for ubuntu
33 | apt:
34 | deb: "/tmp/lain/docker-ce_17.09.1_ubuntu_{{ansible_distribution_version}}_amd64.deb"
35 | when: ansible_distribution == "Ubuntu"
36 |
37 | - name: remove default Docker keys, avoid issues with Swarm
38 | file: path=/etc/docker/key.json state=absent
39 | when: adding_node_mode is defined
40 |
41 | - set_fact:
42 | docker_device: "{{node_info['docker_device']}}"
43 | when: docker_device == "" and node_info is defined
44 |
45 | - include: devicemapper.yaml
46 | when: docker_device != "" and ansible_distribution == "CentOS"
47 |
48 | # Restarting docker is a big deal. User must allow it explicitly.
49 | - name: render docker config for test
50 | template: src=docker.j2 dest=/tmp/docker.conf
51 | - name: get stat of rendered docker config
52 | stat: path=/tmp/docker.conf
53 | register: new_docker_conf_stat
54 | - name: get stat of current docker config
55 | stat: path=/etc/systemd/system/docker.service
56 | register: current_docker_conf_stat
57 |
58 | - name: config docker
59 | template: src=docker.j2 dest=/etc/systemd/system/docker.service
60 | notify:
61 | - reload systemd for docker
62 | - restart docker
63 | - meta: flush_handlers
64 |
65 | - name: set docker graph dir
66 | file: path={{ docker_graph_dir }} state=directory
67 |
68 | - name: ensure docker started
69 | service: name=docker state=started
70 |
71 | - name: wait for docker daemon start, again
72 | command: docker version -f "\{\{.Server.Version\}\}"
73 | register: current_docker_version
74 | until: current_docker_version.stdout
75 | retries: 50
76 | delay: 5
77 | changed_when: False
78 |
--------------------------------------------------------------------------------
/playbooks/roles/docker-version/templates/docker.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Docker Application Container Engine
3 | Documentation=https://docs.docker.com
4 | After=network.target
5 | [Service]
6 | Type=notify
7 | Environment=GOTRACEBACK=crash DOCKER_CERT_PATH=/etc/docker
8 | ExecStart=/usr/bin/docker daemon \
9 | {% if docker_device != "" %}
10 | --storage-driver=devicemapper \
11 | --storage-opt dm.datadev={{ devicemapper_data_dir }} \
12 | --storage-opt dm.metadatadev={{ devicemapper_metadata_dir }} \
13 | {% endif -%}
14 | {% if registry_mirror is defined %}
15 | --registry-mirror={{ registry_mirror }} \
16 | --insecure-registry={{ registry_mirror|replace('http://', '')|replace('https://', '') }} \
17 | {% endif -%}
18 | --insecure-registry=registry.{{ domain }} \
19 | --dns={{ node_ip }} \
20 | --selinux-enabled \
21 | --graph {{ docker_graph_dir }} \
22 | --host unix:///var/run/docker.sock \
23 | --host tcp://{{ node_ip }}:{{ docker_port }} \
24 | --log-driver=none \
25 | --cluster-store=etcd://{{ node_ip }}:{{ etcd_client_port }}
26 |
27 | MountFlags=slave
28 | LimitNOFILE=1048576
29 | LimitNPROC=1048576
30 | LimitCORE=infinity
31 |
32 | [Install]
33 | WantedBy=multi-user.target
34 |
--------------------------------------------------------------------------------
/playbooks/roles/docker/files/bootstrap-ubuntu-docker.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Created by Yu Yang on 2017-12-11
4 | #
5 | if ! which dockerd 2>&1 >/dev/null; then
6 | sudo apt-get remove docker docker-engine docker.io
7 | sudo apt-get update
8 | sudo apt-get -y install \
9 | linux-image-extra-$(uname -r) \
10 | linux-image-extra-virtual
11 |
12 | sudo apt-get -y install \
13 | apt-transport-https \
14 | ca-certificates \
15 | curl \
16 | software-properties-common
17 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
18 | sudo apt-key fingerprint 0EBFCD88
19 | sudo add-apt-repository \
20 | "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
21 | $(lsb_release -cs) \
22 | stable"
23 | sudo apt-get update
24 | sudo apt-get install -y docker-ce=17.09.1~ce-0~ubuntu
25 | fi
26 |
--------------------------------------------------------------------------------
/playbooks/roles/docker/files/docker-enter:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | docker exec -it $1 env TERM=$TERM bash
4 |
--------------------------------------------------------------------------------
/playbooks/roles/docker/files/docker-enter-comp:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | _docker_enter()
4 | {
5 | local cur prev opts
6 | COMPREPLY=()
7 | cur="${COMP_WORDS[COMP_CWORD]}"
8 | prev="${COMP_WORDS[COMP_CWORD-1]}"
9 | opts=`docker ps --format "{{.Names}}" --filter status=running`
10 |
11 | COMPREPLY=( $( compgen -W "${opts}" -- "$cur" ) )
12 | }
13 |
14 | complete -F _docker_enter docker-enter
15 |
16 | # ex: ts=4 sw=4 et filetype=sh
17 |
--------------------------------------------------------------------------------
/playbooks/roles/docker/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for docker
2 | command: systemctl daemon-reload
3 |
4 | - name: restart docker
5 | service: name=docker state=restarted
6 |
--------------------------------------------------------------------------------
/playbooks/roles/docker/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: os-dependent-vars
3 | - role: config
4 | - role: libraries
5 | - role: rsyslog
6 | - role: etcd
7 | - role: binary
8 | - role: firewall
9 | - role: networkd
10 |
--------------------------------------------------------------------------------
/playbooks/roles/docker/tasks/devicemapper.yaml:
--------------------------------------------------------------------------------
1 | - name: check the size(bytes) of block device
2 | shell: blockdev --getsize64 "{{ docker_device }}"
3 | register: size_result
4 |
5 | - set_fact:
6 | size: "{{ size_result.stdout|int // 1024 // 1024 // 1024 }}"
7 |
8 | - name: check if size big enough
9 | fail: msg="the given block device's size is too small"
10 | when: size < 10
11 |
12 | - name: check if the physical volume having been created
13 | shell: pvdisplay -c {{ docker_device }}
14 | register: result
15 | ignore_errors: true
16 |
17 | - name: create physical volume for docker devicemapper storage
18 | command: pvcreate "{{ docker_device }}"
19 | when: result|failed
20 |
21 | - name: check if the volume group having been created
22 | command: vgdisplay "{{ volume_group }}"
23 | register: result
24 | ignore_errors: true
25 |
26 | - name: create volume group
27 | command: vgcreate "{{ volume_group }}" "{{ docker_device }}"
28 | when: result | failed
29 |
30 | - name: check if the logical volume for data having been created
31 | shell: lvdisplay -c | grep {{ volume_group }} | grep /data
32 | register: result
33 | ignore_errors: true
34 |
35 | - name: create logical volume for data
36 | command: lvcreate -l95%VG -n data "{{ volume_group }}"
37 | when: result|failed
38 |
39 | - shell: lvdisplay -c | grep {{ volume_group }} | grep /data | cut -d ":" -f 1
40 | register: result
41 |
42 | - set_fact:
43 | devicemapper_data_dir: "{{ result.stdout|trim }}"
44 |
45 | - name: check if the logical volume for data having been created
46 | shell: lvdisplay -c | grep {{ volume_group }} | grep /metadata
47 | register: result
48 | ignore_errors: true
49 |
50 | - name: create logical volume for metadata
51 | command: lvcreate -l100%FREE -n metadata "{{ volume_group }}"
52 | when: result|failed
53 |
54 | - shell: lvdisplay -c | grep {{ volume_group }} | grep /metadata | cut -d ":" -f 1
55 | register: result
56 |
57 | - set_fact:
58 | devicemapper_metadata_dir: "{{ result.stdout|trim }}"
59 |
--------------------------------------------------------------------------------
/playbooks/roles/docker/templates/daemon.json.j2:
--------------------------------------------------------------------------------
1 | {
2 | {% if ansible_distribution == "CentOS" %}
3 | {% if docker_device != "" %}
4 | "storage-driver": "devicemapper",
5 | "storage-opts": ["dm.datadev={{ devicemapper_data_dir }}","dm.metadatadev={{ devicemapper_metadata_dir }}"],
6 | {% endif -%}
7 | "selinux-enabled": true,
8 | {% endif -%}
9 |
10 | {% if registry_mirror is defined %}
11 | "registry-mirrors": ["{{ registry_mirror }}"],
12 | {% endif -%}
13 | {% if node_labels is defined %}
14 | "labels": [{% for label in node_labels %}"{{ label }}"{% if not loop.last %}, {% endif %}{% endfor %}],
15 | {% endif -%}
16 | "insecure-registries": ["registry.{{ domain }}"{% if registry_mirror is defined %},"{{ registry_mirror|replace('http://', '')|replace('https://', '') }}"{% endif -%}],
17 | "dns": ["{{ node_ip }}"],
18 | "graph": "{{ docker_graph_dir }}",
19 | "hosts": ["unix:///var/run/docker.sock","tcp://{{ node_ip }}:{{ docker_port }}"],
20 | "log-driver": "none",
21 | "cluster-store": "consul://127.0.0.1:8500",
22 | "labels": ["group=default"]
23 | }
24 |
--------------------------------------------------------------------------------
/playbooks/roles/drift-warm-up/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - libraries
3 |
--------------------------------------------------------------------------------
/playbooks/roles/drift-warm-up/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: check whether images exist
2 | docker_check_images:
3 | images: "{{ to_drift_images }}"
4 | when: node_name == target_node
5 | ignore_errors: yes
6 | register: check
7 | changed_when: False
8 |
9 | - name: pull images when not exist (this may take minutes)
10 | docker_pull_image: image={{ item }}
11 | with_items: "{{ to_drift_images }}"
12 | when: node_name == target_node and (check|failed)
13 |
--------------------------------------------------------------------------------
/playbooks/roles/drift/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 |
--------------------------------------------------------------------------------
/playbooks/roles/drift/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - set_fact:
2 | drift_vars: "{{ lookup('template', var_file) }}"
3 |
4 | - name: create directory on target node
5 | file: path="{{item}}" state=directory
6 | with_items: "{{ drift_vars['volumes'] }}"
7 | when: node_name == target_node
8 |
9 | - name: write rsyncd password file
10 | shell: etcdctl get /lain/config/rsyncd_secrets > /tmp/pass
11 | when: node_name == target_node
12 |
13 | - name: chmod password file
14 | file: path=/tmp/pass state=file mode=0600 group=root owner=root
15 | when: node_name == target_node
16 |
17 | - name: pull data from source node
18 | shell: rsync -az --password-file /tmp/pass rsync://"{{rsync_auth_user}}@{{from_ip}}/{{rsync_module}}{{ item[18:] }}/" "{{ item }}"/
19 | with_items: "{{ drift_vars['volumes'] }}"
20 | when: node_name == target_node
21 |
22 | - name: remove the password file
23 | file: path=/tmp/pass state=absent
24 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd-backup/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for etcd_backup
2 | command: systemctl daemon-reload
3 |
4 | - name: restart etcd_backup
5 | service: name=etcd_backup state=restarted
6 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd-backup/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd-backup/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: ship etcd_backup binary
2 | copy: src=plugins/lain/etcd_backup dest=/usr/bin/etcd_backup
3 | when: is_lain_manager
4 |
5 | - name: make etcd_backup service executable
6 | shell: chmod +x /usr/bin/etcd_backup
7 | when: is_lain_manager
8 |
9 | - name: config etcd_backup service
10 | template: src=etcd_backup.service.j2 dest=/etc/systemd/system/etcd_backup.service
11 | notify:
12 | - reload systemd for etcd_backup
13 | when: is_lain_manager
14 |
15 | - name: start etcd_backup
16 | shell: systemctl restart etcd_backup
17 | when: is_lain_manager
18 |
19 | - name: ensure etcd_backup
20 | service: name=etcd_backup state=started enabled=yes
21 | when: is_lain_manager
22 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd-backup/templates/etcd_backup.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=etcd_backup
3 | After=network.target
4 |
5 | [Service]
6 | User=root
7 | LimitNOFILE=65535
8 | Environment='HOSTNAME={{ node_name }}'
9 | ExecStart=/usr/bin/etcd_backup --backup_dir={{ etcd_backup_dir }}/
10 | Restart=on-failure
11 |
12 | [Install]
13 | WantedBy=multi-user.target
14 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd-moosefs/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for etcd_backup mount
2 | command: systemctl daemon-reload
3 |
4 | - name: mount etcd_backup directory
5 | service: name=data-lain-etcd_backup.mount state=restarted
6 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd-moosefs/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd-moosefs/tasks/build.yaml:
--------------------------------------------------------------------------------
1 | - fail: msg="moosefs not exist"
2 | when: mfsmaster == ""
3 | - fail: msg="unknown etcd_backup's dir"
4 | when: etcd_backup_dir == ""
5 |
6 | - stat: path="{{ etcd_mfsdir }}"
7 | register: result
8 | - fail: msg="etcd_backup datadir {{ etcd_mfsdir }} having been exist on moosefs, check and delete it by yourself"
9 | when: result.stat.isdir is defined
10 |
11 | - name: create etcd directory on moosefs
12 | file: path="{{ etcd_mfsdir }}" state=directory
13 |
14 | - name: stop etcd_backup service
15 | service: name=etcd_backup state=stopped
16 |
17 | - file: path="{{ etcd_backup_dir }}.bak" state=absent
18 | - name: backup etcd data (may take minutes)
19 | command: cp -r "{{ etcd_backup_dir }}" "{{ etcd_backup_dir }}.bak"
20 |
21 | - name: move etcd data into moosefs
22 | shell: mv "{{ etcd_backup_dir }}/etcd" "{{ etcd_mfsdir }}/"
23 |
24 | # The .mount file must be var-lib-registry.mount, file name corresponds to /var/lib/registry, check `man systemd.mount` for detail
25 | - name: generate systemd.mount for etcd_backup
26 | template: src=data-lain-etcd_backup.mount.j2 dest=/etc/systemd/system/data-lain-etcd_backup.mount
27 | notify:
28 | - reload systemd for etcd_backup mount
29 | - mount etcd_backup directory
30 | - meta: flush_handlers
31 |
32 | - name: ensure etcd_backup data dir mounted onto moosefs and enable this service
33 | service: name=data-lain-etcd_backup.mount state=started enabled=yes
34 |
35 | - name: start etcd_backup service
36 | service: name=etcd_backup state=started enabled=yes
--------------------------------------------------------------------------------
/playbooks/roles/etcd-moosefs/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - include: build.yaml
2 | when: is_lain_manager
3 |
4 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd-moosefs/templates/data-lain-etcd_backup.mount.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=bind etcd_backup data dir onto moosefs
3 | After=network.target remote-fs.target mfs.mount
4 |
5 | [Mount]
6 | What={{ etcd_mfsdir }}
7 | Where={{ etcd_backup_dir }}
8 | Type=none
9 | Options=bind
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for etcd
2 | command: systemctl daemon-reload
3 |
4 | - name: restart etcd
5 | service: name=etcd state=restarted
6 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd/tasks/etcd-reset.yaml:
--------------------------------------------------------------------------------
1 | - name: add new etcd-member to cluster
2 | local_action: command etcdctl member add {{ node_name }} http://{{ node_ip }}:{{ etcd_peer_port }}
3 | when: adding_etcd_member
4 |
5 | - name: get etcd-member-id
6 | local_action: shell etcdctl member list | grep "name={{ node_name }}" | awk '{print substr($1, 0, length($1)-1)}'
7 | register: member_id
8 | failed_when: member_id.stdout == ""
9 | when: removing_etcd_member
10 |
11 | - name: remove etcd-member from cluster
12 | local_action: command etcdctl member remove {{ member_id.stdout }}
13 | register: result
14 | failed_when: "'500' in result.stderr"
15 | when: removing_etcd_member
16 |
17 | - name: stop etcd service
18 | service: name=etcd state=stopped
19 | when: delete_existing_etcd|bool
20 | ignore_errors: yes
21 |
22 | - name: remove old etcd data
23 | file: path={{ etcd_dir }} state=absent
24 | when: delete_existing_etcd|bool
25 |
26 | - name: create etcd data dir
27 | file: path={{ etcd_dir }} state=directory owner=etcd
28 |
29 | - name: prepare etcd config
30 | set_fact:
31 | etcd_cluster: "{% for node in etcd_members %}{{ node.name }}=http://{{ node.ip }}:{{ etcd_peer_port }}{% if not loop.last %},{% endif %}{% endfor %}"
32 |
33 | # now when etcd-cluster-resizing, all the nodes will cause template changed and restart etcd
34 | # TODO(chenyunfei) check whether is adding new lain-node
35 | - name: config etcd
36 | template: src=etcd.env.j2 dest={{ etcd_dir }}/env owner=etcd
37 | notify:
38 | - restart etcd
39 |
40 | - name: config etcd service
41 | template: src=etcd.service.j2 dest=/etc/systemd/system/etcd.service
42 | notify:
43 | - reload systemd for etcd
44 | - restart etcd
45 |
46 | - meta: flush_handlers
47 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - file: path=/etc/etcd state=directory mode=0755
2 |
3 | - name: copy etcd
4 | copy:
5 | src: "{{ item.src }}"
6 | dest: "{{ item.dest }}"
7 | force: yes
8 | mode: "{{ item.mode }}"
9 | with_items:
10 | - { src: 'etcd', dest: '/usr/bin/etcd', mode: "0755" }
11 | - { src: 'etcdctl', dest: '/usr/bin/etcdctl', mode: "0755" }
12 | - { src: 'etcdctl_comp', dest: '/usr/share/bash-completion/completions/etcdctl', mode: "0644"}
13 |
14 | - name: create etcd user
15 | user: name=etcd createhome=no
16 |
17 | - name: get etcd member list
18 | local_action: shell etcdctl member list | awk '{print $2}' | awk '{print substr($1, 6)}'
19 | register: member_list
20 | failed_when: member_list.stdout == ""
21 | ignore_errors: yes
22 | changed_when: False
23 |
24 | - name: get wanted member list
25 | local_action: shell etcdctl ls /lain/nodes/etcd-members/ | awk -F '[/:]' '{print $5}'
26 | register: wanted_member_list
27 | failed_when: wanted_member_list.stdout == ""
28 | ignore_errors: yes
29 | changed_when: False
30 |
31 | - name: checking whether is adding or removing etcd member
32 | set_fact:
33 | adding_etcd_member: "{{ node_name not in member_list.stdout_lines and is_etcd_member}}"
34 | removing_etcd_member: "{{ node_name in member_list.stdout_lines and not is_etcd_member }}"
35 | when: member_list|success
36 |
37 | - name: decide whether to remove etcd data
38 | set_fact:
39 | delete_existing_etcd: true
40 | when: adding_etcd_member|bool or removing_etcd_member|bool
41 |
42 | - name: check if it is safe to change etcd(also backup etcd if yes)
43 | etcd_prepare_update:
44 | current_members: "{{ member_list.stdout_lines }}"
45 | wanted_members: "{{ wanted_member_list.stdout_lines }}"
46 | is_lain_manager: "{{ is_lain_manager }}"
47 | node_name: "{{node_name}}"
48 | ignore_errors: yes
49 |
50 | # begin to reset etcd
51 | - include: etcd-reset.yaml
52 |
53 | - name: ensure etcd service started
54 | service: name=etcd enabled=yes state=started
55 |
56 | - name: wait for etcd to be healthy
57 | shell: etcdctl cluster-health | grep "cluster is healthy"
58 | register: health_result
59 | until: health_result|success
60 | retries: 50
61 | delay: 5
62 | changed_when: False
63 |
64 | - name: wait for etcd is ready to write
65 | command: etcdctl set /lain/test test
66 | register: result
67 | until: result|success
68 | retries: 50
69 | delay: 5
70 | changed_when: False
71 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd/templates/etcd.env.j2:
--------------------------------------------------------------------------------
1 | ETCD_NAME="{{ node_name }}"
2 | ETCD_DATA_DIR="{{ etcd_dir }}/{{ node_name }}"
3 | ETCD_LISTEN_PEER_URLS="http://{{ node_ip }}:{{ etcd_peer_port }}"
4 | ETCD_LISTEN_CLIENT_URLS="http://localhost:{{ etcd_client_port }},http://{{ node_ip }}:{{ etcd_client_port }}"
5 | ETCD_ADVERTISE_CLIENT_URLS="http://{{ node_ip }}:{{ etcd_client_port }}"
6 | ETCD_INITIAL_CLUSTER="{{ etcd_cluster }}"
7 | {% if bootstrapping|bool %}
8 | ETCD_INITIAL_ADVERTISE_PEER_URLS="http://{{ node_ip }}:{{ etcd_peer_port }}"
9 | ETCD_INITIAL_CLUSTER_STATE="new"
10 | ETCD_INITIAL_CLUSTER_TOKEN="{{ cluster_token }}"
11 | {% elif is_etcd_member|bool %}
12 | ETCD_INITIAL_ADVERTISE_PEER_URLS="http://{{ node_ip }}:{{ etcd_peer_port }}"
13 | ETCD_INITIAL_CLUSTER_STATE="existing"
14 | {% else %}
15 | ETCD_PROXY="on"
16 | {% endif %}
17 |
--------------------------------------------------------------------------------
/playbooks/roles/etcd/templates/etcd.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=etcd key-value store
3 | Documentation=https://github.com/coreos/etcd
4 | After=network.target
5 |
6 | [Service]
7 | User=etcd
8 | Type=notify
9 | LimitNOFILE=65535
10 | EnvironmentFile={{ etcd_dir }}/env
11 | ExecStart=/usr/bin/etcd
12 | Restart=on-failure
13 |
14 | [Install]
15 | WantedBy=multi-user.target
16 |
--------------------------------------------------------------------------------
/playbooks/roles/firewall/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: os-dependent-vars
3 | - role: config
4 |
--------------------------------------------------------------------------------
/playbooks/roles/firewall/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | # firewall
2 | # TODO: should refine firewall configuration instead to disable it.
3 | - name: disable firewalld
4 | service: name=firewalld enabled=no state=stopped
5 | when: ansible_distribution=="CentOS"
6 |
7 | - name: mask firewalld
8 | shell: systemctl mask firewalld
9 | when: ansible_distribution=="CentOS"
10 |
11 | - name: install iptables
12 | package:
13 | name: "{{ iptables_pkt_name }}"
14 | state: present
15 |
16 | - name: enable iptables services
17 | service: name=iptables enabled=yes
18 | when: ansible_distribution == "CentOS"
19 |
20 | - name: deploy init iptables script
21 | template: src=iptables.sh.j2 dest=/tmp/iptables.sh
22 |
23 | - name: init iptables
24 | shell: bash /tmp/iptables.sh
25 |
26 | - name: deploy /etc/sysconfig/iptables
27 | template: src=iptables.save.j2 dest="{{ iptables_save_path }}" mode=600
28 |
--------------------------------------------------------------------------------
/playbooks/roles/firewall/templates/iptables.save.j2:
--------------------------------------------------------------------------------
1 | *filter
2 | :INPUT ACCEPT [0:0]
3 | :FORWARD ACCEPT [0:0]
4 | :OUTPUT ACCEPT [0:0]
5 | COMMIT
6 | *nat
7 | :PREROUTING ACCEPT [0:0]
8 | :INPUT ACCEPT [0:0]
9 | :OUTPUT ACCEPT [0:0]
10 | :POSTROUTING ACCEPT [0:0]
11 | :lain-OUTPUT - [0:0]
12 | :lain-PREROUTING - [0:0]
13 | -A PREROUTING -j lain-PREROUTING
14 | -A OUTPUT -j lain-OUTPUT
15 | COMMIT
16 |
--------------------------------------------------------------------------------
/playbooks/roles/firewall/templates/iptables.sh.j2:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | function chain_add() {
4 | iptables -n -L $1 &>/dev/null || iptables -N $1
5 | }
6 |
7 | function nat_chain_add() {
8 | iptables -t nat -n -L $1 &>/dev/null || iptables -t nat -N $1
9 | }
10 |
11 | function rule_append() {
12 | iptables -C $1 &>/dev/null || iptables -A $1
13 | }
14 |
15 | function nat_rule_append() {
16 | iptables -t nat -C $1 &>/dev/null || iptables -t nat -A $1
17 | }
18 |
19 | iptables -P INPUT ACCEPT
20 | iptables -P OUTPUT ACCEPT
21 | iptables -P FORWARD ACCEPT
22 |
23 | #iptables -D INPUT -j REJECT --reject-with icmp-host-prohibited || true
24 | #iptables -D FORWARD -j REJECT --reject-with icmp-host-prohibited || true
25 |
26 | #rule_append "INPUT -i lo -j ACCEPT"
27 | #rule_append "INPUT -i docker+ -j ACCEPT"
28 | #rule_append "INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT"
29 | #rule_append "INPUT -s {{ node_network }} -j ACCEPT"
30 | #rule_append "INPUT -s {{ calico_default_network }} -j ACCEPT"
31 | #rule_append "INPUT -p icmp -j ACCEPT"
32 | #rule_append "INPUT -p tcp --dport {{ ssh_port }} -j ACCEPT"
33 | #rule_append "FORWARD -s {{ calico_default_network }} -j ACCEPT"
34 | #{% if ansible_eth0 is defined %}
35 | #rule_append "INPUT -i eth0 -j ACCEPT"
36 | #{% endif %}
37 |
38 | nat_chain_add "lain-PREROUTING"
39 | nat_rule_append "PREROUTING -j lain-PREROUTING"
40 | nat_chain_add "lain-OUTPUT"
41 | nat_rule_append "OUTPUT -j lain-OUTPUT"
42 |
--------------------------------------------------------------------------------
/playbooks/roles/images/meta/main.yml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: bootstrap-images
4 | - role: libraries
5 |
--------------------------------------------------------------------------------
/playbooks/roles/images/tasks/main.yml:
--------------------------------------------------------------------------------
1 | - name: pull images
2 | docker_pull_image: image={{ bootstrap_images[item] }} registry=registry.lain.local
3 | with_items: "{{ images }}"
4 | when: not bootstrapping|bool
5 |
--------------------------------------------------------------------------------
/playbooks/roles/lainlet/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
--------------------------------------------------------------------------------
/playbooks/roles/lainlet/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: set lainlet's auth configuration on etcd
2 | etcd_set_key:
3 | key: /lain/config/super_apps/{{item}}
4 | value: " {}"
5 | etcd_client_port: "{{ etcd_client_port }}"
6 | with_items:
7 | - console
8 | - webrouter
9 | - tinydns
10 | - backupctl
11 | - lvault
12 | - registry
13 | - hedwig
14 | - streamrouter
15 |
16 | - name: copy lainlet binary file
17 | copy:
18 | src: lainlet
19 | dest: /usr/bin/lainlet
20 | force: yes
21 | mode: a+x
22 |
23 | - name: generate lainlet.service
24 | template:
25 | src: lainlet.service.j2
26 | dest: /etc/systemd/system/lainlet.service
27 |
28 | - name: systemctl daemon-reload
29 | command: systemctl daemon-reload
30 |
31 | - name: systemctl restart lainlet && systemctl enable lainlet
32 | service:
33 | name: lainlet
34 | state: restarted
35 | enabled: yes
36 |
37 | - name: set lainlet restart cron
38 | template: src=lainlet.cron.j2 dest=/etc/cron.d/lainlet.cron
--------------------------------------------------------------------------------
/playbooks/roles/lainlet/templates/lainlet.cron.j2:
--------------------------------------------------------------------------------
1 | 10 5 * * * root /bin/systemctl restart lainlet 2>&1 > /dev/null
--------------------------------------------------------------------------------
/playbooks/roles/lainlet/templates/lainlet.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=lainlet
3 | After=network.target
4 |
5 | [Service]
6 | LimitNOFILE=65535
7 | ExecStart=/usr/bin/lainlet \
8 | -web=:{{ lainlet_port }} \
9 | -grpc.addr=:{{ lainlet_grpc_port }} \
10 | -etcd={{ node_ip }}:{{ etcd_client_port }} \
11 | -ip={{ node_ip }} \
12 | -debug
13 | Restart=on-failure
14 |
15 | [Install]
16 | WantedBy=multi-user.target
17 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/docker_check_images.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | from subprocess import Popen, PIPE
4 |
5 | from ansible.module_utils.basic import AnsibleModule
6 |
7 |
8 | def main():
9 | module = AnsibleModule(
10 | argument_spec=dict(
11 | images=dict(type='list', required=True),
12 | ),
13 | )
14 |
15 | images = module.params['images']
16 |
17 | p = Popen(['docker', 'inspect', '-f', '{{.Id}}'] + images, stderr=PIPE)
18 | stderr = p.stderr.read()
19 | if p.wait() == 0:
20 | module.exit_json(changed=False)
21 | else:
22 | module.fail_json(msg=stderr)
23 |
24 |
25 | if __name__ == '__main__':
26 | main()
27 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/docker_inspect.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import docker
4 | from docker.errors import APIError
5 |
6 |
7 | def main():
8 | module = AnsibleModule(
9 | argument_spec=dict(
10 | name=dict(required=True),
11 | type=dict(default='container', choices=['container', 'image']),
12 | ),
13 | )
14 |
15 | name = module.params['name']
16 | type = module.params['type']
17 |
18 | client = docker.Client()
19 |
20 | if type == 'container':
21 | inspect_method = client.inspect_container
22 | elif type == 'image':
23 | inspect_method = client.inspect_image
24 | else:
25 | # should not reach here
26 | raise Exception("unknown type")
27 |
28 | try:
29 | result = inspect_method(name)
30 | except APIError as e:
31 | if e.response.status_code == 404:
32 | module.fail_json(msg="%s does not exists" % name)
33 | raise
34 |
35 | result['changed'] = False
36 | module.exit_json(**result)
37 |
38 |
39 | from ansible.module_utils.basic import *
40 | main()
41 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/docker_pull_image.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | from subprocess import call, check_call
4 |
5 |
6 | def main():
7 | module = AnsibleModule(
8 | argument_spec=dict(
9 | image=dict(required=True),
10 | registry=dict(default=''),
11 | ),
12 | )
13 |
14 | image = module.params['image']
15 | registry = module.params['registry']
16 |
17 | retval = call(['docker', 'inspect', '-f', '{{.Id}}', image])
18 | if retval == 0:
19 | # image already exists
20 | module.exit_json(changed=False)
21 |
22 | if registry:
23 | src_image = '%s/%s' % (registry, image)
24 | check_call(['docker', 'pull', src_image])
25 | check_call(['docker', 'tag', src_image, image])
26 | else:
27 | check_call(['docker', 'pull', image])
28 |
29 | module.exit_json(changed=True)
30 |
31 | from ansible.module_utils.basic import *
32 |
33 | main()
34 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/docker_push.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from subprocess import check_call
4 | from urllib2 import urlopen, HTTPError
5 |
6 |
7 | def main():
8 | module = AnsibleModule(
9 | argument_spec=dict(
10 | image=dict(required=True),
11 | registry=dict(required=True),
12 | ),
13 | )
14 |
15 | image = module.params['image']
16 | registry = module.params['registry']
17 |
18 | repo, tag = image.rsplit(':', 1)
19 | url = 'http://%s/v2/%s/manifests/%s' % (registry, repo, tag)
20 | try:
21 | urlopen(url)
22 | except HTTPError as e:
23 | if e.code != 404:
24 | raise
25 | else:
26 | # already in registry
27 | module.exit_json(changed=False)
28 |
29 | target = '%s/%s' % (registry, image)
30 | check_call(['docker', 'tag', image, target])
31 | check_call(['docker', 'push', target])
32 | module.exit_json(changed=True)
33 |
34 |
35 | from ansible.module_utils.basic import *
36 | main()
37 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/etcd_prepare_update.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import os
4 | from subprocess import check_call
5 |
6 | from ansible.module_utils.basic import AnsibleModule
7 |
8 |
9 | def main():
10 | module = AnsibleModule(
11 | argument_spec=dict(
12 | current_members=dict(type='list', required=True),
13 | wanted_members=dict(type='list', required=True),
14 | is_lain_manager=dict(type='bool', required=True),
15 | node_name=dict(type='str', required=True)
16 | ),
17 | )
18 |
19 | current_members = module.params['current_members']
20 | wanted_members = module.params['wanted_members']
21 | is_lain_manager = module.params['is_lain_manager']
22 | node_name = module.params['node_name']
23 |
24 | if len(set(current_members).symmetric_difference(set(wanted_members))) > 1:
25 | module.fail_json(msg="you can only remove or add one node a time.")
26 |
27 | msg = 'skip etcd backup'
28 | if is_lain_manager:
29 | with open(os.devnull, 'w') as fnull:
30 | data_dir = '/var/etcd/%s' % node_name
31 | tmp_dir = '/tmp/lain/etcd_backup/'
32 | check_call(['rm', '-rf', tmp_dir], stdout=fnull)
33 | check_call(['etcdctl', 'backup', '--data-dir', data_dir, '--backup-dir', tmp_dir], stdout=fnull)
34 | msg = "backup etcd to %s successfully" % tmp_dir
35 | module.exit_json(changed=True, msg=msg)
36 |
37 |
38 | if __name__ == '__main__':
39 | main()
40 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/etcd_set_key.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | from urllib2 import urlopen, HTTPError
4 | import json
5 | import os
6 | from subprocess import check_call
7 |
8 | from ansible.module_utils.basic import AnsibleModule
9 |
10 |
11 | def main():
12 | module = AnsibleModule(
13 | argument_spec=dict(
14 | key=dict(type='str', required=True),
15 | value=dict(type='str', required=True),
16 | etcd_client_port=dict(type='str', default="4001"),
17 | ),
18 | )
19 |
20 | key = module.params['key']
21 | value = module.params['value']
22 | endpoint = "http://127.0.0.1:%s" % module.params['etcd_client_port']
23 |
24 | def get_key(key):
25 | try:
26 | f = urlopen('%s/v2/keys%s' % (endpoint, key))
27 | except HTTPError as e:
28 | if e.code == 404:
29 | return None
30 | raise
31 |
32 | data = json.load(f)
33 | return data['node']['value']
34 |
35 | def set_key(key, value):
36 | with open(os.devnull, 'w') as fnull:
37 | check_call(['etcdctl', 'set', key, value], stdout=fnull)
38 |
39 | current_value = get_key(key)
40 |
41 | if current_value == value:
42 | module.exit_json(changed=False)
43 |
44 | set_key(key, value)
45 |
46 | module.exit_json(changed=True)
47 |
48 |
49 | if __name__ == '__main__':
50 | main()
51 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/get_app_proc_ip.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # get app virtual ip from networkd config (etcd)
4 | from subprocess import check_call, call, Popen, PIPE
5 | from ansible.module_utils.basic import *
6 |
7 | LAIN_VIP_PREFIX_KEY = "/lain/networkd/apps"
8 |
9 | module = AnsibleModule(
10 | argument_spec=dict(
11 | container_app=dict(required=True),
12 | container_proc=dict(required=True),
13 | ),
14 | )
15 |
16 |
17 | def main():
18 | container_app = module.params['container_app']
19 | container_proc = module.params['container_proc']
20 |
21 | changed = False
22 | config = get_proc_config(app=container_app, proc=container_proc)
23 | if not config:
24 | module.fail_json(msg="No available proc ip for %s %s" % (container_app, container_proc))
25 | ip = config.get("ip")
26 | if not ip:
27 | module.fail_json(msg="No available proc ip for %s %s" % (container_app, container_proc))
28 | port = config.get("port")
29 | if not port:
30 | module.fail_json(msg="No available proc ip for %s %s" % (container_app, container_proc))
31 | module.exit_json(changed=changed, ip=ip, port=port)
32 |
33 |
34 | def get_proc_config(app, proc):
35 | prefix = "%s/%s/%s" % (LAIN_VIP_PREFIX_KEY, app, proc)
36 | keys = list_etcd_key(prefix)
37 | if not keys:
38 | module.fail_json(msg="No available virtual ip configs")
39 | data = {}
40 | for key in keys:
41 | pair = key[len(prefix)+1:]
42 | data["ip"], data["port"] = pair.split(':')
43 | return data
44 |
45 |
46 | def list_etcd_key(key):
47 | p = Popen(['etcdctl', 'ls', key], stdout=PIPE, stderr=PIPE)
48 | output, err = p.communicate()
49 | if p.returncode == 4:
50 | if "Key not found" in err:
51 | return []
52 | else:
53 | module.fail_json(msg=err)
54 | elif p.returncode != 0:
55 | module.fail_json(msg=err)
56 | return output.rstrip().splitlines()
57 |
58 |
59 | def get_etcd_key(key):
60 | p = Popen(['etcdctl', 'get', key], stdout=PIPE, stderr=PIPE)
61 | output, err = p.communicate()
62 | if p.returncode == 4:
63 | if "Key not found" in err:
64 | return None
65 | else:
66 | module.fail_json(msg=err)
67 | elif p.returncode != 0:
68 | module.fail_json(msg=err)
69 | return output.rstrip()
70 |
71 |
72 | if __name__ == '__main__':
73 | main()
74 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/get_virtual_ip.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # get app virtual ip from networkd config (etcd)
4 | from subprocess import check_call, call, Popen, PIPE
5 | from ansible.module_utils.basic import *
6 |
7 | LAIN_VIP_PREFIX_KEY = "/lain/config/vips"
8 |
9 | module = AnsibleModule(
10 | argument_spec=dict(
11 | container_app=dict(required=True),
12 | container_proc=dict(required=True),
13 | ),
14 | )
15 |
16 |
17 | def main():
18 | container_app = module.params['container_app']
19 | container_proc = module.params['container_proc']
20 |
21 | changed = False
22 | config = get_proc_config(app=container_app, proc=container_proc)
23 | if not config:
24 | module.fail_json(msg="No available virutual ip for %s %s" % (container_app, container_proc))
25 | ip = config.get("ip")
26 | if not ip:
27 | module.fail_json(msg="No available virutual ip for %s %s" % (container_app, container_proc))
28 | module.exit_json(changed=changed, ip=ip)
29 |
30 |
31 | def get_proc_config(app, proc):
32 | keys = list_etcd_key(LAIN_VIP_PREFIX_KEY)
33 | if not keys:
34 | module.fail_json(msg="No available virtual ip configs")
35 | for key in keys:
36 | value = get_etcd_key(key)
37 | if not value:
38 | return None
39 | data = json.loads(value)
40 | config_app = data.get("app")
41 | if config_app != app:
42 | continue
43 | config_proc = data.get("proc")
44 | if config_proc != proc:
45 | continue
46 | data["ip"] = key[len(LAIN_VIP_PREFIX_KEY)+1:]
47 | return data
48 |
49 |
50 | def list_etcd_key(key):
51 | p = Popen(['etcdctl', 'ls', key], stdout=PIPE, stderr=PIPE)
52 | output, err = p.communicate()
53 | if p.returncode == 4:
54 | if "Key not found" in err:
55 | return []
56 | else:
57 | module.fail_json(msg=err)
58 | elif p.returncode != 0:
59 | module.fail_json(msg=err)
60 | return output.rstrip().splitlines()
61 |
62 |
63 | def get_etcd_key(key):
64 | p = Popen(['etcdctl', 'get', key], stdout=PIPE, stderr=PIPE)
65 | output, err = p.communicate()
66 | if p.returncode == 4:
67 | if "Key not found" in err:
68 | return None
69 | else:
70 | module.fail_json(msg=err)
71 | elif p.returncode != 0:
72 | module.fail_json(msg=err)
73 | return output.rstrip()
74 |
75 |
76 | if __name__ == '__main__':
77 | main()
78 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/post_json.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from urllib2 import Request, urlopen, HTTPError
4 | import json
5 |
6 |
7 | def main():
8 | module = AnsibleModule(
9 | argument_spec=dict(
10 | url=dict(type='str', required=True),
11 | body=dict(type='dict', required=True),
12 | header=dict(type='dict', required=False),
13 | )
14 | )
15 |
16 | url = module.params['url']
17 | body = module.params['body']
18 | header = module.params['header']
19 |
20 | req = Request(url)
21 | req.add_header('Content-Type', 'application/json')
22 | if header:
23 | for k, v in header.iteritems():
24 | req.add_header(k, v)
25 |
26 | try:
27 | urlopen(req, json.dumps(body))
28 | except HTTPError as e:
29 | module.fail_json(msg=e.reason, code=e.code, response=e.read())
30 | else:
31 | module.exit_json(changed=True)
32 |
33 | from ansible.module_utils.basic import *
34 | main()
35 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/set_config_domain.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from subprocess import Popen, PIPE
4 | from ansible.module_utils.basic import *
5 |
6 | LAIN_TINYDNS_PREFIX_KEY = "/lain/config/domains"
7 |
8 | module = AnsibleModule(
9 | argument_spec=dict(
10 | domain=dict(required=True),
11 | record=dict(required=True),
12 | ),
13 | )
14 |
15 |
16 | def main():
17 |
18 | domain = module.params['domain']
19 | record = module.params['record']
20 | changed = False
21 |
22 | old_config = get_config(domain)
23 | if not old_config:
24 | if record == "":
25 | module.exit_json(changed=changed)
26 | changed = True
27 | else:
28 | if len(old_config['ips']) > 1:
29 | changed = True
30 | elif old_config['ips'][0] != record:
31 | changed = True
32 |
33 | if changed is False:
34 | module.exit_json(changed=changed)
35 |
36 | set_config(domain, record)
37 | module.exit_json(changed=changed)
38 |
39 |
40 | def get_config(domain):
41 | key = "%s/%s" % (LAIN_TINYDNS_PREFIX_KEY, domain)
42 | value = get_etcd_key(key)
43 |
44 | if value is None:
45 | return None
46 | elif value == "":
47 | return None
48 | data = json.loads(value)
49 | return data
50 |
51 |
52 | def set_config(domain, record):
53 | key = "%s/%s" % (LAIN_TINYDNS_PREFIX_KEY, domain)
54 | if record == "":
55 | rm_etcd_key(key)
56 | return
57 | data = {"ips": [record]}
58 | value = json.dumps(data)
59 | prev_value = get_etcd_key(key)
60 | set_etcd_key(key, value, prev_value)
61 |
62 |
63 | def get_etcd_key(key):
64 | p = Popen(['etcdctl', 'get', key], stdout=PIPE, stderr=PIPE)
65 | output, err = p.communicate()
66 | if p.returncode == 4:
67 | if "Key not found" in err:
68 | return None
69 | else:
70 | module.fail_json(msg=err)
71 | elif p.returncode != 0:
72 | module.fail_json(msg=err)
73 | return output.rstrip()
74 |
75 |
76 | def set_etcd_key(key, value, prev_value=None):
77 | if prev_value is not None:
78 | cmd = ['etcdctl', 'set', key, value, '--swap-with-value', prev_value]
79 | else:
80 | cmd = ['etcdctl', 'set', key, value]
81 | p = Popen(cmd, stdout=PIPE, stderr=PIPE)
82 | output, err = p.communicate()
83 | if p.returncode != 0:
84 | module.fail_json(msg=err)
85 |
86 |
87 | def rm_etcd_key(key):
88 | cmd = ['etcdctl', 'rm', key]
89 | p = Popen(cmd, stdout=PIPE, stderr=PIPE)
90 | output, err = p.communicate()
91 | if p.returncode != 0:
92 | module.fail_json(msg=err)
93 |
94 |
95 | if __name__ == '__main__':
96 | main()
97 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/set_tinydns_domain.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from subprocess import Popen, PIPE
4 | from ansible.module_utils.basic import *
5 |
6 | LAIN_TINYDNS_PREFIX_KEY = "/lain/config/tinydns_fqdns"
7 |
8 | module = AnsibleModule(
9 | argument_spec=dict(
10 | domain=dict(required=True),
11 | record=dict(required=True),
12 | ),
13 | )
14 |
15 |
16 | def main():
17 |
18 | domain = module.params['domain']
19 | record = module.params['record']
20 | changed = False
21 |
22 | old_config = get_config(domain)
23 | if not old_config:
24 | if record == "":
25 | module.exit_json(changed=changed)
26 | changed = True
27 | else:
28 | if len(old_config) > 1:
29 | changed = True
30 | elif old_config[0] != record:
31 | changed = True
32 |
33 | if changed is False:
34 | module.exit_json(changed=changed)
35 |
36 | set_config(domain, record)
37 | module.exit_json(changed=changed)
38 |
39 |
40 | def get_config(domain):
41 | key = "%s/%s" % (LAIN_TINYDNS_PREFIX_KEY, domain)
42 | value = get_etcd_key(key)
43 |
44 | if value is None:
45 | return None
46 | elif value == "":
47 | return None
48 | data = json.loads(value)
49 | return data
50 |
51 |
52 | def set_config(domain, record):
53 | key = "%s/%s" % (LAIN_TINYDNS_PREFIX_KEY, domain)
54 | if record == "":
55 | rm_etcd_key(key)
56 | return
57 | data = [record]
58 | value = json.dumps(data)
59 | prev_value = get_etcd_key(key)
60 | set_etcd_key(key, value, prev_value)
61 |
62 |
63 | def get_etcd_key(key):
64 | p = Popen(['etcdctl', 'get', key], stdout=PIPE, stderr=PIPE)
65 | output, err = p.communicate()
66 | if p.returncode == 4:
67 | if "Key not found" in err:
68 | return None
69 | else:
70 | module.fail_json(msg=err)
71 | elif p.returncode != 0:
72 | module.fail_json(msg=err)
73 | return output.rstrip()
74 |
75 |
76 | def set_etcd_key(key, value, prev_value=None):
77 | if prev_value is not None:
78 | cmd = ['etcdctl', 'set', key, value, '--swap-with-value', prev_value]
79 | else:
80 | cmd = ['etcdctl', 'set', key, value]
81 | p = Popen(cmd, stdout=PIPE, stderr=PIPE)
82 | output, err = p.communicate()
83 | if p.returncode != 0:
84 | module.fail_json(msg=err)
85 |
86 |
87 | def rm_etcd_key(key):
88 | cmd = ['etcdctl', 'rm', key]
89 | p = Popen(cmd, stdout=PIPE, stderr=PIPE)
90 | output, err = p.communicate()
91 | if p.returncode != 0:
92 | module.fail_json(msg=err)
93 |
94 |
95 | if __name__ == '__main__':
96 | main()
97 |
--------------------------------------------------------------------------------
/playbooks/roles/libraries/library/set_virtual_ip.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from subprocess import check_call, call, Popen, PIPE
4 | from ansible.module_utils.basic import *
5 |
6 | module = AnsibleModule(
7 | argument_spec=dict(
8 | ip=dict(required=True),
9 | device=dict(required=True),
10 | ),
11 | )
12 |
13 |
14 | def main():
15 | ip = module.params['ip']
16 | device = module.params['device']
17 | changed = set_vip(ip, device)
18 | module.exit_json(changed=changed)
19 |
20 |
21 | def set_vip(ip, device):
22 | if get_vip(ip, device):
23 | return False
24 | cmd = ['ip', 'addr', 'add', '%s/32' % ip, 'dev', device]
25 | p = Popen(cmd, stdout=PIPE, stderr=PIPE)
26 | output, err = p.communicate()
27 | if p.returncode != 0:
28 | module.fail_json(msg=err)
29 | return True
30 |
31 |
32 | def get_vip(ip, device):
33 | cmd = ['ip', 'addr', 'show', 'dev', device]
34 | p = Popen(cmd, stdout=PIPE, stderr=PIPE)
35 | output, err = p.communicate()
36 | if p.returncode != 0:
37 | module.fail_json(msg="ip addr show failed. stdout: %r" % output)
38 | if ' %s/32 ' % ip in output:
39 | return True
40 | return False
41 |
42 |
43 | if __name__ == '__main__':
44 | main()
45 |
--------------------------------------------------------------------------------
/playbooks/roles/lvault-app/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 |
3 | - role: console-deploy
4 | app: lvault
5 |
--------------------------------------------------------------------------------
/playbooks/roles/manager/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - config
3 |
--------------------------------------------------------------------------------
/playbooks/roles/manager/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: generate ssh key pair for cluster management
2 | command: ssh-keygen -t rsa -N "" -f /root/.ssh/lain
3 | args:
4 | creates: /root/.ssh/lain
5 | when: is_lain_manager
6 |
7 | - name: copy ssh key pair for cluster management
8 | copy: src=/root/.ssh/{{ item }} dest=/root/.ssh/{{ item }}
9 | with_items:
10 | - lain
11 | - lain.pub
12 | when: is_lain_manager
13 |
14 | - name: generate ssh finger print
15 | command: ssh-keyscan -t rsa {{ node_ip }}
16 | register: result
17 | changed_when: False
18 | delegate_to: 127.0.0.1
19 |
20 | - name: put the ssh finger print in known_hosts
21 | lineinfile: dest=/root/.ssh/known_hosts line='{{ result.stdout_lines | last }}' create=yes
22 | delegate_to: 127.0.0.1
23 |
24 | - name: authorize the management ssh key
25 | authorized_key: user=root key="{{ lookup('file', '/root/.ssh/lain.pub') }}"
26 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for moosefs-build
2 | command: systemctl daemon-reload
3 |
4 | - name: restart mfsmaster
5 | service: name=mfsmaster state=restarted
6 |
7 | - name: restart mfschunkserver
8 | service: name=mfschunkserver state=restarted
9 |
10 | - name: restart mfscgiserv
11 | service: name=mfscgiserv state=restarted
12 |
13 | - name: restart mfsmetalogger
14 | service: name=mfsmetalogger state=restarted
15 |
16 | - name: reload mfsmaster
17 | service: name=mfsmaster state=reloaded
18 |
19 | - name: reload mfschunkserver
20 | service: name=mfschunkserver state=reloaded
21 |
22 | - name: reload mfsmetalogger
23 | service: name=mfsmetalogger state=reloaded
24 |
25 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: binary
4 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/tasks/chunkserver.yaml:
--------------------------------------------------------------------------------
1 | - name: create mfs dir
2 | file: path={{ item }} state=directory group=mfs owner=mfs
3 | with_items: "{{ mfs_data_dir }}"
4 |
5 | - name: prepare mfshdd config file for mfschunkserver
6 | template: src=config/mfshdd.cfg.j2 dest=/etc/mfs/mfshdd.cfg
7 | notify:
8 | - reload mfschunkserver
9 |
10 | - name: generate configuration file for mfschunkserver
11 | template: src=config/mfschunkserver.cfg.j2 dest=/etc/mfs/mfschunkserver.cfg
12 | notify:
13 | - reload mfschunkserver
14 |
15 | - name: config mfschunkserver service
16 | template: src=service/mfschunkserver.service.j2 dest=/etc/systemd/system/mfschunkserver.service
17 | notify:
18 | - reload systemd for moosefs-build
19 | - restart mfschunkserver
20 |
21 | - meta: flush_handlers
22 |
23 | - name: ensure moosefs chunkserver started
24 | service: name=mfschunkserver enabled=yes state=started
25 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: extract moosefs rpm package
2 | command: tar --overwrite -z -x -f /tmp/lain/moosefs-3.0.47.tar.gz -C /tmp/
3 |
4 | - name: install moosefs
5 | yum: name=/tmp/fuse-libs-2.9.2-5.el7.x86_64.rpm,/tmp/moosefs-cgi-3.0.47-1.rhsysv.x86_64.rpm,/tmp/moosefs-cgiserv-3.0.47-1.rhsysv.x86_64.rpm,/tmp/moosefs-chunkserver-3.0.47-1.rhsysv.x86_64.rpm,/tmp/moosefs-cli-3.0.47-1.rhsysv.x86_64.rpm,/tmp/moosefs-client-3.0.47-1.rhsysv.x86_64.rpm,/tmp/moosefs-master-3.0.47-1.rhsysv.x86_64.rpm,/tmp/moosefs-metalogger-3.0.47-1.rhsysv.x86_64.rpm,fuse
6 |
7 | - include: master.yaml
8 | when: is_moosefs_master
9 |
10 | - command: etcdctl get /lain/config/moosefs
11 | register: result
12 | failed_when: result.stdout == ""
13 |
14 | - name: write moosefs master addr into /etc/hosts
15 | lineinfile: dest=/etc/hosts line="{{ result.stdout.split(":")[0] }} mfsmaster" insertafter=EOF
16 |
17 | - include: chunkserver.yaml
18 | when: is_moosefs_chunkserver
19 |
20 | - include: metalogger.yaml
21 | when: is_moosefs_metalogger
22 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/tasks/master.yaml:
--------------------------------------------------------------------------------
1 | - name: gernerate configuration file for mfsmaster
2 | template: src=config/mfsmaster.cfg.j2 dest=/etc/mfs/mfsmaster.cfg
3 | notify:
4 | - reload mfsmaster
5 |
6 | - name: config mfsmaster service
7 | template: src=service/mfsmaster.service.j2 dest=/etc/systemd/system/mfsmaster.service
8 | notify:
9 | - reload systemd for moosefs-build
10 | - restart mfsmaster
11 |
12 | - name: config mfscgiserv service
13 | template: src=service/mfscgiserv.service.j2 dest=/etc/systemd/system/mfscgiserv.service
14 | notify:
15 | - reload systemd for moosefs-build
16 | - restart mfscgiserv
17 |
18 | - meta: flush_handlers
19 |
20 | - name: ensure moosefs master started
21 | service: name=mfsmaster enabled=yes state=started
22 |
23 | - name: ensure moosefs cgiserv started
24 | service: name=mfscgiserv enabled=yes state=started
25 |
26 | - name: write moosefs master's address into etcd
27 | command: etcdctl set /lain/config/moosefs "{{ node_ip }}:{{ mfsport }}"
28 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/tasks/metalogger.yaml:
--------------------------------------------------------------------------------
1 | - name: gernerate configuration file for mfsmetalogger
2 | template: src=config/mfsmetalogger.cfg.j2 dest=/etc/mfs/mfsmetalogger.cfg
3 | notify:
4 | - reload mfsmetalogger
5 |
6 | - name: config mfsmetalogger service
7 | template: src=service/mfsmetalogger.service.j2 dest=/etc/systemd/system/mfsmetalogger.service
8 | notify:
9 | - reload systemd for moosefs-build
10 | - restart mfsmetalogger
11 |
12 | - name: ensure moosefs metalogger started
13 | service: name=mfsmetalogger enabled=yes state=started
14 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/templates/config/mfshdd.cfg.j2:
--------------------------------------------------------------------------------
1 | # This file keeps definitions of mounting points (paths) of hard drives to use with chunk server.
2 | # A path may begin with extra '*', which means this hard drive is 'marked for removal' and all data will be replicated to other hard drives (usually on other chunkservers).
3 | # It is possible to specify optional space limit (after each mounting point), there are two ways of doing that:
4 | # - set space to be left unused on a hard drive (this overrides the default setting from mfschunkserver.cfg)
5 | # - limit space to be used on a hard drive
6 | # Space limit definition: [0-9]*(.[0-9]*)?([kMGTPE]|[KMGTPE]i)?B?, add minus in front for the first option.
7 | #
8 | # Examples:
9 | #
10 | # use hard drive '/mnt/hd1' with default options:
11 | #/mnt/hd1
12 | #
13 | # use hard drive '/mnt/hd2', but replicate all data from it:
14 | #*/mnt/hd2
15 | #
16 | # use hard drive '/mnt/hd3', but try to leave 5GiB on it:
17 | #/mnt/hd3 -5GiB
18 | #
19 | # use hard drive '/mnt/hd4', but use only 1.5TiB on it:
20 | #/mnt/hd4 1.5TiB
21 | {% for dir in mfs_data_dir %}
22 | {{ dir }}
23 | {% endfor %}
24 |
25 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/templates/config/mfsmetalogger.cfg.j2:
--------------------------------------------------------------------------------
1 | ###############################################
2 | # RUNTIME OPTIONS #
3 | ###############################################
4 |
5 | # user to run daemon as (default is mfs)
6 | # WORKING_USER = mfs
7 |
8 | # group to run daemon as (optional - if empty then default user group will be used)
9 | # WORKING_GROUP = mfs
10 |
11 | # name of process to place in syslog messages (default is mfsmetalogger)
12 | # SYSLOG_IDENT = mfsmetalogger
13 |
14 | # whether to perform mlockall() to avoid swapping out mfsmetalogger process (default is 0, i.e. no)
15 | # LOCK_MEMORY = 0
16 |
17 | # nice level to run daemon with (default is -19; note: process must be started as root to increase priority, if setting of priority fails, process retains the nice level it started with)
18 | # NICE_LEVEL = -19
19 |
20 | # set default umask for group and others (user has always 0, default is 027 - block write for group and block all for others)
21 | # FILE_UMASK = 027
22 |
23 | # where to store daemon lock file (default is /var/lib/mfs)
24 | # DATA_PATH = /var/lib/mfs
25 |
26 | # number of metadata change log files (default is 50)
27 | # BACK_LOGS = 50
28 |
29 | # number of previous metadata files to be kept (default is 3)
30 | # BACK_META_KEEP_PREVIOUS = 3
31 |
32 | # metadata download frequency in hours (default is 24, should be at least BACK_LOGS/2)
33 | # META_DOWNLOAD_FREQ = 24
34 |
35 | ###############################################
36 | # MASTER CONNECTION OPTIONS #
37 | ###############################################
38 |
39 | # delay in seconds before next try to reconnect to master if not connected (default is 5)
40 | # MASTER_RECONNECTION_DELAY = 5
41 |
42 | # local address to use for connecting with master (default is *, i.e. default local address)
43 | # BIND_HOST = *
44 |
45 | # MooseFS master host, IP is allowed only in single-master installations (default is mfsmaster)
46 | # MASTER_HOST = mfsmaster
47 |
48 | # MooseFS master supervisor port (default is 9419)
49 | # MASTER_PORT = 9419
50 |
51 | # timeout in seconds for master connections (default is 10)
52 | # MASTER_TIMEOUT = 10
53 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/templates/config/mfsmount.cfg.j2:
--------------------------------------------------------------------------------
1 | # The optional mfsmount.cfg file can be used to specify defaults for mfsmount.
2 | # Default mount options can be specified on one line separated by commas or
3 | # over several lines.
4 | #
5 | # Examples:
6 | #
7 | # nosuid,nodev
8 | # mfsmaster=mfsmaster
9 | # mfspassword=secret
10 | #
11 | # The default mount point can also be set. The default mount point must begin
12 | # with a "/" and be a fully qualified path.
13 | #
14 | # Example:
15 | #
16 | # /mnt/mfs
17 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/templates/service/mfscgiserv.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=mfscgiserv
3 | After=network.target
4 |
5 | [Service]
6 | ExecStart=/usr/sbin/mfscgiserv -f start
7 | ExecStop=/usr/sbin/mfscgiserv stop
8 | Restart=always
9 |
10 | [Install]
11 | WantedBy=multi-user.target
12 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/templates/service/mfschunkserver.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=mfschunkserver
3 | After=network.target
4 |
5 | [Service]
6 | ExecStart=/usr/sbin/mfschunkserver -f start
7 | ExecStop=/usr/sbin/mfschunkserver stop
8 | ExecReload=/usr/sbin/mfschunkserver -f reload
9 | Restart=on-failure
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/templates/service/mfsmaster.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=mfsmaster
3 | After=network.target
4 |
5 | [Service]
6 | ExecStart=/usr/sbin/mfsmaster -a -f start
7 | ExecStop=/usr/sbin/mfsmaster stop
8 | ExecReload=/usr/sbin/mfsmaster -f reload
9 | Restart=always
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs-build/templates/service/mfsmetalogger.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=mfsmetalogger
3 | After=network.target
4 |
5 | [Service]
6 | ExecStart=/usr/sbin/mfsmetalogger -f start
7 | ExecStop=/usr/sbin/mfsmetalogger stop
8 | ExecReload=/usr/sbin/mfsmetalogger -f reload
9 | Restart=on-failure
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: binary
3 |
--------------------------------------------------------------------------------
/playbooks/roles/moosefs/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - fail: msg="moosefs master address not exist in /lain/config/moosefs"
2 | when: mfsmaster == ""
3 |
4 |
5 | - name: extract moosefs rpm package
6 | command: tar --overwrite -z -x -f /tmp/lain/moosefs-3.0.47.tar.gz -C /tmp/
7 |
8 | - name: install moosefs
9 | yum: name=/tmp/fuse-libs-2.9.2-5.el7.x86_64.rpm,/tmp/moosefs-cli-3.0.47-1.rhsysv.x86_64.rpm,/tmp/moosefs-client-3.0.47-1.rhsysv.x86_64.rpm,fuse
10 |
11 | - name: write moosefs master addr into /etc/hosts
12 | lineinfile: dest=/etc/hosts line="{{ mfsmaster }} mfsmaster" insertafter=EOF
13 |
14 | - name: create /mfs
15 | file: path=/mfs state=directory
16 |
17 | - name: check if /mfs mounted
18 | command: mfsdirinfo /mfs
19 | register: result
20 | ignore_errors: yes
21 |
22 | - name: set /etc/fstab, automount moosefs
23 | lineinfile: dest=/etc/fstab line="mfsmount /mfs fuse _netdev 0 0" insertafter=EOF
24 |
25 | # mfsmount may failed. it return error "EAGAIN (Resource temporarily unavailable)", means we need to try again later
26 | # try 5 time every 5 seconds.
27 | - name: mount /mfs -P "{{ mfsport }}"
28 | command: mount /mfs
29 | register: mount_result
30 | until: mount_result|success
31 | retries: 50
32 | delay: 5
33 | when: result|failed
34 |
--------------------------------------------------------------------------------
/playbooks/roles/mysql/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: images
4 | images:
5 | - mysql
--------------------------------------------------------------------------------
/playbooks/roles/mysql/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: run container
2 | command: |
3 | docker run -d
4 | --name mysql_container
5 | --net=host
6 | -e MYSQL_ALLOW_EMPTY_PASSWORD=yes
7 | -v {{ mysql_data_dir }}:/var/lib/mysql
8 | {{ mysql_image }}
9 |
10 | - name: wait to make sure MySQL being started
11 | wait_for: port=3306 state=started timeout=15
12 |
13 | - name: initialize databases
14 | command: |
15 | docker exec mysql_container mysql -uroot -e "
16 | CREATE DATABASE IF NOT EXISTS console;
17 | GRANT ALL ON console.* TO console@'%' IDENTIFIED BY 'console';
18 | FLUSH PRIVILEGES;
19 | "
20 |
--------------------------------------------------------------------------------
/playbooks/roles/network-recover/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: libraries
--------------------------------------------------------------------------------
/playbooks/roles/network-recover/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: inspect docker network
2 | inspect_docker_network:
3 | node: "{{ recover_node }}"
4 | app: "{{ recover_app }}"
5 | proc: "{{ recover_proc }}"
6 | instance_number: "{{ recover_instance_number }}"
7 | client_app: "{{ recover_client_app }}"
8 | register: result
9 |
10 | - set_fact: network_id="{{ result.network_id }}"
11 | when: result|success
12 |
13 | - set_fact: endpoint_id="{{ result.endpoint_id }}"
14 | when: result|success
15 |
16 | - set_fact: recycle_ip="{{ result.recycle_ip }}"
17 | when: result|success
18 |
19 | - name: remove dirty endpoint in docker directory of etcd
20 | shell: etcdctl rm /docker/network/v1.0/endpoint/{{ network_id }}/{{ endpoint_id }}
21 | ignore_errors: yes
22 | when: is_lain_manager and result|success
23 |
24 | - name: remove dirty endpoint in calico directory of etcd
25 | shell: etcdctl rm /calico/v1/host/{{ recover_node }}/workload/libnetwork/libnetwork/endpoint/{{ endpoint_id }}
26 | ignore_errors: yes
27 | when: is_lain_manager and result|success
28 |
29 | - name: recycle the used ip
30 | shell: calicoctl ipam release --ip {{ recycle_ip }}
31 | when: is_lain_manager and result|success
32 |
--------------------------------------------------------------------------------
/playbooks/roles/networkd-preupgrade/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | # ansible bug: get_url fails to retrieve https url through http proxy, so just use command
2 | - name: get networkd:v2.4.0
3 | command: wget https://lain.oss-cn-beijing.aliyuncs.com/binary/networkd/releases/download/v2.4.0/networkd.xz -O /tmp/networkd.xz
4 |
5 | - name: unxz networkd.xz
6 | command: unxz -kf /tmp/networkd.xz
7 |
8 | - name: set etcd domains from /etc/dnsmasq.conf
9 | command: etcdctl set /lain/config/domains/{{ item.split('/')[-2] }} '{"ips":[],"type":"node"}'
10 | with_lines: cat /etc/dnsmasq.conf
11 | when: item | regex_search('(^address=)') and not item | regex_search('(^address=/lain.local)')
12 |
13 | - name: set etcd domain for *.lain.local
14 | command: etcdctl set /lain/config/domains/*.lain.local '{"ips":[],"type":"webrouter"}'
15 |
16 | - name: load dnshijack keys from etcd
17 | command: etcdctl ls /lain/config/dnshijack
18 | register: hijack_domain_list
19 | ignore_errors: yes
20 | changed_when: False
21 |
22 | - name : load dnshijack settings from etcd
23 | command: etcdctl get {{ item.1 }}
24 | register: hijack_ip_list
25 | with_indexed_items: "{{ hijack_domain_list.stdout_lines }}"
26 | when: hijack_domain_list|success and hijack_domain_list.stdout != ""
27 | changed_when: False
28 |
29 | - name: set etcd domains from dnshijack
30 | command: etcdctl set /lain/config/domains/*.{{ item.1.split('/')[-1] }} '{"ips":["{{ hijack_ip_list.results[item.0].stdout }}"],"type":""}'
31 | with_indexed_items: "{{ hijack_domain_list.stdout_lines }}"
32 | when: hijack_domain_list|success and hijack_domain_list.stdout != ""
33 |
34 | - name: load dnsmasq_addresses keys from etcd
35 | command: etcdctl ls /lain/config/dnsmasq_addresses
36 | register: dnsmasq_domain_list
37 | ignore_errors: yes
38 | changed_when: False
39 |
40 | - name: load dnsmasq_addresses settings from etcd
41 | command: etcdctl get {{ item }}
42 | register: dnsmasq_ip_list
43 | with_items: " {{ dnsmasq_domain_list.stdout_lines }} "
44 | when: dnsmasq_domain_list|success and dnsmasq_domain_list.stdout != ""
45 | changed_when: False
46 |
47 | - name: set etcd domains from dnsmasq_addresses
48 | command: etcdctl set /lain/config/domains/{{ item.1.split('/')[-1] }} '{{ dnsmasq_ip_list.results[item.0].stdout }}'
49 | with_indexed_items: "{{ dnsmasq_domain_list.stdout_lines }}"
50 | when: dnsmasq_domain_list|success and dnsmasq_domain_list.stdout != ""
51 |
--------------------------------------------------------------------------------
/playbooks/roles/networkd-rollback/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: rollback networkd
2 | copy:
3 | remote_src: True
4 | src: /usr/bin/networkd.back
5 | dest: /usr/bin/networkd
6 | force: yes
7 |
8 | - name: rollback networkd.service
9 | copy:
10 | remote_src: True
11 | src: /etc/systemd/system/networkd.service.back
12 | dest: /etc/systemd/system/networkd.service
13 | force: yes
14 |
15 | - name: systemctl daemon-reload
16 | command: systemctl daemon-reload
17 |
18 | - name: systemctl restart networkd && systemctl enable networkd
19 | service:
20 | name: networkd
21 | state: restarted
22 | enabled: yes
23 |
24 | - name: systemctl restart dnsmasq && systemctl enable dnsmasq
25 | service:
26 | name: dnsmasq
27 | state: started
28 | enabled: yes
29 |
30 |
--------------------------------------------------------------------------------
/playbooks/roles/networkd-update/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | # this role is used to update networkd binary, the updated networkd binary should be located at dir: ../files
2 | - name: copy networkd binary file
3 | copy:
4 | src: networkd
5 | dest: /usr/bin/networkd
6 | force: yes
7 | mode: a+x
8 |
9 | - name: systemctl restart networkd && systemctl enable networkd
10 | service:
11 | name: networkd
12 | state: restarted
13 | enabled: yes
14 |
15 |
--------------------------------------------------------------------------------
/playbooks/roles/networkd-upgrade/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
--------------------------------------------------------------------------------
/playbooks/roles/networkd-upgrade/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: backup original networkd
2 | copy:
3 | remote_src: True
4 | src: /usr/bin/networkd
5 | dest: /usr/bin/networkd.back
6 | force: yes
7 |
8 | - name: backup original networkd.service
9 | copy:
10 | remote_src: True
11 | src: /etc/systemd/system/networkd.service
12 | dest: /etc/systemd/system/networkd.service.back
13 | force: yes
14 |
15 | - name: copy networkd binary file
16 | copy:
17 | src: /tmp/networkd
18 | dest: /usr/bin/networkd
19 | force: yes
20 | mode: a+x
21 |
22 | - name: install arping
23 | # package name is iputils-arping not arping
24 | package: name=iputils-arping state=present
25 | when: ansible_distribution=="Ubuntu"
26 |
27 | - name: generate networkd.service
28 | template:
29 | src: networkd.service.j2
30 | dest: /etc/systemd/system/networkd.service
31 |
32 | - name: systemctl stop dnsmasq && systemctl disable dnsmasq
33 | service:
34 | name: dnsmasq
35 | state: stopped
36 | enabled: no
37 |
38 | - name: systemctl daemon-reload
39 | command: systemctl daemon-reload
40 |
41 | - name: systemctl restart networkd && systemctl enable networkd
42 | service:
43 | name: networkd
44 | state: restarted
45 | enabled: yes
46 |
--------------------------------------------------------------------------------
/playbooks/roles/networkd-upgrade/templates/networkd.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=networkd
3 | After=network.target lainlet.service
4 |
5 | [Service]
6 | Environment=ETCD_AUTHORITY=127.0.0.1:{{ etcd_client_port }}
7 | LimitNOFILE=65535
8 | ExecStart=/usr/bin/networkd {% if domain == 'lain.local' and vip == '0.0.0.0' %}--domain=lain.local{% endif %} \
9 | --net.interface={{ net_interface }} \
10 | --lainlet.endpoint={{ node_ip }}:{{ lainlet_port }} \
11 | --etcd.endpoint=http://{{ node_ip }}:{{ etcd_client_port }} \
12 | --libnetwork \
13 | --tinydns \
14 | --swarm \
15 | --deployd \
16 | --webrouter \
17 | --streamrouter \
18 | --godns.addr=0.0.0.0:53
19 |
20 | Restart=on-failure
21 |
22 | [Install]
23 | WantedBy=multi-user.target
24 |
--------------------------------------------------------------------------------
/playbooks/roles/networkd/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: lainlet
4 |
--------------------------------------------------------------------------------
/playbooks/roles/networkd/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: copy networkd binary file
2 | copy:
3 | src: networkd
4 | dest: /usr/bin/networkd
5 | force: yes
6 | mode: a+x
7 |
8 | - name: install arping
9 | # package name is iputils-arping not arping
10 | package: name=iputils-arping state=present
11 | when: ansible_distribution=="Ubuntu"
12 |
13 | - name: generate networkd.service
14 | template:
15 | src: networkd.service.j2
16 | dest: /etc/systemd/system/networkd.service
17 |
18 | - name: systemctl daemon-reload
19 | command: systemctl daemon-reload
20 |
21 | - name: systemctl restart networkd && systemctl enable networkd
22 | service:
23 | name: networkd
24 | state: restarted
25 | enabled: yes
26 |
--------------------------------------------------------------------------------
/playbooks/roles/networkd/templates/networkd.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=networkd
3 | After=network.target lainlet.service
4 |
5 | [Service]
6 | Environment=ETCD_AUTHORITY=127.0.0.1:{{ etcd_client_port }}
7 | LimitNOFILE=65535
8 | ExecStart=/usr/bin/networkd {% if domain == 'lain.local' and vip == '0.0.0.0' %}--domain=lain.local{% endif %} \
9 | --net.interface={{ net_interface }} \
10 | --lainlet.endpoint={{ node_ip }}:{{ lainlet_port }} \
11 | --etcd.endpoint=http://{{ node_ip }}:{{ etcd_client_port }} \
12 | --libnetwork \
13 | --tinydns \
14 | --swarm \
15 | --deployd \
16 | --webrouter \
17 | --streamrouter \
18 | --godns.addr=0.0.0.0:53
19 |
20 | Restart=on-failure
21 |
22 | [Install]
23 | WantedBy=multi-user.target
24 |
--------------------------------------------------------------------------------
/playbooks/roles/node-change-labels/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: read current /etc/docker/daemon.json
2 | command: cat /etc/docker/daemon.json
3 | register: result
4 |
5 | - name: set old_docker_daemon_json
6 | set_fact:
7 | old_docker_daemon_json: '{{ result.stdout | from_json }}'
8 |
9 | - name: set old_labels
10 | set_fact:
11 | old_labels: '{{ old_docker_daemon_json.labels | default([]) }}'
12 |
13 | - name: merge diff_labels to old_labels when change_type == add
14 | set_fact:
15 | new_labels: '{{ old_labels | union(diff_labels) }}'
16 | when: change_type == "add"
17 |
18 | - name: delete diff_labels from old_labels when change_type == delete
19 | set_fact:
20 | new_labels: '{{ old_labels | difference(diff_labels) }}'
21 | when: change_type == "delete"
22 |
23 | - name: set new_docker_daemon_json
24 | set_fact:
25 | new_docker_daemon_json: '{{ old_docker_daemon_json | combine({"labels": new_labels}) | to_nice_json }}'
26 |
27 | - name: generate new /etc/docker/daemon.json
28 | template:
29 | src: docker-daemon.json.j2
30 | dest: /etc/docker/daemon.json
31 | owner: root
32 | group: root
33 | mode: 0644
34 |
35 | - name: reload docker
36 | service:
37 | name: docker
38 | state: reloaded
39 |
--------------------------------------------------------------------------------
/playbooks/roles/node-change-labels/templates/docker-daemon.json.j2:
--------------------------------------------------------------------------------
1 | {{ new_docker_daemon_json }}
2 |
--------------------------------------------------------------------------------
/playbooks/roles/node-clean/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: libraries
3 |
--------------------------------------------------------------------------------
/playbooks/roles/node-clean/tasks/image-clean.yaml:
--------------------------------------------------------------------------------
1 | - name: collect running images
2 | shell: docker ps --format \{\{.Image\}\} | awk '{split($1, array, ":"); print array[1]}'
3 | register: images
4 | changed_when: False
5 |
6 | - name: display to-save images of each node
7 | debug: var=images.stdout_lines
8 |
9 | - name: "check finding the correct images to save. Next: clean images"
10 | pause: seconds=600
11 |
12 | - name: remove extra images
13 | image_clean:
14 | images: "{{ images.stdout_lines }}"
15 | redundancy: 3
16 |
--------------------------------------------------------------------------------
/playbooks/roles/node-clean/tasks/log-clean.yaml:
--------------------------------------------------------------------------------
1 | - name: collect log files need to clean in /var/log
2 | shell: ls -1 /var/log/messages-*
3 | register: log_files
4 | changed_when: False
5 | ignore_errors: yes
6 |
7 | - name: display the log files need to clean of each node
8 | debug: var=log_files.stdout_lines
9 | when: log_files|success
10 |
11 | - name: "check finding the correct log files to clean. Next: clean log files"
12 | pause: seconds=600
13 | when: log_files|success
14 |
15 | - name: clean log files in /var/log
16 | command: /usr/bin/rm -f {{ item }}
17 | with_items: "{{ log_files.stdout_lines }}"
18 | when: log_files|success and log_files.stdout != ""
19 |
--------------------------------------------------------------------------------
/playbooks/roles/node-clean/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - include: log-clean.yaml
2 |
3 | - include: image-clean.yaml
4 |
--------------------------------------------------------------------------------
/playbooks/roles/node-disable-log-driver/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: read current /etc/docker/daemon.json
2 | command: cat /etc/docker/daemon.json
3 | register: result
4 |
5 | - name: set old_docker_daemon_json
6 | set_fact:
7 | old_docker_daemon_json: '{{ result.stdout | from_json }}'
8 | new_docker_daemon_json: {}
9 |
10 | - name: initialize new_docker_daemon_json without `log-opts`
11 | set_fact:
12 | new_docker_daemon_json: '{{ new_docker_daemon_json | combine({item.key: item.value}) }}'
13 | when: item.key != "log-opts"
14 | with_dict: '{{ old_docker_daemon_json }}'
15 |
16 | - name: set `log-driver` to none in new_docker_daemon_json
17 | set_fact:
18 | new_docker_daemon_json: '{{ new_docker_daemon_json | combine({"log-driver": "none"}) | to_nice_json }}'
19 |
20 | - name: generate new /etc/docker/daemon.json
21 | template:
22 | src: docker-daemon.json.j2
23 | dest: /etc/docker/daemon.json
24 | owner: root
25 | group: root
26 | mode: 0644
27 |
28 | - name: restart docker
29 | service:
30 | name: docker
31 | state: restarted
32 |
--------------------------------------------------------------------------------
/playbooks/roles/node-disable-log-driver/templates/docker-daemon.json.j2:
--------------------------------------------------------------------------------
1 | {{ new_docker_daemon_json }}
2 |
--------------------------------------------------------------------------------
/playbooks/roles/node/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 | - role: etcd
5 | - role: consul
6 | - role: prepare
7 | - role: firewall
8 | - role: binary
9 | - role: manager
10 | - role: docker
11 | - role: calico
12 | - role: ssl
13 | - role: lainlet
14 | - role: rebellion
15 | - role: networkd
16 | - role: moosefs
17 | when: mfsmaster != ""
18 | - role: backupd
19 | when: backup_enabled is defined and backup_enabled == "True"
20 | - role: registry
21 | action: "usemfs"
22 | when: registry_on_moosefs is defined and registry_on_moosefs == "True"
23 | - role: rsync
24 | - role: swarm
25 |
--------------------------------------------------------------------------------
/playbooks/roles/os-dependent-vars/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: Load a variable file based on the OS type
2 | include_vars: "{{ item }}"
3 | with_first_found:
4 | - "../vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version | int}}.yml"
5 | - "../vars/{{ ansible_distribution }}.yml"
6 | - "../vars/{{ ansible_os_family }}.yml"
7 | - "../vars/default.yml"
8 |
--------------------------------------------------------------------------------
/playbooks/roles/os-dependent-vars/vars/CentOS.yml:
--------------------------------------------------------------------------------
1 | rsync_service_name: rsyncd
2 | rsync_service_path: /usr/lib/systemd/system/rsyncd.service
3 |
4 | conntrack_pkt_name: conntrack-tools
5 |
6 | iptables_pkt_name: iptables-services
7 | iptables_save_path: /etc/sysconfig/iptables
8 |
9 | docker_service_path: /usr/lib/systemd/system/docker.service
10 |
11 | collectd_conf_path: /etc/collectd.conf
12 | collectd_conf_dir: /etc/collectd.d
13 |
--------------------------------------------------------------------------------
/playbooks/roles/os-dependent-vars/vars/Ubuntu.yml:
--------------------------------------------------------------------------------
1 | rsync_service_name: rsync
2 | rsync_service_path: /lib/systemd/system/rsync.service
3 |
4 | conntrack_pkt_name: conntrack
5 |
6 | iptables_pkt_name: iptables-persistent
7 | iptables_save_path: /etc/iptables/iptables
8 |
9 | docker_service_path: /lib/systemd/system/docker.service
10 |
11 | collectd_conf_path: /etc/collectd/collectd.conf
12 | collectd_conf_dir: /etc/collectd/collectd.conf.d
13 |
--------------------------------------------------------------------------------
/playbooks/roles/packages/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 |
--------------------------------------------------------------------------------
/playbooks/roles/packages/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: install pip
2 | package: name=python-pip state=present
3 |
4 | - name: install python packages
5 | command: pip install --upgrade --force-reinstall {{ item }}
6 | with_items:
7 | - pip
8 | - python-dateutil==2.5.2
9 | - python-etcd==0.4.3
10 | - docker-py==1.8.0
11 | - psutil==4.1.0
12 | - requests==2.11.1
13 | register: result
14 | changed_when: "'Successfully installed' in result.stdout"
15 |
16 | - name: install lainctl
17 | command: pip install --upgrade --force-reinstall lain-admin-cli==v2.1.2
18 | when: bootstrapping is defined and bootstrapping|bool
19 |
--------------------------------------------------------------------------------
/playbooks/roles/prepare/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 |
--------------------------------------------------------------------------------
/playbooks/roles/prepare/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: ensure epel exists
2 | yum: pkg=epel-release
3 | when: ansible_distribution == "CentOS"
4 |
5 | - name: create data dir
6 | file: path={{ lain_data_dir }} state=directory
7 |
8 | - yum: pkg=libselinux-python
9 | when: ansible_distribution == "CentOS"
10 |
11 | - name: enable selinux
12 | selinux: policy=targeted state=permissive
13 | when: ansible_distribution == "CentOS"
14 |
15 | - name: get stat of nscd.service
16 | stat: path=/etc/systemd/system/nscd.service
17 | register: nscd
18 | ignore_errors: yes
19 |
20 | - name: disable nscd
21 | service: name=nscd enabled=no state=stopped
22 | when: nscd.stat.exists
23 |
24 | - name: load node info from etcd
25 | command: etcdctl get /lain/nodes/nodes/{{ node_name }}:{{ node_ip }}:{{ ssh_port }}
26 | register: result
27 | ignore_errors: yes
28 |
29 | - name: config default domains
30 | command: etcdctl set /lain/config/domains/{{ item }} '{"ips":[],"type":"node"}'
31 | with_items:
32 | - etcd.lain
33 | - consul.lain
34 | - docker.lain
35 | - lainlet.lain
36 | - metric.lain
37 |
38 | - name: config *.lain.local resolved to webrouter vips
39 | command: etcdctl set /lain/config/domains/*.lain.local '{"ips":[],"type":"webrouter"}'
40 |
41 | - name: delete any interface calico created previously
42 | command: for interface in $(ip link show | grep cali | awk '{print $2}' | awk -F':' '{print $1}'); do ip link delete ${interface}; done
43 | ignore_errors: yes
44 |
45 | - set_fact:
46 | node_info: "{{result.stdout|from_json}}"
47 | when: result|success and result.stdout != ""
48 | ignore_errors: yes
49 |
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade-2.0.x-to-v2.3.0/files/clean_logs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import requests
4 | import json
5 |
6 | def clean_content(file_path):
7 | print "Cleaning %s..." % file_path
8 | open(file_path, 'w').close()
9 |
10 | def clean_webrouter():
11 | webrouter_dir1 = '/data/lain/volumes/webrouter/webrouter.worker.worker/1/var/log/nginx'
12 | webrouter_dir2 = '/data/lain/volumes/webrouter/webrouter.worker.worker/2/var/log/nginx'
13 | for root, dirs, files in os.walk(webrouter_dir1, True):
14 | for name in files:
15 | clean_content(os.path.join(root, name))
16 | for root, dirs, files in os.walk(webrouter_dir2, True):
17 | for name in files:
18 | clean_content(os.path.join(root, name))
19 |
20 | def clean_syslog():
21 | clean_content("/var/log/messages")
22 |
23 | def clean_applog():
24 | resp = requests.get('http://lainlet.lain:9001/v2/rebellion/localprocs')
25 | respData = resp.json()
26 | for proc_name, proc_info in respData.iteritems():
27 | parts = proc_name.split(".")
28 | if len(parts) < 3:
29 | continue
30 | app_name = parts[0]
31 | if len(proc_info["PodInfos"]) > 0:
32 | container_info = proc_info["PodInfos"][0]
33 | annotations = json.loads(container_info["Annotation"])
34 | if "logs" in annotations:
35 | for log_file in annotations["logs"]:
36 | clean_content(os.path.join("/data/lain/volumes", app_name, proc_name, str(container_info["InstanceNo"]), "lain/logs", log_file))
37 |
38 | if __name__ == "__main__":
39 | clean_webrouter()
40 | clean_syslog()
41 | clean_applog()
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade-2.0.x-to-v2.3.0/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for rebellion
2 | command: systemctl daemon-reload
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade-2.0.x-to-v2.3.0/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 |
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade-2.0.x-to-v2.3.0/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | # !Caution: this task only applies for rebellion 2.0.x -> v2.3.0
2 | - name: pull new rebellion image
3 | command: docker pull registry.lain.local/rebellion:v2.3.0
4 |
5 | - name: tag new rebellion image
6 | command: docker tag registry.lain.local/rebellion:v2.3.0 rebellion:v2.3.0
7 |
8 | - name: prepare clean log script
9 | copy: src=clean_logs.py dest=/tmp/clean_logs.py mode="u+x"
10 |
11 | - name: update rebellion.service configuration
12 | template: src=rebellion.service.j2 dest=/etc/systemd/system/rebellion.service
13 | notify:
14 | - reload systemd for rebellion
15 | - meta: flush_handlers
16 |
17 | - name: clean log files
18 | command: python /tmp/clean_logs.py
19 |
20 | - name: restart rebellion
21 | service: name=rebellion enabled=yes state=restarted
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade-2.0.x-to-v2.3.0/templates/rebellion.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=rebellion
3 | Requires=docker.service
4 | After=docker.service
5 |
6 | [Service]
7 | ExecStart=/usr/bin/docker run \
8 | --name %n --rm --network=host \
9 | -e LAINLET_PORT={{ lainlet_port }} \
10 | -v {{ lain_data_dir }}/volumes/:/data/lain/volumes/:ro \
11 | -v {{ lain_data_dir }}/rebellion/var/lib/filebeat/:/var/lib/filebeat \
12 | -v {{ lain_data_dir }}/rebellion/logs/filebeat:/var/log/filebeat/ \
13 | -v {{ lain_data_dir }}/rebellion/logs/supervisor:/var/log/supervisor/ \
14 | -v /var/log/:/var/log/syslog/:ro \
15 | rebellion:v2.3.0
16 | ExecStop=/usr/bin/docker stop %n
17 | Restart=always
18 |
19 | [Install]
20 | WantedBy=multi-user.target
21 |
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for rebellion
2 | command: systemctl daemon-reload
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 |
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | # !Caution: this task only applies for rebellion v2.3.0 -> higher
2 | - name: pull new rebellion image
3 | command: docker pull registry.lain.local/rebellion:{{ upgrade_version }}
4 |
5 | - name: tag new rebellion image
6 | command: docker tag registry.lain.local/rebellion:{{ upgrade_version }} rebellion:{{ upgrade_version }}
7 |
8 | - name: update rebellion.service configuration
9 | template: src=rebellion.service.j2 dest=/etc/systemd/system/rebellion.service
10 | notify:
11 | - reload systemd for rebellion
12 | - meta: flush_handlers
13 |
14 | - name: restart rebellion
15 | service: name=rebellion enabled=yes state=restarted
--------------------------------------------------------------------------------
/playbooks/roles/rebellion-upgrade/templates/rebellion.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=rebellion
3 | Requires=docker.service
4 | After=docker.service
5 |
6 | [Service]
7 | ExecStart=/usr/bin/docker run \
8 | --name %n --rm --network=host \
9 | -e LAINLET_PORT={{ lainlet_port }} \
10 | -v {{ lain_data_dir }}/volumes/:/data/lain/volumes/:ro \
11 | -v {{ lain_data_dir }}/rebellion/var/lib/filebeat/:/var/lib/filebeat \
12 | -v {{ lain_data_dir }}/rebellion/logs/filebeat:/var/log/filebeat/ \
13 | -v {{ lain_data_dir }}/rebellion/logs/supervisor:/var/log/supervisor/ \
14 | -v /var/log/:/var/log/syslog/:ro \
15 | rebellion:{{ upgrade_version }}
16 | ExecStop=/usr/bin/docker stop %n
17 | Restart=always
18 |
19 | [Install]
20 | WantedBy=multi-user.target
21 |
--------------------------------------------------------------------------------
/playbooks/roles/rebellion/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for rebellion
2 | command: systemctl daemon-reload
3 |
4 | - name: restart rebellion
5 | service: name=rebellion state=restarted
6 |
7 | - name: restart rsyslog
8 | service: name=rsyslog state=restarted
--------------------------------------------------------------------------------
/playbooks/roles/rebellion/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: images
4 | images:
5 | - rebellion
6 |
--------------------------------------------------------------------------------
/playbooks/roles/rebellion/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: install rsyslog
2 | package: name=rsyslog state=present
3 |
4 | - name: config rebellion
5 | template: src=rebellion.service.j2 dest=/etc/systemd/system/rebellion.service
6 | notify:
7 | - reload systemd for rebellion
8 | - restart rebellion
9 | - meta: flush_handlers
10 |
11 | - name: ensure rebellion started
12 | service: name=rebellion enabled=yes state=started
13 |
14 | - name: checking rebellion working correctly
15 | shell: "docker ps | grep rebellion.service"
16 | register: result
17 | until: result|success
18 | retries: 50
19 | delay: 5
20 | changed_when: False
21 |
22 | - name: deploy rsyslog config
23 | template: src=10-docker-rsyslog.conf.j2 dest=/etc/rsyslog.d/10-docker-rsyslog.conf
24 | notify:
25 | - restart rsyslog
26 |
--------------------------------------------------------------------------------
/playbooks/roles/rebellion/templates/10-docker-rsyslog.conf.j2:
--------------------------------------------------------------------------------
1 | :programname, startswith, "docker" {
2 | $template tpllogd,"<%pri%> %timestamp:::date-rfc3339% %HOSTNAME% %syslogtag% %msg%\n"
3 |
4 | # ### begin forwarding rule ###
5 | # The statement between the begin ... end define a SINGLE forwarding
6 | # rule. They belong together, do NOT split them. If you create multiple
7 | # forwarding rules, duplicate the whole block!
8 | # Remote Logging (we use TCP for reliable delivery)
9 | #
10 | # An on-disk queue is created for this action. If the remote host is
11 | # down, messages are spooled to disk and sent when it is up again.
12 | $ActionQueueFileName fwdRule1 # unique name prefix for spool files
13 | $ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible)
14 | $ActionQueueSaveOnShutdown on # save messages to disk on shutdown
15 | $ActionQueueType LinkedList # run asynchronously
16 | $ActionResumeRetryCount -1 # infinite retries if host is down
17 | *.* @@{{ node_ip }}:{{ rebellion_rsyslog_tcp_port }};tpllogd
18 | # ### end of the forwarding rule ###
19 | }
--------------------------------------------------------------------------------
/playbooks/roles/rebellion/templates/rebellion.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=rebellion
3 | Requires=docker.service
4 | After=docker.service
5 |
6 | [Service]
7 | ExecStartPre=-/usr/bin/docker stop %n
8 | ExecStartPre=-/usr/bin/docker rm %n
9 | ExecStart=/usr/bin/docker run \
10 | --name %n --restart=always --network=host \
11 | -e LAINLET_PORT={{ lainlet_port }} \
12 | -v {{ lain_data_dir }}/volumes/:/data/lain/volumes/:ro \
13 | -v {{ lain_data_dir }}/rebellion/var/lib/filebeat/:/var/lib/filebeat \
14 | -v {{ lain_data_dir }}/rebellion/logs/filebeat:/var/log/filebeat/ \
15 | -v {{ lain_data_dir }}/rebellion/logs/supervisor:/var/log/supervisor/ \
16 | -v /var/log/:/var/log/syslog/:ro \
17 | {{ rebellion_image }}
18 | ExecStop=/bin/bash -c '/usr/bin/docker stop %n || true'
19 |
20 | [Install]
21 | WantedBy=multi-user.target
22 |
--------------------------------------------------------------------------------
/playbooks/roles/registry-moosefs/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: registry
4 | action: "none"
5 |
--------------------------------------------------------------------------------
/playbooks/roles/registry-moosefs/tasks/main.yaml:
--------------------------------------------------------------------------------
1 |
2 | # system_volumes.registry is like "/var/lib/registry:/var/lib/registry"
3 | - set_fact:
4 | registry_datadir: "{{ system_volumes.registry.split(':')[0] }}"
5 |
6 |
7 | - include: build.yaml
8 | when: is_lain_manager
9 |
10 | - name: create registry's data-dir
11 | file: path="{{ registry_datadir }}" state=directory
12 | when: not is_lain_manager
13 |
14 | - name: generate systemd.mount for /var/lib/registry
15 | template: src=var-lib-registry.mount.j2 dest=/etc/systemd/system/var-lib-registry.mount
16 | notify:
17 | - reload systemd for registry
18 | - mount registry directory
19 | when: not is_lain_manager
20 |
21 | - meta: flush_handlers
22 | when: not is_lain_manager
23 |
24 | - name: ensure registry data dir mounted onto moosefs and enable this service
25 | service: name=var-lib-registry.mount state=started enabled=yes
26 | when: not is_lain_manager
27 |
--------------------------------------------------------------------------------
/playbooks/roles/registry-moosefs/templates/var-lib-registry.mount.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=bind registry data dir onto moosefs
3 | After=network.target remote-fs.target mfs.mount
4 |
5 | [Mount]
6 | What={{ registry_mfsdir }}
7 | Where={{ registry_datadir }}
8 | Type=none
9 | Options=bind
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/playbooks/roles/registry/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for registry
2 | command: systemctl daemon-reload
3 |
4 | - name: mount registry directory
5 | service: name=var-lib-registry.mount state=restarted
6 |
--------------------------------------------------------------------------------
/playbooks/roles/registry/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: libraries
4 |
5 |
--------------------------------------------------------------------------------
/playbooks/roles/registry/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - include: push.yml
2 | when: action == 'push'
3 |
4 | # system_volumes.registry is like "/var/lib/registry:/var/lib/registry"
5 | - set_fact:
6 | registry_datadir: "{{ system_volumes.registry.split(':')[0] }}"
7 | when: action == 'usemfs'
8 |
9 | - name: create registry's data-dir
10 | file: path="{{ registry_datadir }}" state=directory
11 | when: action == 'usemfs'
12 |
13 | - name: generate systemd.mount for /var/lib/registry
14 | template: src=var-lib-registry.mount.j2 dest=/etc/systemd/system/var-lib-registry.mount
15 | notify:
16 | - reload systemd for registry
17 | - mount registry directory
18 | when: action == 'usemfs'
19 |
20 | - meta: flush_handlers
21 | when: action == 'usemfs'
22 |
23 | - name: ensure registry data dir mounted onto moosefs and enable this service
24 | service: name=var-lib-registry.mount state=started enabled=yes
25 | when: action == 'usemfs'
26 |
--------------------------------------------------------------------------------
/playbooks/roles/registry/tasks/push.yml:
--------------------------------------------------------------------------------
1 | - name: restart calico-felix
2 | service: name=calico-felix state=restarted
3 | ignore_errors: yes
4 |
5 | - name: wait_for registry ready
6 | command: curl -m 2 http://registry.lain.local/v2/
7 | register: result
8 | until: "result.stdout.startswith('{')"
9 | retries: 50
10 | delay: 5
11 | changed_when: False
12 |
13 | - name: push image to registry (may take minutes)
14 | docker_push:
15 | image: "{{ bootstrap_images[item] }}"
16 | registry: registry.lain.local
17 | with_items: "{{images_to_push|default([])}}"
18 |
19 | # vim: set filetype=ansible.yaml:
20 |
--------------------------------------------------------------------------------
/playbooks/roles/registry/templates/registry.j2:
--------------------------------------------------------------------------------
1 | {
2 | "image": "{{ registry_image }}",
3 | "expose": 5000,
4 | "num_instances": 1,
5 | "memory": "128m",
6 | "env":
7 | [
8 | "LAIN_APPNAME=registry",
9 | "LAIN_PROCNAME=web",
10 | "CALICO_IP=auto",
11 | "CALICO_PROFILE=default",
12 | "GUNICORN_OPTS=[--preload]"
13 | ],
14 | "annotation": "{\"mountpoint\": [\"registry.{{ domain }}\"]}"
15 | }
16 |
--------------------------------------------------------------------------------
/playbooks/roles/registry/templates/var-lib-registry.mount.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=bind registry data dir onto moosefs
3 | After=network.target remote-fs.target mfs.mount
4 |
5 | [Mount]
6 | What={{ registry_mfsdir }}
7 | Where={{ registry_datadir }}
8 | Type=none
9 | Options=bind
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/playbooks/roles/remove-node/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: os-dependent-vars
3 |
--------------------------------------------------------------------------------
/playbooks/roles/remove-node/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: check if having lain container running on this node
2 | shell: docker ps | grep -v .portal.portal | grep "registry.{{ domain }}" | wc -l
3 | register: result
4 |
5 | - fail: msg="still having lain container running on this node, check if by `docker ps`"
6 | when: result.stdout != '0'
7 |
8 | - name: stop networkd
9 | service: name=networkd state=stopped
10 |
11 | - name: stop the swarm agent
12 | service: name=swarm-agent state=stopped
13 |
14 | - name: stop the swarm manager
15 | service: name=swarm-manager state=stopped
16 |
17 | - name: stop lainlet
18 | service: name=lainlet state=stopped
19 |
20 | - name: stop rebellion
21 | service: name=rebellion state=stopped
22 |
23 | - name: get /lain/config/backup_enabled
24 | command: etcdctl get /lain/config/backup_enabled
25 | register: result
26 | ignore_errors: yes
27 |
28 | - name: stop backupd
29 | service: name=backupd state=stopped
30 | when: result|success and result.stdout == 'True'
31 |
32 | - name: umount /var/lib/registry
33 | command: umount /var/lib/registry
34 | ignore_errors: yes
35 |
36 | - name: umount /mfs
37 | command: umount /mfs
38 | ignore_errors: yes
39 |
40 | - name: stop rsyncd
41 | service: name="{{rsync_service_name}}" state=stopped
42 |
43 | - name: stop calico
44 | service: name={{item}} state=stopped
45 | with_items:
46 | - "calico-bird"
47 | - "calico-bird6"
48 | - "calico-confd"
49 | - "calico-felix"
50 | - "calico-libnetwork"
51 |
52 | - name: stop etcd
53 | service: name=etcd state=stopped
54 |
55 | - name: stop consul
56 | service: name=consul state=stopped
57 |
--------------------------------------------------------------------------------
/playbooks/roles/rsync/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: os-dependent-vars
3 | - role: config
4 |
--------------------------------------------------------------------------------
/playbooks/roles/rsync/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: install rsync
2 | package: name=rsync state=present
3 |
4 | - name: get network segment
5 | command: etcdctl get /lain/config/node_network
6 | register: network_result
7 |
8 | - set_fact:
9 | network: "{{network_result.stdout}}"
10 |
11 | - name: generate secret for rsyncd
12 | shell: etcdctl set /lain/config/rsyncd_secrets "$(uuidgen)"
13 | register: new_secrets_result
14 | when: bootstrapping is defined and bootstrapping|bool
15 |
16 | - name: get rsync secret from etcd
17 | command: etcdctl get /lain/config/rsyncd_secrets
18 | register: secrets_result
19 |
20 | - set_fact:
21 | rsyncd_secrets: "{{secrets_result.stdout}}"
22 |
23 | - fail: msg="secrets value needed, you can get it in /etc/rsyncd.secrets on manager-node"
24 | when: rsyncd_secrets == ""
25 |
26 | - name: set set secrets into etcd
27 | command: etcdctl set /lain/config/rsyncd_secrets "{{ rsyncd_secrets }}"
28 | when: bootstrapping|bool
29 |
30 | - name: write secrets
31 | template: src=rsyncd.secrets.j2 dest={{ rsync_secrets_file }}
32 | register: secrets_result
33 |
34 | - name: chmod secrets file
35 | file: path={{ rsync_secrets_file }} state=file mode=0400 group=root owner=root
36 |
37 | - name: generate rsyncd configuration
38 | template: src=rsyncd.conf.j2 dest="{{rsync_conf_path}}"
39 | register: config_result
40 |
41 | - name: generate service configration
42 | template: src=rsyncd.service.j2 dest={{ rsync_service_path }}
43 | register: service_result
44 |
45 | - name: reload systemd for rsync
46 | command: systemctl daemon-reload
47 |
48 | - name: restart the "{{ rsync_service_name }}"
49 | service: name="{{ rsync_service_name }}" enabled=yes state=restarted
50 | when: secrets_result|changed or config_result|changed or service_result|changed
51 |
52 | - name: ensure "{{ rsync_service_name }}" started
53 | service: name="{{ rsync_service_name }}" enabled=yes state=started
54 |
--------------------------------------------------------------------------------
/playbooks/roles/rsync/templates/rsyncd.conf.j2:
--------------------------------------------------------------------------------
1 | use chroot = yes
2 | max connections = 4
3 | timeout = 900
4 | transfer logging = yes
5 | dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2
6 |
7 | [lain_volume]
8 | uid = root
9 | gid = root
10 | path = /data/lain/volumes
11 | comment = the volume host directory for lain
12 | read only = true
13 | hosts allow = {{ rsync_network }}
14 | auth users = {{ rsync_auth_user }}
15 | secrets file = {{ rsync_secrets_file }}
16 |
--------------------------------------------------------------------------------
/playbooks/roles/rsync/templates/rsyncd.secrets.j2:
--------------------------------------------------------------------------------
1 | {{ rsync_auth_user }}:{{ rsyncd_secrets }}
2 |
--------------------------------------------------------------------------------
/playbooks/roles/rsync/templates/rsyncd.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=fast remote file copy program daemon
3 | ConditionPathExists=/etc/rsyncd.conf
4 |
5 | [Service]
6 | ExecStart=/usr/bin/rsync --daemon --no-detach --config={{rsync_conf_path}}
7 |
8 | [Install]
9 | WantedBy=multi-user.target
10 |
--------------------------------------------------------------------------------
/playbooks/roles/rsyslog-relocate/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: restart rsyslog
2 | service: name=rsyslog state=restarted
--------------------------------------------------------------------------------
/playbooks/roles/rsyslog-relocate/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: relocate syslog messages
2 | template: src=syslog-messages.conf.j2 dest=/etc/rsyslog.d/syslog-messages.conf
3 | notify:
4 | - restart rsyslog
5 |
6 | - name: remove default logrotate settting in syslog if exists
7 | replace: dest=/etc/logrotate.d/syslog regexp='/var/log/messages'
8 |
9 | - name: reset syslog-messages logrotate config
10 | template: src=syslog-messages.j2 dest=/etc/logrotate.d/syslog-messages
--------------------------------------------------------------------------------
/playbooks/roles/rsyslog-relocate/templates/syslog-messages.conf.j2:
--------------------------------------------------------------------------------
1 | *.info;mail.none;authpriv.none;cron.none {{ syslog_messages_location|default('/var/log/messages') }}
2 | & stop
--------------------------------------------------------------------------------
/playbooks/roles/rsyslog-relocate/templates/syslog-messages.j2:
--------------------------------------------------------------------------------
1 | {{ syslog_messages_location|default('/var/log/messages') }}
2 | {
3 | rotate 7
4 | daily
5 |
6 | compress
7 |
8 | postrotate
9 | /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
10 | endscript
11 | }
--------------------------------------------------------------------------------
/playbooks/roles/rsyslog/files/rsyslog.conf:
--------------------------------------------------------------------------------
1 | # rsyslog configuration file
2 |
3 | #### MODULES ####
4 |
5 | #$ModLoad imudp
6 | #$UDPServerRun 514
7 | $ModLoad imtcp
8 | $InputTCPServerRun 514
9 |
10 |
11 | #### GLOBAL DIRECTIVES ####
12 |
13 | $WorkDirectory /var/lib/rsyslog
14 | $ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
15 | $IncludeConfig /etc/rsyslog.d/*.conf
16 |
17 |
18 | #### RULES ####
19 |
20 | *.info;mail.none;authpriv.none;cron.none /var/log/messages
21 |
--------------------------------------------------------------------------------
/playbooks/roles/rsyslog/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: restart rsyslog
2 | service: name=rsyslog state=restarted
3 |
--------------------------------------------------------------------------------
/playbooks/roles/rsyslog/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: install rsyslog
2 | package: name=rsyslog state=present
3 |
4 | - name: copy rsyslog.conf
5 | copy: src=rsyslog.conf dest=/etc/rsyslog.conf backup=yes
6 | notify:
7 | - restart rsyslog
8 |
9 | - meta: flush_handlers
10 |
--------------------------------------------------------------------------------
/playbooks/roles/ssl/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: manager
3 |
--------------------------------------------------------------------------------
/playbooks/roles/ssl/tasks/ca.yaml:
--------------------------------------------------------------------------------
1 | # ref doc: https://help.github.com/enterprise/11.10.340/admin/articles/using-self-signed-ssl-certificates/
2 |
3 | - file: path={{ manager_home }}/.certs state=directory mode=0700
4 |
5 | - name: generate the root CA key
6 | command: openssl genrsa -out {{ manager_home }}/.certs/rootCA.key 2048
7 | args:
8 | creates: "{{ manager_home }}/.certs/rootCA.key"
9 |
10 | - name: generate the self-signed root CA certificate
11 | # TODO notify sysadmin when the cert is near expiring
12 | command: openssl req -x509 -new -nodes -key {{ manager_home }}/.certs/rootCA.key -days 365 -out {{ manager_home }}/.certs/rootCA.crt -subj "/C=ZZ/O=Lain/CN={{ domain }}"
13 | args:
14 | creates: "{{ manager_home }}/.certs/rootCA.crt"
15 |
16 | - name: generate the wildcard SSL key for web
17 | command: openssl genrsa -out {{ manager_home }}/.certs/web.key 2048
18 | args:
19 | creates: "{{ manager_home }}/.certs/web.key"
20 |
21 | - name: generate the certificate signing request for web SSL key
22 | command: openssl req -new -key {{ manager_home }}/.certs/web.key -out {{ manager_home }}/.certs/web.csr -subj "/C=ZZ/O=Lain/CN=*.{{ domain }}"
23 | args:
24 | creates: "{{ manager_home }}/.certs/web.csr"
25 |
26 | - name: generate the signed certificate for web SSL
27 | # TODO notify sysadmin when the cert is near expiring
28 | command: >
29 | openssl x509 -req -in {{ manager_home }}/.certs/web.csr
30 | -CA {{ manager_home }}/.certs/rootCA.crt
31 | -CAkey {{ manager_home }}/.certs/rootCA.key
32 | -CAcreateserial -out {{ manager_home }}/.certs/web.crt
33 | -days 365
34 | args:
35 | creates: "{{ manager_home }}/.certs/web.crt"
36 |
37 | - file: path="{{ manager_home }}/.certs/{{ item }}" mode=0600
38 | with_items:
39 | - rootCA.key
40 | - rootCA.crt
41 | - web.key
42 | - web.csr
43 | - web.crt
44 |
--------------------------------------------------------------------------------
/playbooks/roles/ssl/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - include: ca.yaml
2 | when: is_lain_manager
3 |
4 | - name: copy self-signed CA root(CentOS)
5 | copy: src="{{ manager_home }}/.certs/rootCA.crt" dest=/etc/pki/ca-trust/source/anchors/
6 | when: ansible_distribution=="CentOS"
7 |
8 | - name: copy self-signed CA root(Ubuntu)
9 | copy: src="{{ manager_home }}/.certs/rootCA.crt" dest=/usr/local/share/ca-certificates/
10 | when: ansible_distribution=="Ubuntu"
11 |
12 | - name: trust self-sigend CA root(CentOS)
13 | command: update-ca-trust extract
14 | when: ansible_distribution=="CentOS"
15 |
16 | - name: trust self-sigend CA root(Ubuntu)
17 | command: update-ca-certificates
18 | when: ansible_distribution=="Ubuntu"
19 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-manage/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for swarm-manage
2 | command: systemctl daemon-reload
3 |
4 | - name: restart swarm agent
5 | service: name=swarm-agent state=restarted
6 |
7 | - name: restart swarm manager
8 | service: name=swarm-manager state=restarted
9 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-manage/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
3 | - role: docker
4 | - role: etcd
5 | - role: binary
6 | - role: images
7 | images:
8 | - swarm
9 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-manage/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: config swarm agent
2 | template: src=swarm-agent.service.j2 dest=/etc/systemd/system/swarm-agent.service
3 | notify:
4 | - reload systemd for swarm-manage
5 | - restart swarm agent
6 | - meta: flush_handlers
7 |
8 | - name: ensure swarm agent started
9 | service: name=swarm-agent enabled=yes state=started
10 |
11 | - name: checking swarm agent working correctly
12 | command: etcdctl ls {{ swarm_discovery_path }}/{{ node_ip }}:{{ docker_port }}
13 | register: result
14 | until: result|success
15 | retries: 50
16 | delay: 5
17 | changed_when: False
18 |
19 | # every node may becomming a swarm-manager later,
20 | # add it into service to make administration convenient
21 | - name: add swarm manager service
22 | template: src=swarm-manager.service.j2 dest=/etc/systemd/system/swarm-manager.service
23 | notify:
24 | - reload systemd for swarm-manage
25 | - meta: flush_handlers
26 |
27 | - name: stop swarm manager
28 | service: name=swarm-manager state=stopped
29 | when: not is_swarm_manager
30 |
31 | # make sure the swarm manager started
32 | - include: swarm-manager.yaml
33 | when: is_swarm_manager
34 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-manage/tasks/swarm-manager.yaml:
--------------------------------------------------------------------------------
1 | - name: config swarm manager
2 | template: src=swarm-manager.service.j2 dest=/etc/systemd/system/swarm-manager.service
3 | notify:
4 | - reload systemd for swarm-manage
5 | - restart swarm manager
6 | - meta: flush_handlers
7 |
8 | - name: ensure swarm manager started
9 | service: name=swarm-manager enabled=yes state=started
10 |
11 | - name: waiting for swarm manager to collect information from cluster nodes
12 | shell: "docker -H tcp://{{ node_ip }}:{{ swarm_manager_port }} info | grep 'Nodes: ' | awk '{ print $2 }'"
13 | register: swarm_cluster_nodes
14 | until: swarm_cluster_nodes.stdout|int > 0
15 | retries: 50
16 | delay: 5
17 | changed_when: False
18 |
19 | - name: set the swarm manager ip into etcd
20 | command: etcdctl set "{{ swarm_manager_ip_key }}" "{{ node_ip }}"
21 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-manage/templates/swarm-agent.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=docker swarm agent
3 | After=docker.service
4 |
5 | [Service]
6 | ExecStartPre=-/usr/bin/docker stop %n
7 | ExecStartPre=-/usr/bin/docker rm %n
8 | ExecStart=/usr/bin/docker run \
9 | --name %n \
10 | --restart=always \
11 | {{ swarm_image }} join \
12 | --addr={{ node_ip }}:{{ docker_port }} \
13 | etcd://{{ node_ip }}:{{ etcd_client_port }}/lain/swarm
14 | ExecStop=/bin/bash -c '/usr/bin/docker stop %n || true'
15 |
16 | [Install]
17 | WantedBy=multi-user.target
18 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-manage/templates/swarm-manager.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=docker swarm manager
3 | After=docker.service
4 |
5 | [Service]
6 | ExecStartPre=-/usr/bin/docker stop %n
7 | ExecStartPre=-/usr/bin/docker rm %n
8 | ExecStart=/usr/bin/docker run \
9 | --name %n \
10 | --restart=always \
11 | -p {{ swarm_manager_port }}:{{ docker_port }} \
12 | {{ swarm_image }} manage \
13 | --replication \
14 | --addr={{ node_ip }}:{{ swarm_manager_port }} \
15 | etcd://{{ node_ip }}:{{ etcd_client_port }}/lain/swarm
16 | ExecStop=/bin/bash -c '/usr/bin/docker stop %n || true'
17 |
18 | [Install]
19 | WantedBy=multi-user.target
20 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-upgrade/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemd for swarm-manage
2 | command: systemctl daemon-reload
3 |
4 | - name: restart swarm agent
5 | service: name=swarm-agent state=restarted
6 |
7 | - name: stop swarm manager
8 | service: name=swarm-manager state=stopped
9 |
10 | - name: restart swarm manager
11 | service: name=swarm-manager state=restarted
12 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-upgrade/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: config
--------------------------------------------------------------------------------
/playbooks/roles/swarm-upgrade/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: pull new swarm image
2 | command: docker pull registry.lain.local/swarm:{{ upgrade_version }}
3 |
4 | - name: tag new swarm image
5 | command: docker tag registry.lain.local/swarm:{{ upgrade_version }} swarm:{{ upgrade_version }}
6 |
7 | - name: stop deployd
8 | service: name=deployd enabled=yes state=stopped
9 | ignore_errors: yes
10 |
11 | - name: config swarm agent
12 | template: src=swarm-agent.service.j2 dest=/etc/systemd/system/swarm-agent.service
13 | notify:
14 | - reload systemd for swarm-manage
15 | - restart swarm agent
16 | - meta: flush_handlers
17 |
18 | - name: ensure swarm agent started
19 | service: name=swarm-agent enabled=yes state=started
20 |
21 | - name: checking swarm agent working correctly
22 | command: etcdctl ls {{ swarm_discovery_path }}/{{ node_ip }}:{{ docker_port }}
23 | register: result
24 | until: result|success
25 | retries: 50
26 | delay: 5
27 | changed_when: False
28 |
29 | # every node may becomming a swarm-manager later,
30 | # add it into service to make administration convenient
31 | - name: add swarm manager service
32 | template: src=swarm-manager.service.j2 dest=/etc/systemd/system/swarm-manager.service
33 | notify:
34 | - reload systemd for swarm-manage
35 | - stop swarm manager
36 | when: node_name not in manager_list
37 | - meta: flush_handlers
38 |
39 | - name: config swarm manager
40 | template: src=swarm-manager.service.j2 dest=/etc/systemd/system/swarm-manager.service
41 | notify:
42 | - restart swarm manager
43 | - reload systemd for swarm-manage
44 | when: node_name in manager_list
45 | - meta: flush_handlers
46 |
47 | - name: ensure swarm manager started
48 | service: name=swarm-manager enabled=yes state=started
49 | when: node_name in manager_list
50 |
51 | - name: waiting for swarm manager to collect information from cluster nodes
52 | shell: "docker -H swarm.lain:{{ swarm_manager_port }} info | grep 'Nodes: ' | awk '{ print $2 }'"
53 | register: swarm_cluster_nodes
54 | until: swarm_cluster_nodes.stdout|int == {{ groups['nodes'] | length }}
55 | retries: 50
56 | delay: 5
57 | changed_when: False
58 |
59 | - name: start deployd
60 | service: name=deployd enabled=yes state=started
61 | ignore_errors: yes
62 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-upgrade/templates/swarm-agent.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=docker swarm agent
3 | After=docker.service
4 |
5 | [Service]
6 | ExecStart=/usr/bin/docker run \
7 | --name %n \
8 | --rm \
9 | swarm:{{ upgrade_version }} join \
10 | --addr={{ node_ip }}:{{ docker_port }} \
11 | etcd://{{ node_ip }}:{{ etcd_client_port }}/lain/swarm
12 | ExecStop=/usr/bin/docker stop %n
13 | Restart=always
14 |
15 | [Install]
16 | WantedBy=multi-user.target
17 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm-upgrade/templates/swarm-manager.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=docker swarm manager
3 | After=docker.service
4 |
5 | [Service]
6 | ExecStart=/usr/bin/docker run \
7 | --name %n \
8 | --rm \
9 | -p {{ swarm_manager_port }}:{{ docker_port }} \
10 | swarm:{{ upgrade_version }} manage \
11 | --replication \
12 | --addr={{ node_ip }}:{{ swarm_manager_port }} \
13 | etcd://{{ node_ip }}:{{ etcd_client_port }}/lain/swarm
14 | ExecStop=/usr/bin/docker stop %n
15 | Restart=always
16 |
17 | [Install]
18 | WantedBy=multi-user.target
19 |
--------------------------------------------------------------------------------
/playbooks/roles/swarm/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: swarm-manage
3 |
--------------------------------------------------------------------------------
/playbooks/roles/systemd/files/journald.conf.d/lain.conf:
--------------------------------------------------------------------------------
1 | [Journal]
2 | # new ver systemd bug: https://github.com/systemd/systemd/pull/1662
3 | Compress=no
4 |
5 | # Explicitly use persistent storage
6 | Storage=persistent
7 |
8 | # Explicitly control log forwarding flow, since the default configuration of
9 | # systemd is prone to change
10 | ForwardToSyslog=no
11 | ForwardToKMsg=no
12 | ForwardToConsole=no
13 | #ForwardToWall=yes
14 |
--------------------------------------------------------------------------------
/playbooks/roles/systemd/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: tune journald config
2 | copy: src=journald.conf.d dest=/etc/systemd/
3 | register: result
4 |
5 | - name: reload systemd
6 | command: systemctl daemon-reload
7 | when: result|changed
8 |
9 | - name: restart journald
10 | service: name=systemd-journald state=restarted
11 | when: result|changed
12 |
--------------------------------------------------------------------------------
/playbooks/roles/webrouter-start/meta/main.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: firewall
3 | - role: webrouter
4 | - role: console-deploy
5 | app: webrouter
6 |
--------------------------------------------------------------------------------
/playbooks/roles/webrouter-start/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: set webrouter virtual ip config
2 | set_virtual_ip_key: ip="{{ vip }}" port="{{ item }}" container_app="webrouter" container_proc="worker"
3 | with_items:
4 | - 80
5 | - 443
6 | - 8080
7 | - 8443
8 |
9 | - meta: flush_handlers
10 |
--------------------------------------------------------------------------------
/playbooks/roles/webrouter/files/nginx/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80 default_server;
3 | server_name everythingelse;
4 |
5 | #charset koi8-r;
6 | access_log /var/log/nginx/default.access.log main;
7 |
8 | location / {
9 | return 404;
10 | }
11 |
12 | #error_page 404 /404.html;
13 |
14 | # redirect server error pages to the static page /50x.html
15 | #
16 | error_page 500 502 503 504 /50x.html;
17 | location = /50x.html {
18 | root /usr/share/nginx/html;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/playbooks/roles/webrouter/files/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | user nginx;
3 | worker_processes 4;
4 |
5 | error_log /var/log/nginx/error.log warn;
6 | pid /var/run/nginx.pid;
7 |
8 |
9 | events {
10 | worker_connections 10240;
11 | }
12 |
13 |
14 | http {
15 | include /etc/nginx/mime.types;
16 | default_type application/octet-stream;
17 | server_names_hash_bucket_size 512;
18 | real_ip_header "X-Forwarded-For";
19 | set_real_ip_from 10.0.0.0/8;
20 | set_real_ip_from 172.20.0.0/16;
21 | real_ip_recursive on;
22 |
23 | log_format main '$remote_addr@$remote_user@[$time_local]@$Host@"$request"@'
24 | '$status@$body_bytes_sent@"$http_referer"@'
25 | '$http_user_agent@$http_x_forwarded_for@'
26 | 'upstream_response_time@$upstream_response_time@request_time@$request_time';
27 |
28 | large_client_header_buffers 4 1024k;
29 | client_max_body_size 0;
30 | chunked_transfer_encoding on;
31 |
32 | access_log /var/log/nginx/access.log main;
33 |
34 | sendfile on;
35 | #tcp_nopush on;
36 |
37 | keepalive_timeout 65;
38 |
39 | #gzip on;
40 |
41 | include /etc/nginx/upstreams/*.upstreams;
42 | include /etc/nginx/conf.d/*.conf;
43 | include /etc/nginx/default.conf;
44 | }
45 |
--------------------------------------------------------------------------------
/playbooks/roles/webrouter/files/nginx/proxy.conf:
--------------------------------------------------------------------------------
1 | proxy_next_upstream error invalid_header http_502;
2 |
3 | proxy_redirect off;
4 | proxy_set_header Host $host;
5 | proxy_set_header X-Real-IP $remote_addr;
6 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
7 | proxy_set_header X-Original-URI $request_uri;
8 | proxy_set_header REQUEST_URI $request_uri;
9 |
10 | set $xproto $scheme;
11 | if ($http_x_forwarded_proto ~* "^http") {
12 | set $xproto $http_x_forwarded_proto;
13 | }
14 | proxy_set_header X-Forwarded-Proto $xproto;
15 |
16 | proxy_http_version 1.1;
17 | proxy_set_header Upgrade $http_upgrade;
18 | proxy_set_header Connection "upgrade";
19 |
20 | #client_max_body_size 10m;
21 | client_body_buffer_size 128k;
22 | proxy_connect_timeout 90;
23 | proxy_send_timeout 90;
24 | proxy_read_timeout 900;
25 | proxy_buffer_size 32k;
26 | proxy_buffers 4 32k;
27 | proxy_busy_buffers_size 64k;
28 | proxy_temp_file_write_size 64k;
29 |
--------------------------------------------------------------------------------
/playbooks/roles/webrouter/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | - name: prepare webrouter volume dirs
2 | file: path={{ lain_data_dir }}/volumes/webrouter/webrouter.worker.worker/1{{ item }} state=directory
3 | with_items:
4 | - /var/log/nginx
5 | - /var/log/watcher
6 | - /var/log/supervisor
7 | - /etc/nginx/ssl
8 | - /etc/nginx/conf.d
9 | - /etc/nginx/upstreams
10 | - /etc/nginx/locations
11 | - /etc/nginx/buffer
12 |
13 | - name: copy configs to webrouter volumes
14 | copy: src={{ item.src }} dest={{ lain_data_dir }}/volumes/webrouter/webrouter.worker.worker/1{{ item.dest }}
15 | with_items:
16 | - src: nginx/proxy.conf
17 | dest: /etc/nginx/proxy.conf
18 | - src: nginx/nginx.conf
19 | dest: /etc/nginx/nginx.conf
20 | - src: nginx/default.conf
21 | dest: /etc/nginx/default.conf
22 |
23 | - name: load ssl info from etcd
24 | command: etcdctl get /lain/config/ssl
25 | register: result
26 |
27 | - name: copy ssl crt to volumes
28 | copy: src={{ manager_home }}/.certs/{{ item.value }}.crt dest={{ lain_data_dir }}/volumes/webrouter/webrouter.worker.worker/1/etc/nginx/ssl/ owner=root
29 | with_dict: "{{result.stdout|from_json}}"
30 | when: result|success and result.stdout != ""
31 |
32 | - name: copy ssl key to volumes
33 | copy: src={{ manager_home }}/.certs/{{ item.value }}.key dest={{ lain_data_dir }}/volumes/webrouter/webrouter.worker.worker/1/etc/nginx/ssl/ owner=root
34 | with_dict: "{{result.stdout|from_json}}"
35 | when: result|success and result.stdout != ""
36 |
--------------------------------------------------------------------------------
/playbooks/site.yaml:
--------------------------------------------------------------------------------
1 | - hosts: "{{ target|default('nodes') }}"
2 | roles:
3 | - node
4 |
--------------------------------------------------------------------------------