Skip to content

Commit

Permalink
rearchitect
Browse files Browse the repository at this point in the history
  • Loading branch information
pacogomez committed Dec 28, 2017
1 parent 1fab7d8 commit 434a7e1
Show file tree
Hide file tree
Showing 21 changed files with 1,052 additions and 73 deletions.
5 changes: 5 additions & 0 deletions cleanup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash

rm -rf build dist *.egg-info
find . -name '*.pyc' -delete
find . -name '*.log' -delete
151 changes: 118 additions & 33 deletions container_service_extension/broker.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
# SPDX-License-Identifier: BSD-2-Clause

import click

from container_service_extension.cluster import add_nodes
from container_service_extension.cluster import get_master_ip
from container_service_extension.cluster import init_cluster
from container_service_extension.cluster import join_cluster
from container_service_extension.cluster import load_from_metadata
from container_service_extension.cluster import TYPE_MASTER
from container_service_extension.cluster import TYPE_NODE

import logging

import pkg_resources

from pyvcloud.vcd.client import _WellKnownEndpoint
from pyvcloud.vcd.client import BasicLoginCredentials
from pyvcloud.vcd.client import Client
Expand All @@ -12,10 +22,10 @@
from pyvcloud.vcd.task import Task
from pyvcloud.vcd.vapp import VApp
from pyvcloud.vcd.vdc import VDC

import re
import requests
import threading
import time
import traceback
import uuid
import yaml
Expand All @@ -39,6 +49,8 @@

SAMPLE_TEMPLATE_PHOTON_V1 = {
'name':
'photon-v1',
'catalog_item':
'photon-custom-hw11-1.0-62c543d-k8s',
'source_ova_name':
'photon-custom-hw11-1.0-62c543d.ova',
Expand All @@ -55,11 +67,15 @@
'mem':
2048,
'admin_password':
'guest_os_admin_password'
'guest_os_admin_password',
'description':
"PhotonOS v1\nDocker 17.06.0-1\nKubernetes 1.8.1\nweave 2.0.5"
}

SAMPLE_TEMPLATE_UBUNTU_16_04 = {
'name':
'ubuntu-16.04',
'catalog_item':
'ubuntu-16.04-server-cloudimg-amd64-k8s',
'source_ova_name':
'ubuntu-16.04-server-cloudimg-amd64.ova',
Expand All @@ -76,7 +92,9 @@
'mem':
2048,
'admin_password':
'guest_os_admin_password'
'guest_os_admin_password',
'description':
'Ubuntu 16.04\nDocker 17.09.0~ce\nKubernetes 1.8.2\nweave 2.0.5'
}

