├── inventory
├── localhost
└── gce.py
├── files
├── docker2
├── docker
└── docker.service
├── hosts
├── template
├── ip-detect
└── config.yaml
├── install.yml
├── group_vars
└── all
├── tasks
├── setup_bootstrap_node.yml
├── create_master_instances.yml
└── configure_master_dcos_nodes.yml
├── configure_dcos.yml
├── add_agents.yml
├── README.md
└── LICENSE
/inventory/localhost:
--------------------------------------------------------------------------------
1 | localhost
2 |
--------------------------------------------------------------------------------
/files/docker2:
--------------------------------------------------------------------------------
1 | other_args=--storage-driver=overlay
2 |
--------------------------------------------------------------------------------
/files/docker:
--------------------------------------------------------------------------------
1 | DOCKER_OPTS="other_args=--storage-driver=overlay"
2 |
--------------------------------------------------------------------------------
/hosts:
--------------------------------------------------------------------------------
1 | [masters]
2 | master0 ip=10.132.0.3
3 |
4 | [agents]
5 | agent[0000:9999]
6 |
7 | [bootstrap]
8 | bootstrap
9 |
--------------------------------------------------------------------------------
/template/ip-detect:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Example ip-detect script using an external authority
3 | # Uses the GCE metadata server to get the node's internal
4 | # ipv4 address
5 |
6 | curl -fsSL -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/network-interfaces/0/ip
7 |
--------------------------------------------------------------------------------
/template/config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | bootstrap_url: http://{{ bootstrap_public_ip }}:{{ bootstrap_public_port }}
3 | cluster_name: {{ cluster_name }}
4 | exhibitor_storage_backend: static
5 | ip_detect_filename: /genconf/ip-detect
6 | master_discovery: static
7 | master_list:
8 | {% for master in groups['masters'] %}
9 | - {{ hostvars[master]['ip'] }}
10 | {% endfor %}
11 | resolvers:
12 | - 8.8.4.4
13 | - 8.8.8.8
14 |
--------------------------------------------------------------------------------
/install.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Configure dcos installer on bootstrap node
3 | hosts: localhost
4 | become: yes
5 | become_user: root
6 | become_method: sudo
7 | gather_facts: no
8 | connection: local
9 | tasks:
10 | - include: tasks/setup_bootstrap_node.yml
11 |
12 | - name: Create and launch master instances
13 | hosts: localhost
14 | become: yes
15 | become_user: root
16 | become_method: sudo
17 | gather_facts: no
18 | connection: local
19 | tasks:
20 | - include: tasks/create_master_instances.yml
21 | - pause: seconds=20
22 |
23 | - name: initialise master dcos nodes
24 | hosts: masters
25 | become: yes
26 | become_user: root
27 | become_method: sudo
28 | serial: 2
29 | tasks:
30 | - include: tasks/configure_master_dcos_nodes.yml
31 |
32 |
--------------------------------------------------------------------------------
/files/docker.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Docker Application Container Engine
3 | Documentation=https://docs.docker.com
4 | After=network.target
5 |
6 | [Service]
7 | Type=notify
8 | # the default is not to use systemd for cgroups because the delegate issues still
9 | # exists and systemd currently does not support the cgroup feature set required
10 | # for containers run by docker
11 | ExecStart=/usr/bin/docker daemon --storage-driver=overlay
12 | ExecReload=/bin/kill -s HUP $MAINPID
13 | # Having non-zero Limit*s causes performance problems due to accounting overhead
14 | # in the kernel. We recommend using cgroups to do container-local accounting.
15 | LimitNOFILE=infinity
16 | LimitNPROC=infinity
17 | LimitCORE=infinity
18 | # Uncomment TasksMax if your systemd version supports it.
19 | # Only systemd 226 and above support this version.
20 | #TasksMax=infinity
21 | TimeoutStartSec=0
22 | # set delegate yes so that systemd does not reset the cgroups of docker containers
23 | Delegate=yes
24 | # kill only the docker process, not all processes in the cgroup
25 | KillMode=process
26 |
27 | [Install]
28 | WantedBy=multi-user.target
29 |
--------------------------------------------------------------------------------
/group_vars/all:
--------------------------------------------------------------------------------
1 | ---
2 | project: trek-trackr
3 |
4 | subnet: default-6f68d4d6fabcb680
5 |
6 | login_name: ajazam
7 |
8 | bootstrap_public_ip: 10.132.0.2
9 |
10 | zone: europe-west1-c
11 |
12 |
13 |
14 |
15 | master_boot_disk_size: 10
16 |
17 | master_machine_type: n1-standard-2
18 |
19 | master_boot_disk_type: pd-standard
20 |
21 |
22 | agent_boot_disk_size: 10
23 |
24 | agent_machine_type: n1-standard-2
25 |
26 | agent_boot_disk_type: pd-standard
27 |
28 | agent_instance_type: "MIGRATE"
29 |
30 | agent_type: private
31 |
32 | start_id: 0001
33 |
34 | end_id: 0001
35 |
36 |
37 |
38 |
39 | gcloudbin: /usr/bin/gcloud
40 |
41 | image: 'centos-7-v20161027'
42 |
43 | image_project: 'centos-cloud'
44 |
45 | bootstrap_public_port: 8080
46 |
47 | cluster_name: cluster_name
48 |
49 | scopes: "https://www.googleapis.com/auth/cloud-platform"
50 |
51 | dcos_installer_filename: dcos_generate_config.sh
52 |
53 | dcos_installer_download_path: "https://downloads.dcos.io/dcos/stable/{{ dcos_installer_filename }}"
54 |
55 | home_directory: "/home/{{ login_name }}"
56 |
57 | downloads_from_bootstrap: 2
58 |
59 | dcos_bootstrap_container: dcosinstaller
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/tasks/setup_bootstrap_node.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: create directory genconf
3 | file: dest="{{ home_directory }}/genconf" state=directory
4 |
5 | - name: copy config
6 | template: src=template/config.yaml dest="{{ home_directory }}/genconf"
7 |
8 | - name: copy ipdetect
9 | template: src=template/ip-detect dest="{{ home_directory }}/genconf" mode="u=rwx,g=rwx,o=rwx"
10 |
11 | - name: check presence of dcos installer
12 | stat: path="{{ home_directory }}/{{ dcos_installer_filename }}"
13 | register: dcos_installer_state
14 |
15 | - name: get dcos installer
16 | get_url: url={{ dcos_installer_download_path }} dest={{ home_directory }} mode="u=rwx,g=rwx,o=rwx"
17 | when: dcos_installer_state.stat.islnk is not defined
18 |
19 | - name: stop docker
20 | service: name=docker state=stopped
21 |
22 | - name: ensure docker is running
23 | service: name=docker state=started
24 |
25 | - name: Generate customised build file
26 | command: "{{ home_directory }}/{{ dcos_installer_filename }}"
27 | args:
28 | chdir: "{{ home_directory }}"
29 | # need a when statement here
30 |
31 | - name: start docker container
32 | docker_container:
33 | name: "{{ dcos_bootstrap_container }}"
34 | image: nginx
35 | state: started
36 | volumes: "{{ home_directory }}/genconf/serve:/usr/share/nginx/html:ro"
37 | ports: "{{ bootstrap_public_port }}:80"
38 |
--------------------------------------------------------------------------------
/tasks/create_master_instances.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | - name: remove masters from known_hosts file
4 | command: /usr/bin/ssh-keygen -R {{ hostvars[item].inventory_hostname }}
5 | with_items:
6 | - "{{ groups['masters'] }}"
7 | ignore_errors: true
8 |
9 | - name : remove masters IP from known_hosts file
10 | command: /usr/bin/ssh-keygen -R {{ hostvars[item]['ip'] }}
11 | with_items:
12 | - "{{ groups['masters'] }}"
13 | ignore_errors: true
14 |
15 | - name: Create and launch masters
16 | command: "{{ gcloudbin }} compute --project {{ project }} instances create {{ hostvars[item].inventory_hostname }}
17 | --zone {{ zone }} --machine-type {{ master_machine_type }} --subnet {{ subnet }}
18 | --private-network-ip {{ hostvars[item]['ip'] }} --maintenance-policy \"MIGRATE\" --tags \"master\"
19 | --scopes https://www.googleapis.com/auth/cloud-platform --image {{ image }} --image-project {{ image_project }}
20 | --boot-disk-size {{ master_boot_disk_size }} --boot-disk-type {{ master_boot_disk_type }}
21 | --boot-disk-device-name {{ hostvars[item].inventory_hostname }}-boot --metadata hostname={{ hostvars[item].inventory_hostname }}"
22 | with_items:
23 | - "{{ groups['masters'] }}"
24 | register: master_instances
25 | async: 7200
26 | poll: 0
27 |
28 | - name: wait for master instance creation to complete
29 | async_status: jid={{ item.ansible_job_id }}
30 | register: master_instance_jobs
31 | until : master_instance_jobs.finished
32 | retries: 300
33 | with_items: "{{ master_instances.results }}"
34 |
--------------------------------------------------------------------------------
/tasks/configure_master_dcos_nodes.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: create tmp directory
3 | file: dest=/tmp/dcos state=directory
4 |
5 | - name: install dependencies
6 | yum: name={{ item }} state=present
7 | with_items:
8 | - unzip
9 | - ipset
10 | - ntp
11 |
12 | - name: install ntpd
13 | service: name=ntpd state=started enabled=yes
14 |
15 | - name: add group nogroup
16 | group: name=nogroup state=present
17 |
18 | - name: disable selinux
19 | selinux: state=disabled
20 |
21 | - name: restart host
22 | shell: sleep 1;/usr/sbin/reboot
23 | async: 1
24 | poll: 0
25 | ignore_errors: true
26 |
27 | - name: waiting for host to come back online
28 | local_action: wait_for host={{ inventory_hostname }} search_regex=OpenSSH port=22 timeout=300 state=started
29 |
30 | - name: Add docker repository
31 | yum_repository:
32 | name: dockerrepo
33 | description: Docker Respository
34 | baseurl: https://yum.dockerproject.org/repo/main/centos/$releasever/
35 | state: present
36 | enabled: yes
37 | gpgcheck: yes
38 | gpgkey: https://yum.dockerproject.org/gpg
39 |
40 | - pause: seconds=1
41 |
42 | - name: install docker
43 | yum: name=docker-engine-1.11.2 state=present
44 |
45 | - name: copy docker config for overlayfs
46 | copy: src=files/docker.service dest=/usr/lib/systemd/system
47 |
48 | - name: reload sytemd
49 | command: /usr/bin/systemctl daemon-reload
50 |
51 | - name: start docker
52 | service: name=docker state=started
53 |
54 | # following needs to have serial: 2
55 | - name: fetch installer from bootstrap
56 | get_url: url=http://{{ bootstrap_public_ip }}:{{ bootstrap_public_port }}/dcos_install.sh dest=/tmp/dcos mode="u=rwx,g=rwx,o=rwx"
57 |
58 | # configure master nodes
59 |
60 | - name: install dcos on master
61 | command: bash dcos_install.sh master
62 | args:
63 | chdir: /tmp/dcos
64 |
--------------------------------------------------------------------------------
/configure_dcos.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: configure hosts
3 | hosts: tag_master,tag_privateagent,tag_publicagent
4 | become: yes
5 | gather_facts: no
6 | tasks:
7 | - name: create tmp directory
8 | file: dest=/tmp/dcos state=directory
9 |
10 | - name: install dependencies
11 | yum: name={{ item }} state=present
12 | with_items:
13 | - unzip
14 | - ipset
15 |
16 | - name: add group nogroup
17 | group: name=nogroup state=present
18 |
19 | - name: disable selinux
20 | selinux: state=disabled
21 |
22 | - name: restart host
23 | shell: sleep 1;/usr/sbin/reboot
24 | async: 1
25 | poll: 0
26 | ignore_errors: true
27 |
28 | - name: waiting for host to come back online
29 | local_action: wait_for host={{ inventory_hostname }} search_regex=OpenSSH port=22 timeout=300 state=started
30 |
31 | # - name: update yum packages
32 | # yum: update_cache=yes state=present
33 |
34 | - name: Add docker repository
35 | yum_repository:
36 | name: dockerrepo
37 | description: Docker Respository
38 | baseurl: https://yum.dockerproject.org/repo/main/centos/$releasever/
39 | state: present
40 | enabled: yes
41 | gpgcheck: yes
42 | gpgkey: https://yum.dockerproject.org/gpg
43 |
44 | - pause: seconds=1
45 |
46 | - name: install docker
47 | yum: name=docker-engine state=present
48 |
49 | - name: copy docker config for overlayfs
50 | copy: src=files/docker.service dest=/usr/lib/systemd/system
51 |
52 | - name: reload sytemd
53 | command: /usr/bin/systemctl daemon-reload
54 |
55 | - name: start docker
56 | service: name=docker state=started
57 |
58 |
59 |
60 | - name: fetch dcos installer
61 | hosts: tag_master,tag_privateagent,tag_publicagent
62 | become: yes
63 | gather_facts: no
64 | serial: 2
65 | tasks:
66 | - name: fetch installer from bootstrap
67 | get_url: url=http://{{ bootstrap_public_ip }}:{{ bootstrap_public_port }}/dcos_install.sh dest=/tmp/dcos mode="u=rwx,g=rwx,o=rwx"
68 |
69 | - name: configure master nodes with dcos
70 | hosts: tag_master
71 | become: yes
72 | gather_facts: no
73 | tasks:
74 | - name: install dcos on master
75 | command: bash dcos_install.sh master
76 | args:
77 | chdir: /tmp/dcos
78 |
79 | - name: configure private agent nodes with dcos
80 | hosts: tag_privateagent
81 | become: yes
82 | gather_facts: no
83 | tasks:
84 | - name: install dcos on private agents
85 | command: bash dcos_install.sh slave
86 | args:
87 | chdir: /tmp/dcos
88 |
89 | - name: configure public agent nodes with dcos
90 | hosts: tag_publicagent
91 | become: yes
92 | gather_facts: no
93 | tasks:
94 | - name: install dcos on public nodes
95 | command: bash dcos_install.sh slave_public
96 | args:
97 | chdir: /tmp/dcos
98 |
--------------------------------------------------------------------------------
/add_agents.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Create agent instances
3 | hosts: localhost
4 | become: yes
5 | become_user: root
6 | gather_facts: no
7 | connection: local
8 | tasks:
9 | - name: remove agents from known_hosts file
10 | command: /usr/bin/ssh-keygen -R {{ item }}
11 | with_sequence: start={{ start_id }} end={{ end_id }} format=agent%04x
12 | ignore_errors: true
13 |
14 | - name: launch agent instances
15 | command: "{{ gcloudbin }} compute --project {{ project }} instances create {{ item }} --zone {{ zone }} --machine-type {{ agent_machine_type }}
16 | --subnet {{ subnet }} --maintenance-policy {{ agent_instance_type }} --tags \"{{agent_type}}agent\" --scopes {{ scopes }}
17 | --image {{ image }} --image-project {{ image_project }} --boot-disk-size {{ agent_boot_disk_size }}
18 | --boot-disk-type {{ agent_boot_disk_type }} --boot-disk-device-name boot --metadata hostname={{ item }}"
19 | with_sequence: start={{ start_id }} end={{ end_id }} format=agent%04x
20 | register: vm_instances
21 | async: 7200
22 | poll: 0
23 |
24 | - name: wait for instance creation to complete
25 | async_status: jid={{ item.ansible_job_id }}
26 | register: instances_jobs
27 | until: instances_jobs.finished
28 | retries: 300
29 | with_items: "{{ vm_instances.results }}"
30 |
31 | - name: start dcos bootstrap container
32 | hosts: localhost
33 | gather_facts: no
34 | become: yes
35 | become_user: root
36 | connection: local
37 | tasks:
38 | - name: start docker
39 | service: name=docker state=started
40 |
41 | - name: ensure dcos installer container is started
42 | docker_container:
43 | name: "{{ dcos_bootstrap_container }}"
44 | state: started
45 |
46 | - pause: seconds=10
47 |
48 | - name: Install dcos on nodes
49 | hosts: agents[{{start_id}}:{{ end_id }}]
50 | become: yes
51 | become_user: root
52 | gather_facts: no
53 | tasks:
54 | - name: create tmp directory
55 | file: dest=/tmp/dcos state=directory
56 |
57 | - name: install dependencies
58 | yum: name="{{ item }}" state=present
59 | with_items:
60 | - unzip
61 | - ipset
62 | - ntp
63 |
64 | - name: install ntpd
65 | service: name=ntpd state=started enabled=yes
66 |
67 | - name: add group nogroup
68 | group: name=nogroup state=present
69 |
70 | - name: disable selinux
71 | selinux: state=disabled
72 |
73 | - name: restart host
74 | shell: sleep 1;/usr/sbin/reboot
75 | async: 1
76 | poll: 0
77 | ignore_errors: true
78 |
79 | - name: waiting for host to come back online
80 | local_action: wait_for host={{ inventory_hostname }} search_regex=OpenSSH port=22 timeout=300 state=started
81 |
82 | - name: Add docker repository
83 | yum_repository:
84 | name: dockerrepo
85 | description: Docker Respository
86 | baseurl: https://yum.dockerproject.org/repo/main/centos/$releasever/
87 | state: present
88 | enabled: yes
89 | gpgcheck: yes
90 | gpgkey: https://yum.dockerproject.org/gpg
91 |
92 | - pause: seconds=1
93 |
94 | - name: install docker
95 | yum: name=docker-engine-1.11.2 state=present
96 |
97 | - name: copy docker config for overlayfs
98 | copy: src=files/docker.service dest=/usr/lib/systemd/system
99 |
100 | - name: reload sytemd
101 | command: /usr/bin/systemctl daemon-reload
102 |
103 | - name: start docker
104 | service: name=docker state=started enabled=yes
105 |
106 | # following needs to have serial: 2
107 | - name: fetch installer from bootstrap
108 | get_url: url=http://{{ bootstrap_public_ip }}:{{ bootstrap_public_port }}/dcos_install.sh dest=/tmp/dcos mode="u=rwx,g=rwx,o=rwx"
109 |
110 | # configure master nodes
111 | - name: install dcos on private agent
112 | command: bash dcos_install.sh slave
113 | args:
114 | chdir: /tmp/dcos
115 | when: agent_type == 'private'
116 |
117 | - name: install dcos on public agent
118 | command: bash dcos_install.sh slave_public
119 | args:
120 | chdir: /tmp/dcos
121 | when: agent_type == 'public'
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DCOS on Google Compute Engine
2 |
3 | This repository contains scripts to configure a DC/OS cluster on Google Compute Engine.
4 |
5 | A bootstrap node is required to run the scripts and to bootstrap the DC/OS cluster.
6 |
7 | **PLEASE READ THE ENTIRE DOCUMENT. YOU MUST MAKE CHANGES FOR THE SCRIPTS TO WORK IN YOUR GCE ENVIRONMENT.**
8 |
9 | ## Bootstrap node configuration
10 |
11 | **YOU MUST CREATE A PROJECT** using the google cloud console. The author created a project called trek-treckr
12 |
13 | You can create the bootstrap node using the google cloud console. The author used a n1-standard-1 instance running centos 7 with a 10 GB persistent disk in
14 | zone europe-west1-c. The bootstrap node must have "Allow full access to all Cloud APIs" in the Identity and API access section. Also enable Block project-wide SSH keys in the SSH Keys section. Create the instance.
15 |
16 | After creating the boot instance run the following from the shell
17 | ```bash
18 | sudo yum update google-cloud-sdk
19 | sudo yum update
20 | sudo yum install epel-release
21 | sudo yum install python-pip
22 | sudo pip install -U pip
23 | sudo pip install 'apache-libcloud==1.2.1'
24 | sudo pip install 'docker-py==1.9.0'
25 | sudo yum install git-1.8.3.1 ansible-2.1.1.0
26 | ```
27 |
28 | You need to create the rsa public/private keypairs to allow passwordless logins via SSH to the nodes of the DC/OS cluster. This is required by ansible to create the cluster nodes and install DC/OS on the nodes.
29 |
30 | Run the following to generate the keys
31 | ```bash
32 | ssh-keygen -t rsa -f ~/.ssh/id_rsa -C ajazam
33 | ```
34 | **PLEASE REPLACE ajazam** with your username. Do not enter a password when prompted
35 |
36 | Make a backup copy of id_rsa.
37 |
38 | Open rsa pub key
39 | ```bash
40 | sudo vi ~/.ssh/id_rsa.pub
41 | ```
42 |
43 | shows
44 |
45 | ```bash
46 | ssh-rsa abcdefghijklmaasnsknsdjfsdfjs;dfj;sdflkjsd ajazam
47 | ```
48 | Prefix your username, followed by a colon, to the above line. Also replace ajazam at the end with your username.
49 |
50 | ```bash
51 | ajazam:ssh-rsa abcdefghijklmaasnsknsdjfsdfjs;dfj;sdflkjsd ajazam
52 | ```
53 | save contents of id_rsa.pub. **Please replace the ajazam with your username**.
54 |
55 |
56 |
57 | Add the rsa public key to your project
58 | ```bash
59 | chmod 400 ~/.ssh/id_rsa
60 | gcloud compute project-info add-metadata --metadata-from-file sshKeys=~/.ssh/id_rsa.pub
61 | ```
62 |
63 | Disable selinux for docker to work
64 |
65 | make the following change to /etc/selinux/config
66 |
67 | ```bash
68 | SELINUX=disabled
69 | ```
70 |
71 | reboot host
72 |
73 | To install docker add the yum repo
74 |
75 | ```bash
76 | sudo tee /etc/yum.repos.d/docker.repo <<-'EOF'
77 | [dockerrepo]
78 | name=Docker Repository
79 | baseurl=https://yum.dockerproject.org/repo/main/centos/7/
80 | enabled=1
81 | gpgcheck=1
82 | gpgkey=https://yum.dockerproject.org/gpg
83 | EOF
84 | ```
85 |
86 | install the docker package
87 | ```bash
88 | sudo yum install docker-engine-1.11.2
89 | ```
90 |
91 | Add following changes to /usr/lib/systemd/system/docker.service
92 |
93 | ```bash
94 | ExecStart=/usr/bin/docker daemon --storage-driver=overlay
95 | ```
96 |
97 | reload systemd
98 |
99 | ```bash
100 | sudo systemctl daemon-reload
101 | ```
102 |
103 | Start docker
104 | ```bash
105 | sudo systemctl start docker.service
106 | ```
107 |
108 | Verify if docker works
109 |
110 | ```bash
111 | sudo docker run hello-world
112 | ```
113 |
114 |
115 | download the dcos-gce scripts
116 | ```bash
117 | git clone https://github.com/dcos-labs/dcos-gce
118 | ```
119 |
120 | change directory
121 | ```bash
122 | cd dcos-gce
123 | ```
124 |
125 | Please make appropriate changes to group_vars/all. You need to review project, subnet, login_name, bootstrap_public_ip & zone
126 |
127 | insert following into ~/.ansible.cfg to stop host key checking
128 | ```bash
129 | [defaults]
130 | host_key_checking = False
131 |
132 | [paramiko_connection]
133 | record_host_keys = False
134 |
135 | [ssh_connection]
136 | ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null
137 | ```
138 |
139 | Ensure the IP address for master0 in ./hosts is the next consecutive IP from bootstrap_public_ip.
140 |
141 | To create and configure the master nodes run
142 | ```bash
143 | ansible-playbook -i hosts install.yml
144 | ```
145 | To create and configure the private nodes run
146 | ```bash
147 | ansible-playbook -i hosts add_agents.yml --extra-vars "start_id=0001 end_id=0002 agent_type=private"
148 | ```
149 | start_id=0001 and end_id=0002 specify the range of id's that are appended to the hostname "agent" to create unique agent names. If start_id is not specified then a default of 0001 is used.
150 | If the end_id is not specified then a default of 0001 is used.
151 |
152 | *When specifying start_id or end_id via CLI, the leading zeroes must be dropped for any agent id higher than 7* or ansible will throw a format error.
153 | ```bash
154 | ansible-playbook -i hosts add_agents.yml --extra-vars "start_id=0006 end_id=10 agent_type=private"
155 | ```
156 | The values for agent_type are either private or public. If an agent_type is not specified then it is assumed agent_type is private.
157 |
158 | To create public nodes type
159 | ```bash
160 | ansible-playbook -i hosts add_agents.yml --extra-vars "start_id=0003 end_id=0004 agent_type=public"
161 | ```
162 | ## Configurable parameters
163 |
164 | File './hosts' is an ansible inventory file. Text wrapped by [] represents a group name and individual entries after the group name represent hosts in that group.
165 | The [masters] group contains node names and IP addresses for the master nodes. In the supplied file the host name is master0 and the ip address 10.132.0.3 is assigned to
166 | master0. **YOU MUST CHANGE** the IP address for master0 for your network. You can create multiple entries e.g. master1, master2 etc. Each node must have a unique IP address.
167 |
168 | The [agents] group has one entry. It specifies the names of all the agents one can have in the DC/OS cluster. The value specifies that agent0000 to agent9999, a
169 | total of 10,000 agents are allowed. This really is an artificial limit because it can easily be changed.
170 |
171 | The [bootstrap] group has the name of the bootstrap node.
172 |
173 | File './group_vars/all' contains miscellaneous parameters that will change the behaviour of the installation scripts. The parameters are split into two groups. Group 1 parameters must be changed to reflect your environment. Group 2 parameters can optionally be changed to change the behaviour of the scripts.
174 |
175 | ### Group 1 parameters YOU MUST CHANGE for your environment
176 |
177 | ```text
178 | project
179 | ```
180 | Your project id. Default: trek-trackr
181 |
182 | ```text
183 | subnet
184 | ```
185 | Your network. Default: default
186 |
187 | ```text
188 | login_name
189 | ```
190 | The login name used for accessing each GCE instance. Default: ajazam
191 |
192 | ```text
193 | bootstrap_public_ip
194 | ```
195 | The bootstrap nodes public IP. Default: 10.132.0.2
196 |
197 | ```text
198 | zone
199 | ```
200 | You may change this to your preferred zone. Default: europe-west1-c
201 |
202 |
203 | ### Group 2 parameters which optionally change the behaviour of the installation scripts
204 |
205 | ```text
206 | master_boot_disk_size:
207 | ```
208 | The size of the master node boot disk. Default 10 GB
209 |
210 | ```text
211 | master_machine_type
212 | ```
213 | The GCE instance type used for the master nodes. Default: n1-standard-2
214 |
215 | ```text
216 | master_boot_disk_type
217 | ```
218 | The master boot disk type. Default: pd-standard
219 |
220 | ```text
221 | agent_boot_disk_size
222 | ```
223 | The size of the agent boot disk. Default 10 GB
224 |
225 | ```text
226 | agent_machine_type
227 | ```
228 | The GCE instance type used for the agent nodes. Default: n1-standard-2
229 |
230 | ```text
231 | agent_boot_disk_type
232 | ```
233 | The agent boot disk type. Default: pd-standard
234 |
235 | ```text
236 | agent_instance_type
237 | ```
238 | Allows agents to be preemptible. If the value is "MIGRATE" then they are not preemptible. If the value is '"TERMINATE" --preemptible' then the instance is preemptible. Default: "MIGRATE"
239 |
240 | ```text
241 | agent_type
242 | ```
243 | Can specify whether an agent is "public" or "private". Default: "private"
244 |
245 | ```text
246 | start_id
247 | ```
248 | The number appended to the text *agent* is used to define the hostname of the first agent. e.g. agent0001. Intermediate agents between start_id and end_id will be created if required. Default: 0001
249 |
250 | ```text
251 | end_id
252 | ```
253 | The number appended to the text *agent* is used to define the hostname of the last agent. e.g. agent0001. Intermediate agents between start_id and end_id will be created if required. Default: 0001
254 |
255 |
256 | ```text
257 | gcloudbin
258 | ```
259 | The location of the gcloudbin binary. Default: /usr/local/bin/gcloud
260 |
261 | ```text
262 | image
263 | ```
264 | The disk image used on the master and agent. Default: /centos-cloud/centos-7-v20161027
265 |
266 | ```text
267 | bootstrap_public_port
268 | ```
269 | The port on the bootstrap node which is used to fetch the dcos installer from each of the master and agent nodes. Default: 8080
270 |
271 | ```text
272 | cluster_name
273 | ```
274 | The name of the DC/OS cluster. Default: cluster_name
275 |
276 | ```text
277 | scopes
278 | ```
279 | Don't change this. Required by the google cloud SDK
280 |
281 | ```text
282 | dcos_installer_filename
283 | ```
284 | The filename for the DC/OS installer. Default dcos_generate_config.sh
285 |
286 | ```text
287 | dcos_installer_download_path
288 | ```
289 | The location of where the dcos installer is available from dcos.io. Default: https://downloads.dcos.io/dcos/stable/{{ dcos_installer_filename }} The value of {{ dcos_installer_file }} is described above.
290 |
291 | ```text
292 | home_directory
293 | ```
294 | The home directory for your logins. Default: /home/{{ login_name }} The value of {{ login_name }} is described above.
295 |
296 | ```text
297 | downloads_from_bootstrap
298 | ```
299 | The concurrent downloads of the dcos installer to the cluster of master and agent nodes. You may need to experiment with this to get the best performance. The performance will be a function of the machine type used for the bootstrap node. Default: 2
300 |
301 | ```text
302 | dcos_bootstrap_container
303 | ```
304 | Holds the name of the dcos bootstrap container running on the bootstrap node. Default: dcosinstaller
305 |
306 |
307 |
308 |
309 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/inventory/gce.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2013 Google Inc.
3 | #
4 | # This file is part of Ansible
5 | #
6 | # Ansible is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # Ansible is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with Ansible. If not, see .
18 |
19 | '''
20 | GCE external inventory script
21 | =================================
22 |
23 | Generates inventory that Ansible can understand by making API requests
24 | Google Compute Engine via the libcloud library. Full install/configuration
25 | instructions for the gce* modules can be found in the comments of
26 | ansible/test/gce_tests.py.
27 |
28 | When run against a specific host, this script returns the following variables
29 | based on the data obtained from the libcloud Node object:
30 | - gce_uuid
31 | - gce_id
32 | - gce_image
33 | - gce_machine_type
34 | - gce_private_ip
35 | - gce_public_ip
36 | - gce_name
37 | - gce_description
38 | - gce_status
39 | - gce_zone
40 | - gce_tags
41 | - gce_metadata
42 | - gce_network
43 |
44 | When run in --list mode, instances are grouped by the following categories:
45 | - zone:
46 | zone group name examples are us-central1-b, europe-west1-a, etc.
47 | - instance tags:
48 | An entry is created for each tag. For example, if you have two instances
49 | with a common tag called 'foo', they will both be grouped together under
50 | the 'tag_foo' name.
51 | - network name:
52 | the name of the network is appended to 'network_' (e.g. the 'default'
53 | network will result in a group named 'network_default')
54 | - machine type
55 | types follow a pattern like n1-standard-4, g1-small, etc.
56 | - running status:
57 | group name prefixed with 'status_' (e.g. status_running, status_stopped,..)
58 | - image:
59 | when using an ephemeral/scratch disk, this will be set to the image name
60 | used when creating the instance (e.g. debian-7-wheezy-v20130816). when
61 | your instance was created with a root persistent disk it will be set to
62 | 'persistent_disk' since there is no current way to determine the image.
63 |
64 | Examples:
65 | Execute uname on all instances in the us-central1-a zone
66 | $ ansible -i gce.py us-central1-a -m shell -a "/bin/uname -a"
67 |
68 | Use the GCE inventory script to print out instance specific information
69 | $ contrib/inventory/gce.py --host my_instance
70 |
71 | Author: Eric Johnson
72 | Contributors: Matt Hite
73 | Version: 0.0.2
74 | '''
75 |
76 | __requires__ = ['pycrypto>=2.6']
77 | try:
78 | import pkg_resources
79 | except ImportError:
80 | # Use pkg_resources to find the correct versions of libraries and set
81 | # sys.path appropriately when there are multiversion installs. We don't
82 | # fail here as there is code that better expresses the errors where the
83 | # library is used.
84 | pass
85 |
86 | USER_AGENT_PRODUCT="Ansible-gce_inventory_plugin"
87 | USER_AGENT_VERSION="v2"
88 |
89 | import sys
90 | import os
91 | import argparse
92 | import ConfigParser
93 |
94 | import logging
95 | logging.getLogger('libcloud.common.google').addHandler(logging.NullHandler())
96 |
97 | try:
98 | import json
99 | except ImportError:
100 | import simplejson as json
101 |
102 | try:
103 | from libcloud.compute.types import Provider
104 | from libcloud.compute.providers import get_driver
105 | _ = Provider.GCE
106 | except:
107 | print("GCE inventory script requires libcloud >= 0.13")
108 | sys.exit(1)
109 |
110 |
111 | class GceInventory(object):
112 | def __init__(self):
113 | # Read settings and parse CLI arguments
114 | self.parse_cli_args()
115 | self.config = self.get_config()
116 | self.driver = self.get_gce_driver()
117 | self.ip_type = self.get_inventory_options()
118 | if self.ip_type:
119 | self.ip_type = self.ip_type.lower()
120 |
121 | # Just display data for specific host
122 | if self.args.host:
123 | print(self.json_format_dict(self.node_to_dict(
124 | self.get_instance(self.args.host)),
125 | pretty=self.args.pretty))
126 | sys.exit(0)
127 |
128 | # Otherwise, assume user wants all instances grouped
129 | print(self.json_format_dict(self.group_instances(),
130 | pretty=self.args.pretty))
131 | sys.exit(0)
132 |
133 | def get_config(self):
134 | """
135 | Populates a SafeConfigParser object with defaults and
136 | attempts to read an .ini-style configuration from the filename
137 | specified in GCE_INI_PATH. If the environment variable is
138 | not present, the filename defaults to gce.ini in the current
139 | working directory.
140 | """
141 | gce_ini_default_path = os.path.join(
142 | os.path.dirname(os.path.realpath(__file__)), "gce.ini")
143 | gce_ini_path = os.environ.get('GCE_INI_PATH', gce_ini_default_path)
144 |
145 | # Create a ConfigParser.
146 | # This provides empty defaults to each key, so that environment
147 | # variable configuration (as opposed to INI configuration) is able
148 | # to work.
149 | config = ConfigParser.SafeConfigParser(defaults={
150 | 'gce_service_account_email_address': '',
151 | 'gce_service_account_pem_file_path': '',
152 | 'gce_project_id': '',
153 | 'libcloud_secrets': '',
154 | 'inventory_ip_type': '',
155 | })
156 | if 'gce' not in config.sections():
157 | config.add_section('gce')
158 | if 'inventory' not in config.sections():
159 | config.add_section('inventory')
160 |
161 | config.read(gce_ini_path)
162 | return config
163 |
164 | def get_inventory_options(self):
165 | """Determine inventory options. Environment variables always
166 | take precedence over configuration files."""
167 | ip_type = self.config.get('inventory', 'inventory_ip_type')
168 | # If the appropriate environment variables are set, they override
169 | # other configuration
170 | ip_type = os.environ.get('INVENTORY_IP_TYPE', ip_type)
171 | return ip_type
172 |
173 | def get_gce_driver(self):
174 | """Determine the GCE authorization settings and return a
175 | libcloud driver.
176 | """
177 | # Attempt to get GCE params from a configuration file, if one
178 | # exists.
179 | secrets_path = self.config.get('gce', 'libcloud_secrets')
180 | secrets_found = False
181 | try:
182 | import secrets
183 | args = list(getattr(secrets, 'GCE_PARAMS', []))
184 | kwargs = getattr(secrets, 'GCE_KEYWORD_PARAMS', {})
185 | secrets_found = True
186 | except:
187 | pass
188 |
189 | if not secrets_found and secrets_path:
190 | if not secrets_path.endswith('secrets.py'):
191 | err = "Must specify libcloud secrets file as "
192 | err += "/absolute/path/to/secrets.py"
193 | print(err)
194 | sys.exit(1)
195 | sys.path.append(os.path.dirname(secrets_path))
196 | try:
197 | import secrets
198 | args = list(getattr(secrets, 'GCE_PARAMS', []))
199 | kwargs = getattr(secrets, 'GCE_KEYWORD_PARAMS', {})
200 | secrets_found = True
201 | except:
202 | pass
203 | if not secrets_found:
204 | args = [
205 | self.config.get('gce','gce_service_account_email_address'),
206 | self.config.get('gce','gce_service_account_pem_file_path')
207 | ]
208 | kwargs = {'project': self.config.get('gce', 'gce_project_id')}
209 |
210 | # If the appropriate environment variables are set, they override
211 | # other configuration; process those into our args and kwargs.
212 | args[0] = os.environ.get('GCE_EMAIL', args[0])
213 | args[1] = os.environ.get('GCE_PEM_FILE_PATH', args[1])
214 | kwargs['project'] = os.environ.get('GCE_PROJECT', kwargs['project'])
215 |
216 | # Retrieve and return the GCE driver.
217 | gce = get_driver(Provider.GCE)(*args, **kwargs)
218 | gce.connection.user_agent_append(
219 | '%s/%s' % (USER_AGENT_PRODUCT, USER_AGENT_VERSION),
220 | )
221 | return gce
222 |
223 | def parse_cli_args(self):
224 | ''' Command line argument processing '''
225 |
226 | parser = argparse.ArgumentParser(
227 | description='Produce an Ansible Inventory file based on GCE')
228 | parser.add_argument('--list', action='store_true', default=True,
229 | help='List instances (default: True)')
230 | parser.add_argument('--host', action='store',
231 | help='Get all information about an instance')
232 | parser.add_argument('--pretty', action='store_true', default=False,
233 | help='Pretty format (default: False)')
234 | self.args = parser.parse_args()
235 |
236 |
237 | def node_to_dict(self, inst):
238 | md = {}
239 |
240 | if inst is None:
241 | return {}
242 |
243 | if inst.extra['metadata'].has_key('items'):
244 | for entry in inst.extra['metadata']['items']:
245 | md[entry['key']] = entry['value']
246 |
247 | net = inst.extra['networkInterfaces'][0]['network'].split('/')[-1]
248 | # default to exernal IP unless user has specified they prefer internal
249 | if self.ip_type == 'internal':
250 | ssh_host = inst.private_ips[0]
251 | else:
252 | ssh_host = inst.public_ips[0] if len(inst.public_ips) >= 1 else inst.private_ips[0]
253 |
254 | return {
255 | 'gce_uuid': inst.uuid,
256 | 'gce_id': inst.id,
257 | 'gce_image': inst.image,
258 | 'gce_machine_type': inst.size,
259 | 'gce_private_ip': inst.private_ips[0],
260 | 'gce_public_ip': inst.public_ips[0] if len(inst.public_ips) >= 1 else None,
261 | 'gce_name': inst.name,
262 | 'gce_description': inst.extra['description'],
263 | 'gce_status': inst.extra['status'],
264 | 'gce_zone': inst.extra['zone'].name,
265 | 'gce_tags': inst.extra['tags'],
266 | 'gce_metadata': md,
267 | 'gce_network': net,
268 | # Hosts don't have a public name, so we add an IP
269 | 'ansible_ssh_host': ssh_host
270 | }
271 |
272 | def get_instance(self, instance_name):
273 | '''Gets details about a specific instance '''
274 | try:
275 | return self.driver.ex_get_node(instance_name)
276 | except Exception as e:
277 | return None
278 |
279 | def group_instances(self):
280 | '''Group all instances'''
281 | groups = {}
282 | meta = {}
283 | meta["hostvars"] = {}
284 |
285 | for node in self.driver.list_nodes():
286 | name = node.name
287 |
288 | meta["hostvars"][name] = self.node_to_dict(node)
289 |
290 | zone = node.extra['zone'].name
291 | if groups.has_key(zone): groups[zone].append(name)
292 | else: groups[zone] = [name]
293 |
294 | tags = node.extra['tags']
295 | for t in tags:
296 | if t.startswith('group-'):
297 | tag = t[6:]
298 | else:
299 | tag = 'tag_%s' % t
300 | if groups.has_key(tag): groups[tag].append(name)
301 | else: groups[tag] = [name]
302 |
303 | net = node.extra['networkInterfaces'][0]['network'].split('/')[-1]
304 | net = 'network_%s' % net
305 | if groups.has_key(net): groups[net].append(name)
306 | else: groups[net] = [name]
307 |
308 | machine_type = node.size
309 | if groups.has_key(machine_type): groups[machine_type].append(name)
310 | else: groups[machine_type] = [name]
311 |
312 | image = node.image and node.image or 'persistent_disk'
313 | if groups.has_key(image): groups[image].append(name)
314 | else: groups[image] = [name]
315 |
316 | status = node.extra['status']
317 | stat = 'status_%s' % status.lower()
318 | if groups.has_key(stat): groups[stat].append(name)
319 | else: groups[stat] = [name]
320 |
321 | groups["_meta"] = meta
322 |
323 | return groups
324 |
325 | def json_format_dict(self, data, pretty=False):
326 | ''' Converts a dict to a JSON object and dumps it as a formatted
327 | string '''
328 |
329 | if pretty:
330 | return json.dumps(data, sort_keys=True, indent=2)
331 | else:
332 | return json.dumps(data)
333 |
334 |
335 | # Run the script
336 | GceInventory()
337 |
--------------------------------------------------------------------------------