summaryrefslogtreecommitdiffstats
path: root/roles/openshift_node/library
diff options
context:
space:
mode:
authorJason DeTiberus <jdetiber@redhat.com>2015-03-23 16:30:49 -0400
committerJhon Honce <jhonce@redhat.com>2015-03-24 11:29:44 -0700
commitd67c5b8f79609d2d3b07cc009f58e3dc988782c5 (patch)
tree9daf6d897dbb60d680f6dd195464e5157eab6953 /roles/openshift_node/library
parent461f6c1e07f36238729944a5f769600077ebf0b0 (diff)
downloadopenshift-d67c5b8f79609d2d3b07cc009f58e3dc988782c5.tar.gz
openshift-d67c5b8f79609d2d3b07cc009f58e3dc988782c5.tar.bz2
openshift-d67c5b8f79609d2d3b07cc009f58e3dc988782c5.tar.xz
openshift-d67c5b8f79609d2d3b07cc009f58e3dc988782c5.zip
node registration changes
- Remove default value for openshift_hostname and make it required - Remove workarounds that are no longer needed - Remove resources parameter from openshift_register_node module - pre-create node certificates for each node before registering node - distribute created node certificates to each node - Move node registration logic to a new openshift_register_nodes role - This is because we now have to run the steps on a master as opposed to on the nodes like we were previously doing. - Rename openshift_register_node module to kubernetes_register_node, one more step to genericizing enough for upstreaming, however there are still plenty of openshift specific commands that still need to be genericized.
Diffstat (limited to 'roles/openshift_node/library')
-rw-r--r--roles/openshift_node/library/openshift_register_node.py390
1 files changed, 0 insertions, 390 deletions
diff --git a/roles/openshift_node/library/openshift_register_node.py b/roles/openshift_node/library/openshift_register_node.py
deleted file mode 100644
index 4922585d7..000000000
--- a/roles/openshift_node/library/openshift_register_node.py
+++ /dev/null
@@ -1,390 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# vim: expandtab:tabstop=4:shiftwidth=4
-
-import os
-import multiprocessing
-import socket
-from subprocess import check_output, Popen
-from decimal import *
-
-DOCUMENTATION = '''
----
-module: kubernetes_register_node
-short_description: Registers a kubernetes node with a master
-description:
- - Registers a kubernetes node with a master
-options:
- name:
- default: null
- description:
- - Identifier for this node (usually the node fqdn).
- required: true
- api_verison:
- choices: ['v1beta1', 'v1beta3']
- default: 'v1beta1'
- description:
- - Kubernetes API version to use
- required: true
- host_ip:
- default: null
- description:
- - IP Address to associate with the node when registering.
- Available in the following API versions: v1beta1.
- required: false
- hostnames:
- default: []
- description:
- - Valid hostnames for this node. Available in the following API
- versions: v1beta3.
- required: false
- external_ips:
- default: []
- description:
- - External IP Addresses for this node. Available in the following API
- versions: v1beta3.
- required: false
- internal_ips:
- default: []
- description:
- - Internal IP Addresses for this node. Available in the following API
- versions: v1beta3.
- required: false
- cpu:
- default: null
- description:
- - Number of CPUs to allocate for this node. If not provided, then
- the node will be registered to advertise the number of logical
- CPUs available. When using the v1beta1 API, you must specify the
- CPU count as a floating point number with no more than 3 decimal
- places. API version v1beta3 and newer accepts arbitrary float
- values.
- required: false
- memory:
- default: null
- description:
- - Memory available for this node. If not provided, then the node
- will be registered to advertise 80% of MemTotal as available
- memory. When using the v1beta1 API, you must specify the memory
- size in bytes. API version v1beta3 and newer accepts binary SI
- and decimal SI values.
- required: false
-'''
-EXAMPLES = '''
-# Minimal node registration
-- openshift_register_node: name=ose3.node.example.com
-
-# Node registration using the v1beta1 API and assigning 1 CPU core and 10 GB of
-# Memory
-- openshift_register_node:
- name: ose3.node.example.com
- api_version: v1beta1
- hostIP: 192.168.1.1
- cpu: 1
- memory: 500000000
-
-# Node registration using the v1beta3 API, setting an alternate hostname,
-# internalIP, externalIP and assigning 3.5 CPU cores and 1 TiB of Memory
-- openshift_register_node:
- name: ose3.node.example.com
- api_version: v1beta3
- external_ips: ['192.168.1.5']
- internal_ips: ['10.0.0.5']
- hostnames: ['ose2.node.internal.local']
- cpu: 3.5
- memory: 1Ti
-'''
-
-
-class ClientConfigException(Exception):
- pass
-
-class ClientConfig:
- def __init__(self, client_opts, module):
- _, output, error = module.run_command(["/usr/bin/openshift", "ex",
- "config", "view", "-o",
- "json"] + client_opts,
- check_rc = True)
- self.config = json.loads(output)
-
- if not (bool(self.config['clusters']) or
- bool(self.config['contexts']) or
- bool(self.config['current-context']) or
- bool(self.config['users'])):
- raise ClientConfigException(msg="Client config missing required " \
- "values",
- output=output)
-
- def current_context(self):
- return self.config['current-context']
-
- def section_has_value(self, section_name, value):
- section = self.config[section_name]
- if isinstance(section, dict):
- return value in section
- else:
- val = next((item for item in section
- if item['name'] == value), None)
- return val is not None
-
- def has_context(self, context):
- return self.section_has_value('contexts', context)
-
- def has_user(self, user):
- return self.section_has_value('users', user)
-
- def has_cluster(self, cluster):
- return self.section_has_value('clusters', cluster)
-
- def get_value_for_context(self, context, attribute):
- contexts = self.config['contexts']
- if isinstance(contexts, dict):
- return contexts[context][attribute]
- else:
- return next((c['context'][attribute] for c in contexts
- if c['name'] == context), None)
-
- def get_user_for_context(self, context):
- return self.get_value_for_context(context, 'user')
-
- def get_cluster_for_context(self, context):
- return self.get_value_for_context(context, 'cluster')
-
-class Util:
- @staticmethod
- def getLogicalCores():
- return multiprocessing.cpu_count()
-
- @staticmethod
- def getMemoryPct(pct):
- with open('/proc/meminfo', 'r') as mem:
- for line in mem:
- entries = line.split()
- if str(entries.pop(0)) == 'MemTotal:':
- mem_total_kb = Decimal(entries.pop(0))
- mem_capacity_kb = mem_total_kb * Decimal(pct)
- return str(mem_capacity_kb.to_integral_value() * 1024)
-
- return ""
-
- @staticmethod
- def remove_empty_elements(mapping):
- if isinstance(mapping, dict):
- m = mapping.copy()
- for key, val in mapping.iteritems():
- if not val:
- del m[key]
- return m
- else:
- return mapping
-
-class NodeResources:
- def __init__(self, version, cpu=None, memory=None):
- if version == 'v1beta1':
- self.resources = dict(capacity=dict())
- self.resources['capacity']['cpu'] = cpu if cpu else Util.getLogicalCores()
- self.resources['capacity']['memory'] = memory if cpu else Util.getMemoryPct(.75)
-
- def get_resources(self):
- return Util.remove_empty_elements(self.resources)
-
-class NodeSpec:
- def __init__(self, version, cpu=None, memory=None, cidr=None, externalID=None):
- if version == 'v1beta3':
- self.spec = dict(podCIDR=cidr, externalID=externalID,
- capacity=dict())
- self.spec['capacity']['cpu'] = cpu if cpu else Util.getLogicalCores()
- self.spec['capacity']['memory'] = memory if memory else Util.getMemoryPct(.75)
-
- def get_spec(self):
- return Util.remove_empty_elements(self.spec)
-
-class NodeStatus:
- def addAddresses(self, addressType, addresses):
- addressList = []
- for address in addresses:
- addressList.append(dict(type=addressType, address=address))
- return addressList
-
- def __init__(self, version, externalIPs = [], internalIPs = [],
- hostnames = []):
- if version == 'v1beta3':
- self.status = dict(addresses = addAddresses('ExternalIP',
- externalIPs) +
- addAddresses('InternalIP',
- internalIPs) +
- addAddresses('Hostname',
- hostnames))
-
- def get_status(self):
- return Util.remove_empty_elements(self.status)
-
-class Node:
- def __init__(self, module, client_opts, version='v1beta1', name=None,
- hostIP = None, hostnames=[], externalIPs=[], internalIPs=[],
- cpu=None, memory=None, labels=dict(), annotations=dict(),
- podCIDR=None, externalID=None):
- self.module = module
- self.client_opts = client_opts
- if version == 'v1beta1':
- self.node = dict(id = name,
- kind = 'Node',
- apiVersion = version,
- hostIP = hostIP,
- resources = NodeResources(version, cpu, memory),
- cidr = podCIDR,
- labels = labels,
- annotations = annotations
- )
- elif version == 'v1beta3':
- metadata = dict(name = name,
- labels = labels,
- annotations = annotations
- )
- self.node = dict(kind = 'Node',
- apiVersion = version,
- metadata = metadata,
- spec = NodeSpec(version, cpu, memory, podCIDR,
- externalID),
- status = NodeStatus(version, externalIPs,
- internalIPs, hostnames),
- )
-
- def get_name(self):
- if self.node['apiVersion'] == 'v1beta1':
- return self.node['id']
- elif self.node['apiVersion'] == 'v1beta3':
- return self.node['name']
-
- def get_node(self):
- node = self.node.copy()
- if self.node['apiVersion'] == 'v1beta1':
- node['resources'] = self.node['resources'].get_resources()
- elif self.node['apiVersion'] == 'v1beta3':
- node['spec'] = self.node['spec'].get_spec()
- node['status'] = self.node['status'].get_status()
- return Util.remove_empty_elements(node)
-
- def exists(self):
- _, output, error = self.module.run_command(["/usr/bin/osc", "get",
- "nodes"] + self.client_opts,
- check_rc = True)
- if re.search(self.module.params['name'], output, re.MULTILINE):
- return True
- return False
-
- def create(self):
- cmd = ['/usr/bin/osc'] + self.client_opts + ['create', 'node', '-f', '-']
- rc, output, error = self.module.run_command(cmd,
- data=self.module.jsonify(self.get_node()))
- if rc != 0:
- if re.search("minion \"%s\" already exists" % self.get_name(),
- error):
- self.module.exit_json(changed=False,
- msg="node definition already exists",
- node=self.get_node())
- else:
- self.module.fail_json(msg="Node creation failed.", rc=rc,
- output=output, error=error,
- node=self.get_node())
- else:
- return True
-
-def main():
- module = AnsibleModule(
- argument_spec = dict(
- name = dict(required = True, type = 'str'),
- host_ip = dict(type = 'str'),
- hostnames = dict(type = 'list', default = []),
- external_ips = dict(type = 'list', default = []),
- internal_ips = dict(type = 'list', default = []),
- api_version = dict(type = 'str', default = 'v1beta1', # TODO: after kube rebase, we can default to v1beta3
- choices = ['v1beta1', 'v1beta3']),
- cpu = dict(type = 'str'),
- memory = dict(type = 'str'),
- labels = dict(type = 'dict', default = {}), # TODO: needs documented
- annotations = dict(type = 'dict', default = {}), # TODO: needs documented
- pod_cidr = dict(type = 'str'), # TODO: needs documented
- external_id = dict(type = 'str'), # TODO: needs documented
- client_config = dict(type = 'str'), # TODO: needs documented
- client_cluster = dict(type = 'str', default = 'master'), # TODO: needs documented
- client_context = dict(type = 'str', default = 'master'), # TODO: needs documented
- client_user = dict(type = 'str', default = 'admin') # TODO: needs documented
- ),
- mutually_exclusive = [
- ['host_ip', 'external_ips'],
- ['host_ip', 'internal_ips'],
- ['host_ip', 'hostnames'],
- ],
- supports_check_mode=True
- )
-
- user_has_client_config = os.path.exists(os.path.expanduser('~/.kube/.kubeconfig'))
- if not (user_has_client_config or module.params['client_config']):
- module.fail_json(msg="Could not locate client configuration, "
- "client_config must be specified if "
- "~/.kube/.kubeconfig is not present")
-
- client_opts = []
- if module.params['client_config']:
- client_opts.append("--kubeconfig=%s" % module.params['client_config'])
-
- try:
- config = ClientConfig(client_opts, module)
- except ClientConfigException as e:
- module.fail_json(msg="Failed to get client configuration", exception=e)
-
- client_context = module.params['client_context']
- if config.has_context(client_context):
- if client_context != config.current_context():
- client_opts.append("--context=%s" % client_context)
- else:
- module.fail_json(msg="Context %s not found in client config" %
- client_context)
-
- client_user = module.params['client_user']
- if config.has_user(client_user):
- if client_user != config.get_user_for_context(client_context):
- client_opts.append("--user=%s" % client_user)
- else:
- module.fail_json(msg="User %s not found in client config" %
- client_user)
-
- client_cluster = module.params['client_cluster']
- if config.has_cluster(client_cluster):
- if client_cluster != config.get_cluster_for_context(client_cluster):
- client_opts.append("--cluster=%s" % client_cluster)
- else:
- module.fail_json(msg="Cluster %s not found in client config" %
- client_cluster)
-
- # TODO: provide sane defaults for some (like hostname, externalIP,
- # internalIP, etc)
- node = Node(module, client_opts, module.params['api_version'],
- module.params['name'], module.params['host_ip'],
- module.params['hostnames'], module.params['external_ips'],
- module.params['internal_ips'], module.params['cpu'],
- module.params['memory'], module.params['labels'],
- module.params['annotations'], module.params['pod_cidr'],
- module.params['external_id'])
-
- # TODO: attempt to support changing node settings where possible and/or
- # modifying node resources
- if node.exists():
- module.exit_json(changed=False, node=node.get_node())
- elif module.check_mode:
- module.exit_json(changed=True, node=node.get_node())
- else:
- if node.create():
- module.exit_json(changed=True,
- msg="Node created successfully",
- node=node.get_node())
- else:
- module.fail_json(msg="Unknown error creating node",
- node=node.get_node())
-
-
-# import module snippets
-from ansible.module_utils.basic import *
-if __name__ == '__main__':
- main()