SAMPLE_CONFIG = {
Expand Down Expand Up @@ -115,25 +133,27 @@ def validate_broker_config_elements(config):
raise Exception('invalid key: %s' % k)


def validate_broker_config_content(config, client):
def validate_broker_config_content(config, client, template):
from container_service_extension.config import bool_to_msg
logged_in_org = client.get_org()
org = Org(client, resource=logged_in_org)
org.get_catalog(config['broker']['catalog'])
click.echo('Find catalog \'%s\': %s' % (config['broker']['catalog'],
bool_to_msg(True)))
default_template_found = False
for template in config['broker']['templates']:
click.secho('Validating template: %s' % template['name'])
if config['broker']['default_template'] == template['name']:
default_template_found = True
click.secho(' Is default template: %s' % True)
else:
click.secho(' Is default template: %s' % False)
org.get_catalog_item(config['broker']['catalog'], template['name'])
click.echo('Find template \'%s\', \'%s\': %s' %
(config['broker']['catalog'], template['name'],
bool_to_msg(True)))
for t in config['broker']['templates']:
if template == '*' or template == t['name']:
click.secho('Validating template: %s' % t['name'])
if config['broker']['default_template'] == t['name']:
default_template_found = True
click.secho(' Is default template: %s' % True)
else:
click.secho(' Is default template: %s' % False)
org.get_catalog_item(config['broker']['catalog'],
t['catalog_item'])
click.echo('Find template \'%s\', \'%s\': %s' %
(config['broker']['catalog'], t['catalog_item'],
bool_to_msg(True)))

assert default_template_found

Expand All @@ -145,22 +165,6 @@ def get_new_broker(config):
return None


def wait_until_tools_ready(vm):
while True:
try:
status = vm.guest.toolsRunningStatus
if 'guestToolsRunning' == status:
LOGGER.debug('vm tools %s are ready' % vm)
return
LOGGER.debug('waiting for vm tools %s to be ready (%s)' % (vm,
status))
time.sleep(1)
except Exception:
LOGGER.debug('waiting for vm tools %s to be ready (%s)* ' %
(vm, status))
time.sleep(1)


def spinning_cursor():
while True:
for cursor in '|/-\\':
Expand Down Expand Up @@ -247,8 +251,8 @@ def update_task(self, status, operation, message=None, error_message=None):
self.t = self.task.update(
status.value,
'vcloud.cse',
operation,
message,
operation,
'',
None,
'urn:cse:cluster:%s' % self.cluster_id,
Expand All @@ -271,6 +275,16 @@ def is_valid_name(self, name):
allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
return all(allowed.match(x) for x in name.split("."))

def get_template(self):
if 'template' in self.body and self.body['template'] is not None:
name = self.body['template']
else:
name = self.config['broker']['default_template']
for template in self.config['broker']['templates']:
if template['name'] == name:
return template
raise Exception('Template %s not found' % name)

def run(self):
LOGGER.debug('thread started op=%s' % self.op)
if self.op == OP_CREATE_CLUSTER:
Expand Down Expand Up @@ -344,6 +358,11 @@ def create_cluster_thread(self):
org = Org(self.client_tenant, resource=org_resource)
vdc_resource = org.get_vdc(self.body['vdc'])
vdc = VDC(self.client_tenant, resource=vdc_resource)
self.update_task(
TaskStatus.RUNNING,
self.op,
message='Creating cluster vApp %s(%s)' % (self.cluster_name,
self.cluster_id))
vapp_resource = vdc.create_vapp(
self.cluster_name,
description='cluster %s' % self.cluster_name,
Expand All @@ -359,6 +378,7 @@ def create_cluster_thread(self):
TaskStatus.CANCELED
],
callback=None)
assert t.get('status').lower() == TaskStatus.SUCCESS.value
tags = {}
tags['cse.cluster.id'] = self.cluster_id
tags['cse.version'] = pkg_resources.require(
Expand All @@ -374,8 +394,73 @@ def create_cluster_thread(self):
fail_on_status=None,
expected_target_statuses=[TaskStatus.SUCCESS],
callback=None)
self.update_task(
TaskStatus.RUNNING,
self.op,
message='Creating master node for %s(%s)' % (self.cluster_name,
self.cluster_id))
template = self.get_template()
vapp.reload()
add_nodes(
1,
template,
TYPE_MASTER,
self.config,
self.client_tenant,
org,
vdc,
vapp,
self.body,
wait=True)

self.update_task(
TaskStatus.RUNNING,
self.op,
message='Initializing cluster %s(%s)' % (self.cluster_name,
self.cluster_id))

vapp.reload()
init_cluster(self.config, vapp, template)

master_ip = get_master_ip(self.config, vapp, template)
t = vapp.set_metadata('GENERAL', 'READWRITE', 'cse.master.ip',
master_ip)
self.client_tenant.get_task_monitor().\
wait_for_status(
task=t,
timeout=600,
poll_frequency=5,
fail_on_status=None,
expected_target_statuses=[TaskStatus.SUCCESS],
callback=None)

# self.customize_nodes()
if self.body['node_count'] > 0:

self.update_task(
TaskStatus.RUNNING,
self.op,
message='Creating %s node(s) for %s(%s)' %
(self.body['node_count'], self.cluster_name,
self.cluster_id))
add_nodes(
self.body['node_count'],
template,
TYPE_NODE,
self.config,
self.client_tenant,
org,
vdc,
vapp,
self.body,
wait=True)
self.update_task(
TaskStatus.RUNNING,
self.op,
message='Adding %s node(s) to %s(%s)' %
(self.body['node_count'], self.cluster_name,
self.cluster_id))
vapp.reload()
join_cluster(self.config, vapp, template)

self.update_task(
TaskStatus.SUCCESS,
Expand Down
Empty file.
129 changes: 129 additions & 0 deletions container_service_extension/client/cluster.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# container-service-extension
# Copyright (c) 2017 VMware, Inc. All Rights Reserved.
# SPDX-License-Identifier: BSD-2-Clause


import json
import requests


class Cluster(object):
def __init__(self, client):
self.client = client
self._uri = self.client.get_api_uri() + '/cse'

def get_templates(self):
method = 'GET'
uri = '%s/template' % (self._uri)
response = self.client._do_request_prim(
method,
uri,
self.client._session,
contents=None,
media_type=None,
accept_type='application/*+json',
auth=None)
if response.status_code == requests.codes.ok:
return json.loads(response.content.decode("utf-8"))
else:
raise Exception(json.loads(response.content))

def get_clusters(self):
method = 'GET'
uri = self._uri
response = self.client._do_request_prim(
method,
uri,
self.client._session,
contents=None,
media_type=None,
accept_type='application/*+json',
auth=None)
if response.status_code == requests.codes.ok:
return json.loads(response.content.decode("utf-8"))
else:
raise Exception(json.loads(response.content))

def create_cluster(self,
vdc,
network_name,
name,
node_count=2,
cpu_count=None,
memory=None,
storage_profile=None,
ssh_key=None,
template=None):
"""Create a new Kubernetes cluster
:param vdc: (str): The name of the vdc backing the org in which the
cluster would be created
:param network_name: (str): The name of the network to which the
cluster vApp will connect to
:param name: (str): The name of the cluster
:param node_count: (str): The number of slave nodes
:param cpu_count: (str): The number of virtual cpus on each of the
nodes in the cluster
:param memory: (str): The amount of memory (in MB) on each of the nodes
in the cluster
:param storage_profile: (str): The name of the storage profile which
will back the cluster
:param ssh_key: (str): The ssh key that clients can use to log into the
node vms without explicitly providing passwords
:param template: (str): The name of the catalog template to
instantiate the nodes from
:return: (json) A parsed json object describing the requested cluster.
"""
method = 'POST'
uri = self._uri
data = {
'name': name,
'node_count': node_count,
'vdc': vdc,
'cpu_count': cpu_count,
'memory': memory,
'network': network_name,
'storage_profile': storage_profile,
'ssh_key': ssh_key,
'template': template
}
response = self.client._do_request_prim(
method,
uri,
self.client._session,
contents=data,
media_type=None,
accept_type='application/*+json')
if response.status_code == requests.codes.accepted:
return json.loads(response.content)
else:
raise Exception(json.loads(response.content).get('message'))

def delete_cluster(self, cluster_name):
method = 'DELETE'
uri = '%s/%s' % (self._uri, cluster_name)
response = self.client._do_request_prim(
method,
uri,
self.client._session,
accept_type='application/*+json')
if response.status_code == requests.codes.accepted:
return json.loads(response.content)
else:
raise Exception(json.loads(response.content).get('message'))

def get_config(self, cluster_name):
method = 'GET'
uri = '%s/%s/config' % (self._uri, cluster_name)
response = self.client._do_request_prim(
method,
uri,
self.client._session,
contents=None,
media_type=None,
accept_type='text/x-yaml',
auth=None)
if response.status_code == requests.codes.ok:
return response.content.decode('utf-8').replace('\\n', '\n')[1:-1]
else:
raise Exception(json.loads(response.content))
Loading

0 comments on commit 434a7e1

Please sign in to comment.