From 1fc41ad97411b435c512ba3a0de63929eda9c33d Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Fri, 28 Jun 2019 08:00:28 +0300 Subject: Change: make yarns run against a remote Ick instance, not local --- yarns/lib.py | 214 +++++++++++++++++++++++++++-------------------------------- 1 file changed, 99 insertions(+), 115 deletions(-) (limited to 'yarns/lib.py') diff --git a/yarns/lib.py b/yarns/lib.py index 5fbd5ab..6d8f2cf 100644 --- a/yarns/lib.py +++ b/yarns/lib.py @@ -19,11 +19,13 @@ import errno import json import os import random +import re import signal import socket import sys import time import urllib +import uuid import cliapp import requests @@ -37,119 +39,80 @@ datadir = os.environ['DATADIR'] V = Variables(datadir) -def start_controller(): - port = V['port'] = random_free_port() - - V['url'] = 'http://127.0.0.1:{}'.format(V['port']) - - filename = 'ick_controller.yaml' - env = dict(os.environ) - env['ICK_CONTROLLER_CONFIG'] = filename - write_yaml(filename, { - 'token-issuer': V['issuer'], - 'token-audience': V['audience'], - 'token-public-key': cat('token.key.pub'), - 'log': [ - { - 'filename': 'ick_controller.log', - }, - ], - 'statedir': V['statedir'], - 'apt-server': 'localhost', - 'artifact-store': V['artifact_store'], - 'auth-url': V['auth_url'], - 'notify-url': V['notify_url'], - }) - - V['pid'] = gunicorn('ick_controller', 'app', port, env) - - -def stop_controller(): - if V['pid'] is not None: - os.kill(int(V['pid']), signal.SIGTERM) - - -def start_artifact_store(): - port = V['bsport'] = random_free_port() - - V['bsurl'] = 'http://127.0.0.1:{}'.format(V['bsport']) - - filename = 'artifact_store.yaml' - env = dict(os.environ) - env['ARTIFACT_STORE_CONFIG'] = filename - write_yaml(filename, { - 'token-issuer': V['issuer'], - 'token-audience': V['audience'], - 'token-public-key': cat('token.key.pub'), - 'log': [ - { - 'filename': 'artifact_store.log', - }, - ], - 'blobdir': V['blobdir'], - }) - - V['bspid'] = gunicorn('artifact_store', 'app', port, env) - - -def stop_artifact_store(): - if V['pid'] is not None: - os.kill(int(V['bspid']), signal.SIGTERM) - - -def write_yaml(filename, obj): - yaml.safe_dump(obj, open(filename, 'w')) - - -def gunicorn(module_name, var_name, port, env): - log_filename = '{}.gunicorn.log'.format(module_name) - pid_filename = '{}.pid'.format(module_name) - - argv = [ - 'gunicorn3', - '--daemon', - '--bind', '127.0.0.1:{}'.format(port), - '--log-file', log_filename, - '--log-level', 'debug', - '-p', pid_filename, - '{}:{}'.format(module_name, var_name), - ] - cliapp.runcmd(argv, env=env) - wait_for_port(port) - return int(cat(pid_filename)) - - -def random_free_port(): - MAX = 1000 - for i in range(MAX): - port = random.randint(1025, 2**15-1) - s = socket.socket() - try: - s.bind(('0.0.0.0', port)) - except OSError as e: - if e.errno == errno.EADDRINUSE: - continue - print('cannot find a random free port') - raise - s.close() - break - print('picked port', port) - return port - - -def wait_for_port(port): - MAX = 5 - t = time.time() - while time.time() < t + MAX: - try: - s = socket.socket() - s.connect(('127.0.0.1', port)) - except socket.error: - time.sleep(0.1) - except OSError as e: - raise - else: - return +def remember_client_id(alias, client_id, client_secret): + clients = V['clients'] + if clients is None: + clients = {} + clients[alias] = { + 'client_id': client_id, + 'client_secret': client_secret, + } + V['clients'] = clients + + +def get_client_id(alias): + clients = V['clients'] or {} + return clients[alias]['client_id'] + + +def get_client_ids(): + clients = V['clients'] or {} + return [x['client_id'] for x in clients.values()] + + +def get_client_secret(alias): + clients = V['clients'] or {} + return clients[alias]['client_secret'] + + +def create_api_client(alias, scopes): + client_id = str(uuid.uuid4()) + client_secret = str(uuid.uuid4()) + print('invented client id', client_id) + api = os.environ['CONTROLLER'] + print('controller URL', api) + secrets = os.environ['SECRETS'] + print('secrets', secrets) + base_argv = ['qvisqvetool', '--secrets', secrets, '-a', api] + print('base_argv', base_argv) + cliapp.runcmd(base_argv + ['create', 'client', client_id, client_secret]) + cliapp.runcmd(base_argv + ['allow-scope', 'client', client_id] + scopes) + remember_client_id(alias, client_id, client_secret) + + +def delete_api_client(client_id): + api = os.environ['CONTROLLER'] + secrets = os.environ['SECRETS'] + base_argv = ['qvisqvetool', '--secrets', secrets, '-a', api] + cliapp.runcmd(base_argv + ['delete', 'client', client_id]) + + +def get_api_token(alias, scopes): + print('getting token for', alias) + + client_id = get_client_id(alias) + client_secret = get_client_secret(alias) + api = os.environ['CONTROLLER'] + + auth = (client_id, client_secret) + data = { + 'grant_type': 'client_credentials', + 'scope': ' '.join(scopes), + } + + url = '{}/token'.format(api) + + print('url', url) + print('auth', auth) + print('data', data) + r = requests.post(url, auth=auth, data=data) + if not r.ok: + sys.exit('Error getting token: %s %s' % (r.status_code, r.text)) + + token = r.json()['access_token'] + print('token', token) + return token + def unescape(s): t = '' @@ -186,6 +149,12 @@ def get_token(user): def http(V, func, url, **kwargs): + V['request'] = { + 'func': repr(func), + 'url': url, + 'kwargs': kwargs, + } + print('http', func, url, kwargs) status, content_type, headers, body = func(url, **kwargs) V['status_code'] = status V['content_type'] = content_type @@ -201,6 +170,11 @@ def get(url, token): return r.status_code, r.headers['Content-Type'], dict(r.headers), r.text +def get_version(url): + status, ctype, headers, text = get(url + '/version', 'no token') + assert ctype == 'application/json' + return json.loads(text) + def get_blob(url, token): headers = { 'Authorization': 'Bearer {}'.format(token), @@ -309,5 +283,15 @@ def list_diff(a, b): return None -def encode_basename(basename): - return urllib.quote(basename, safe='') +def expand_vars(text, variables): + result = '' + while text: + m = re.search(r'\${(?P[^}]+)}', text) + if not m: + result += text + break + name = m.group('name') + print('expanding ', name) + result += text[:m.start()] + variables[name] + text = text[m.end():] + return result -- cgit v1.2.1