You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2019/12/10 19:21:57 UTC

[couchdb-infra-cm] 02/03: Basic inventory generation

This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb-infra-cm.git

commit a329b177223ab247ce936f2de4edcb42725490fa
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Fri Aug 9 14:50:19 2019 -0500

    Basic inventory generation
    
    For the time being I'm relying on a tool to generate our inventory
    lists. In the future if we get our permissions scheme setup we'll be
    able to open this up to anyone that has an IBM Cloud account that is
    associated with the CouchDB CI Infra account.
---
 README.md           |  11 ++++
 production          |  24 +++++++++
 requirements.txt    |   1 +
 tools/gen-inventory | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 188 insertions(+)

diff --git a/README.md b/README.md
index fefe37b..82a2d52 100644
--- a/README.md
+++ b/README.md
@@ -9,3 +9,14 @@ Setup
     $ virtualenv venv
     $ source venv/bin/activate
     $ pip install -r requirements.txt
+
+
+Generating Inventory Listings
+---
+
+Create a `~/.couchdb-infra-cm.cfg` file that contains the following options:
+
+    [ibmcloud]
+    api_key = <REDACTED>
+
+Then simply run the script which will dump the current inventory to stdout. Redirect the output to whatever filename you so desire.
diff --git a/production b/production
new file mode 100644
index 0000000..940d582
--- /dev/null
+++ b/production
@@ -0,0 +1,24 @@
+all:
+  children:
+    ci_agents:
+      hosts:
+        169.61.160.207:
+          boot_volume:
+            device: xvda
+            name: ci-farm-server-1-boot
+          instance:
+            created_at: '2019-08-09T17:10:36.149Z'
+            id: ff9bd14d-c0ea-4f99-9d62-0c9b2f566264
+            name: ci-farm-server-1
+            profile: cc1-4x8
+            subnet: couchdb-ci-farm-subnet-2
+            vpc: couchdb-ci-farm
+            zone: us-south-2
+          ips:
+            private: 10.240.64.4
+            public: 169.61.160.207
+          system:
+            arch: amd64
+            num_cpus: 4
+            ram: 8
+
diff --git a/requirements.txt b/requirements.txt
index 90d4055..8bf65d1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1,2 @@
 ansible
+requests
diff --git a/tools/gen-inventory b/tools/gen-inventory
new file mode 100755
index 0000000..3f85b2a
--- /dev/null
+++ b/tools/gen-inventory
@@ -0,0 +1,152 @@
+#!/usr/bin/env python
+
+import ConfigParser as cp
+import json
+import os
+import re
+
+import requests
+import yaml
+
+
+IBM_CLOUD_URL = "https://us-south.iaas.cloud.ibm.com/v1/"
+IAM_URL = "https://iam.cloud.ibm.com/identity/token"
+
+IBM_CLOUD_GENERATION = "1"
+IBM_CLOUD_VERSION = "2019-08-09"
+
+API_KEY = None
+IAM_TOKEN = None
+SESS = requests.session()
+
+CI_AGENT_RE = re.compile("ci-farm-server-\d+")
+
+
+def tostr(obj):
+    ret = {}
+    for k, v in obj.items():
+        if isinstance(k, unicode):
+            k = k.encode("utf-8")
+        if isinstance(v, dict):
+            ret[k] = tostr(v)
+        elif isinstance(v, unicode):
+            ret[k] = v.encode("utf-8")
+        else:
+            ret[k] = v
+    return ret
+
+
+def load_api_key():
+    global API_KEY
+    path = os.path.expanduser("~/.couchdb-infra-cm.cfg")
+    if not os.path.exists(path):
+        print "Missing config file: " + path
+        exit(1)
+    parser = cp.SafeConfigParser()
+    parser.read([path])
+    API_KEY = parser.get("ibmcloud", "api_key")
+
+
+def load_iam_token():
+    global IAM_TOKEN
+    headers = {
+        "Accept": "application/json"
+    }
+    data = {
+        "grant_type": "urn:ibm:params:oauth:grant-type:apikey",
+        "apikey": API_KEY
+    }
+    resp = SESS.post(IAM_URL, headers=headers, data=data)
+    resp.raise_for_status()
+    body = resp.json()
+    IAM_TOKEN = body["token_type"] + " " + body["access_token"]
+    SESS.headers["Authorization"] = IAM_TOKEN
+
+
+def init():
+    load_api_key()
+    load_iam_token()
+
+
+def list_instances():
+    url = IBM_CLOUD_URL + "/instances"
+    params = {
+        "version": IBM_CLOUD_VERSION,
+        "generation": IBM_CLOUD_GENERATION,
+        "limit": 100
+    }
+    while url:
+        resp = SESS.get(url, params=params)
+        body = resp.json()
+        for instance in body["instances"]:
+            interface_url = instance["primary_network_interface"]["href"]
+            resp = SESS.get(interface_url, params=params)
+            instance["primary_network_interface"] = resp.json()
+            yield instance
+        url = body.get("next")
+
+
+def load_ci_agent(ci_agents, instance):
+    if instance["status"] != "running":
+        return
+
+    name = instance["name"]
+    floating_ips = instance["primary_network_interface"]["floating_ips"]
+    if not len(floating_ips):
+        print "Instance {} does not have any floating ips".format(name)
+        exit(2)
+
+    public_ip = floating_ips[0]["address"]
+
+    ci_agents[public_ip] = {
+        "instance": {
+            "id": instance["id"],
+            "name": instance["name"],
+            "created_at": instance["created_at"],
+            "profile": instance["profile"]["name"],
+            "vpc": instance["vpc"]["name"],
+            "zone": instance["zone"]["name"],
+            "subnet": instance["primary_network_interface"]["subnet"]["name"]
+        },
+        "ips": {
+            "public": public_ip,
+            "private": instance["primary_network_interface"]["primary_ipv4_address"]
+        },
+        "boot_volume": {
+            "device": instance["boot_volume_attachment"]["device"]["id"],
+            "name": instance["boot_volume_attachment"]["volume"]["name"]
+        },
+        "system": {
+            "arch": instance["vcpu"]["architecture"],
+            "num_cpus": instance["vcpu"]["count"],
+            "ram": instance["memory"]
+        }
+    }
+
+
+def main():
+    init()
+
+    ci_agents = {}
+
+    for instance in list_instances():
+        if CI_AGENT_RE.match(instance["name"]):
+            load_ci_agent(ci_agents, instance)
+            continue
+
+        print "Unknown instance: " + instance["name"]
+        exit(2)
+
+    inventory = {"all": {
+        "children": {
+            "ci_agents": {
+                "hosts": ci_agents
+            }
+        }
+    }}
+
+    print yaml.dump(tostr(inventory), default_flow_style=False)
+
+
+if __name__ == "__main__":
+    main()