def vmaction(): """ start/stop/delete/create vm """ config = Kconfig() k = config.k if 'name' in request.form: name = request.form['name'] action = request.form['action'] if action == 'start': result = k.start(name) elif action == 'stop': result = k.stop(name) elif action == 'delete': result = k.delete(name) elif action == 'create' and 'profile' in request.form: profile = request.form['profile'] result = config.create_vm(name, profile) else: result = "Nothing to do" print(result) response = jsonify(result) print(response) response.status_code = 200 return response else: failure = {'result': 'failure', 'reason': "Invalid Data"} response = jsonify(failure) response.status_code = 400 return jsonify(failure)
def process_vm(name, namespace, spec, operation='create', timeout=60): config = Kconfig(quiet=True) exists = config.k.exists(name) if operation == "delete" and exists: print("Deleting vm %s" % name) return config.k.delete(name) if operation == "create": if not exists: profile = spec.get("profile") if profile is None: if 'image' in spec: profile = spec['image'] else: profile = name print("Creating vm %s" % name) if profile is not None: result = config.create_vm(name, profile, overrides=spec) if result['result'] != 'success': return result info = config.k.info(name) image = info.get('image') if image is not None and 'ip' not in info: raise kopf.TemporaryError("Waiting to populate ip", delay=10) newspec = {'spec': {'info': info}} return update_vm_cr(name, namespace, newspec)
def main(): """ """ argument_spec = { "state": { "default": "present", "choices": ['present', 'absent'], "type": 'str' }, "name": {"required": True, "type": "str"}, "client": {"required": False, "type": "str"}, "image": {"required": False, "type": "str"}, "profile": {"required": False, "type": "str"}, "parameters": {"required": False, "type": "dict"}, } module = AnsibleModule(argument_spec=argument_spec) client = module.params['client'] config = Kconfig(client=client, quiet=True) k = config.k name = module.params['name'] exists = k.exists(name) state = module.params['state'] if state == 'present': if exists: changed = False skipped = True meta = {'result': 'skipped'} else: image = module.params['image'] profile = module.params['profile'] if image is not None: profile = image elif profile is None: # module.fail_json(msg='profile or image needs to be specified', changed=False) profile = 'kvirt' config.profiles[profile] = {} overrides = module.params['parameters'] if module.params['parameters'] is not None else {} meta = config.create_vm(name, profile, overrides=overrides) changed = True skipped = False else: if exists: meta = k.delete(name) changed = True skipped = False else: changed = False skipped = True meta = {'result': 'skipped'} module.exit_json(changed=changed, skipped=skipped, meta=meta)
def vmaction(): """ start/stop/delete/create vm """ config = Kconfig() k = config.k if 'name' in request.form: name = request.form['name'] action = request.form['action'] if action not in ['start', 'stop', 'delete', 'create']: result = {'result': 'failure', 'reason': "Invalid Action"} response = jsonify(result) response.status_code = 400 else: if action == 'start': result = k.start(name) elif action == 'stop': result = k.stop(name) elif action == 'delete': result = k.delete(name) elif action == 'create' and 'profile' in request.form: profile = request.form['profile'] parameters = {} for p in request.form: if p.startswith('parameters'): value = request.form[p] key = p.replace('parameters[', '').replace(']', '') parameters[key] = value parameters['nets'] = parameters['nets'].split(',') parameters['disks'] = [ int(disk) for disk in parameters['disks'].split(',') ] if name == '': name = nameutils.get_random_name() result = config.create_vm(name, profile, overrides=parameters) response = jsonify(result) response.status_code = 200 else: result = {'result': 'failure', 'reason': "Invalid Data"} response = jsonify(result) response.status_code = 400 return jsonify(result)
def create_vm(self, request, context): print("Handling create_vm call for:\n%s" % request) config = Kconfig() overrides = ast.literal_eval( request.overrides) if request.overrides != '' else {} profile = request.profile customprofile = ast.literal_eval( request.customprofile) if request.customprofile != '' else {} name = request.name if name == '': name = nameutils.get_random_name() if config.type in ['gcp', 'kubevirt']: name = name.replace('_', '-') if config.type != 'aws': common.pprint("Using %s as name of the vm" % name) if request.image != '': if request.image in config.profiles: common.pprint("Using %s as profile" % request.image) profile = request.image elif profile is not None: if profile.endswith('.yml'): profilefile = profile profile = None if not os.path.exists(profilefile): common.pprint("Missing profile file %s" % profilefile, color='red') result = { 'result': 'failure', 'reason': "Missing profile file %s" % profilefile } response = kcli_pb2.result(**result) return response else: with open(profilefile, 'r') as entries: entries = yaml.safe_load(entries) entrieskeys = list(entries.keys()) if len(entrieskeys) == 1: profile = entrieskeys[0] customprofile = entries[profile] common.pprint("Using data from %s as profile" % profilefile, color='blue') else: common.pprint("Cant' parse %s as profile file" % profilefile, color='red') result = { 'result': 'failure', 'reason': "Missing profile file %s" % profilefile } response = kcli_pb2.result(**result) return response elif overrides: profile = 'kvirt' config.profiles[profile] = {} else: common.pprint( "You need to either provide a profile, an image or some parameters", color='red') result = { 'result': 'failure', 'reason': "You need to either provide a profile, an image or some parameters" } response = kcli_pb2.result(**result) response = kcli_pb2.result(**result) return response if request.vmfiles: for _fil in request.vmfiles: origin = _fil.origin content = _fil.content with open(origin, 'w') as f: f.write(content) if request.ignitionfile != '': with open("%s.ign" % name, 'w') as f: f.write(request.ignitionfile) result = config.create_vm(name, profile, overrides=overrides, customprofile=customprofile) result['vm'] = name response = kcli_pb2.result(**result) return response
def create(args): paramfile = args.paramfile if not os.path.exists( '/i_am_a_container') else '/workdir/%s' % args.paramfile config = Kconfig() k = config.k client = config.client platform = config.type pprint("Deploying on client %s" % client, color='blue') envname = paramfile if paramfile is not None else 'testk' if not os.path.exists(paramfile): pprint("Specified parameter file %s doesn't exist.Leaving..." % real_path(paramfile), color='red') sys.exit(1) with open(paramfile) as entries: paramdata = yaml.safe_load(entries) data = { 'cluster': envname, 'helper_image': 'CentOS-7-x86_64-GenericCloud.qcow2', 'domain': 'karmalabs.com', 'network': 'default', 'masters': 1, 'workers': 0, 'tag': 'cnvlab', 'pub_key': '%s/.ssh/id_rsa.pub' % os.environ['HOME'], 'pull_secret': 'openshift_pull.json', 'version': 'nightly', 'macosx': False, 'baremetal': False, 'network_type': 'OpenShiftSDN' } data.update(paramdata) version = data.get('version') if version not in ['ci', 'nightly', 'upstream']: pprint("Using stable version", color='blue') else: pprint("Using %s version" % version, color='blue') cluster = data.get('cluster') helper_image = data.get('helper_image') image = data.get('image') api_ip = data.get('api_ip') public_api_ip = data.get('public_api_ip') bootstrap_api_ip = data.get('bootstrap_api_ip') domain = data.get('domain') network = data.get('network') masters = data.get('masters') workers = data.get('workers') tag = data.get('tag') pub_key = data.get('pub_key') pull_secret = pwd_path( data.get('pull_secret')) if version != 'upstream' else pwd_path( 'fake_pull.json') macosx = data.get('macosx') baremetal = data.get('baremetal') if macosx and not os.path.exists('/i_am_a_container'): macosx = False if platform == 'openstack' and (api_ip is None or public_api_ip is None): pprint( "You need to define both api_ip and public_api_ip in your parameters file", color='red') os._exit(1) if not os.path.exists(pull_secret): pprint("Missing pull secret file %s" % pull_secret, color='red') sys.exit(1) if not os.path.exists(pub_key): if os.path.exists('/%s/.kcli/id_rsa.pub' % os.environ['HOME']): pub_key = '%s/.kcli/id_rsa.pub' % os.environ['HOME'] else: pprint("Missing public key file %s" % pub_key, color='red') sys.exit(1) clusterdir = pwd_path("clusters/%s" % cluster) if os.path.exists(clusterdir): pprint("Please Remove existing %s first..." % clusterdir, color='red') sys.exit(1) os.environ['KUBECONFIG'] = "%s/auth/kubeconfig" % clusterdir if find_executable('oc') is None: SYSTEM = 'macosx' if os.path.exists('/Users') else 'linux' pprint("Downloading oc in current directory", color='blue') occmd = "curl -s https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/%s/oc.tar.gz" % SYSTEM occmd += "| tar zxf - oc" occmd += "; chmod 700 oc" call(occmd, shell=True) if os.path.exists('/i_am_a_container'): if macosx: occmd = "curl -s https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/maxosx/oc.tar.gz" occmd += "| tar zxf -C /workdir - oc" occmd += "; chmod 700 /workdir/oc" call(occmd, shell=True) else: move('oc', '/workdir/oc') if find_executable('openshift-install') is None: if version == 'ci': get_ci_installer(pull_secret, tag=tag, baremetal=baremetal) elif version == 'nightly': get_installer(nightly=True) elif version == 'upstream': get_upstream_installer() else: get_installer() if not macosx and os.path.exists('/i_am_a_container'): move('openshift-install', '/workdir') INSTALLER_VERSION = os.popen( 'openshift-install version').readlines()[0].split(" ")[1].strip() pprint("Using installer version %s" % INSTALLER_VERSION, color='blue') if version == 'upstream': COS_VERSION = "latest" COS_TYPE = "fcos" else: COS_TYPE = "rhcos" version_match = re.match("v([0-9]*).([0-9]*).*", INSTALLER_VERSION) if version_match is not None: COS_VERSION = "%s%s" % (version_match.group(1), version_match.group(2)) else: COS_VERSION = "rhcos44" if image is None: images = [v for v in k.volumes() if COS_TYPE in v and COS_VERSION in v] if images: image = os.path.basename(images[0]) else: pprint("Downloading %s image" % COS_TYPE, color='blue') result = config.handle_host(pool=config.pool, image="%s%s" % (COS_TYPE, COS_VERSION), download=True, update_profile=False) if result['result'] != 'success': os._exit(1) images = [ v for v in k.volumes() if image.startswith("%s-%s" % (COS_TYPE, COS_VERSION)) ] image = images[0] pprint("Using image %s" % image, color='blue') else: pprint("Checking if image %s is available" % image, color='blue') images = [v for v in k.volumes() if image in v] if not images: pprint( "Missing %s. Indicate correct image in your parameters file..." % image, color='red') os._exit(1) paramdata['image'] = image if not os.path.exists(clusterdir): os.makedirs(clusterdir) data['pub_key'] = open(pub_key).read().strip() data['pull_secret'] = re.sub(r"\s", "", open(pull_secret).read()) installconfig = config.process_inputfile(cluster, "install-config.yaml", overrides=data) with open("%s/install-config.yaml" % clusterdir, 'w') as f: f.write(installconfig) call('openshift-install --dir=%s create manifests' % clusterdir, shell=True) for f in [f for f in glob("customisation/*.yaml")]: if '99-ingress-controller.yaml' in f: ingressrole = 'master' if workers == 0 else 'worker' replicas = masters if workers == 0 else workers installconfig = config.process_inputfile(cluster, f, overrides={ 'replicas': replicas, 'role': ingressrole }) with open("%s/openshift/99-ingress-controller.yaml" % clusterdir, 'w') as f: f.write(installconfig) else: copy2(f, "%s/openshift" % clusterdir) if baremetal: metal3config = config.process_inputfile(cluster, "metal3-config.yaml", overrides=data) pprint("Rendering metal3 config map", color='blue') with open("%s/openshift/metal3-config.yaml" % clusterdir, 'w') as f: f.write(metal3config) call('openshift-install --dir=%s create ignition-configs' % clusterdir, shell=True) staticdata = gather_dhcp(data, platform) if staticdata: pprint("Deploying helper dhcp node" % image, color='green') staticdata.update({ 'network': network, 'dhcp_image': helper_image, 'prefix': cluster, domain: '%s.%s' % (cluster, domain) }) config.plan(cluster, inputfile='dhcp.yml', overrides=staticdata) if platform in virtplatforms: if api_ip is None: pprint("You need to define api_ip in your parameters file", color='red') os._exit(1) host_ip = api_ip if platform != "openstack" else public_api_ip pprint("Using %s for api vip...." % host_ip, color='blue') if not os.path.exists("/i_am_a_container"): hosts = open("/etc/hosts").readlines() wronglines = [ e for e in hosts if not e.startswith('#') and "api.%s.%s" % (cluster, domain) in e and host_ip not in e ] for wrong in wronglines: pprint( "Cleaning duplicate entries for api.%s.%s in /etc/hosts" % (cluster, domain), color='blue') call("sudo sed -i '/api.%s.%s/d' /etc/hosts" % (cluster, domain), shell=True) hosts = open("/etc/hosts").readlines() correct = [ e for e in hosts if not e.startswith('#') and "api.%s.%s" % (cluster, domain) in e and host_ip in e ] if not correct: entries = [ "%s.%s.%s" % (x, cluster, domain) for x in [ 'api', 'console-openshift-console.apps', 'oauth-openshift.apps', 'prometheus-k8s-openshift-monitoring.apps' ] ] entries = ' '.join(entries) call("sudo sh -c 'echo %s %s >> /etc/hosts'" % (host_ip, entries), shell=True) if os.path.exists('/Users'): if not os.path.exists('/etc/resolver'): os.mkdir('/etc/resolver') if not os.path.exists('/etc/resolver/%s.%s' % (cluster, domain)): pprint("Adding wildcard for apps.%s.%s in /etc/resolver" % (cluster, domain), color='blue') call( "sudo sh -c 'echo nameserver %s > /etc/resolver/%s.%s'" % (api_ip, cluster, domain), shell=True) else: resolverlines = open("/etc/resolver/%s.%s" % (cluster, domain)).readlines() correct = [e for e in resolverlines if api_ip not in e] if not correct: pprint( "Adding wildcard for apps.%s.%s in /etc/resolver" % (cluster, domain), color='blue') call( "sudo sh -c 'echo nameserver %s > /etc/resolver/%s.%s'" % (api_ip, cluster, domain), shell=True) elif not os.path.exists( "/etc/NetworkManager/dnsmasq.d/%s.%s.conf" % (cluster, domain)): pprint("Adding wildcard for apps.%s.%s in /etc/resolver" % (cluster, domain), color='blue') nm = "sudo sh -c '" nm += "echo server=/apps.%s.%s/%s > /etc/NetworkManager/dnsmasq.d/%s.%s.conf'" % ( cluster, domain, api_ip, cluster, domain) nm += ";sudo systemctl reload NetworkManager" call(nm, shell=True) else: nmfile = open("/etc/NetworkManager/dnsmasq.d/%s.%s.conf" % (cluster, domain)).readlines() correct = [e for e in nmfile if host_ip in e] if not correct: pprint("Adding wildcard for apps.%s.%s in /etc/resolver" % (cluster, domain), color='blue') nm = "sudo sh -c '" nm += "echo server=/apps.%s.%s/%s > /etc/NetworkManager/dnsmasq.d/%s.%s.conf'" % ( cluster, domain, api_ip, cluster, domain) nm += ";sudo systemctl reload NetworkManager" call(nm, shell=True) else: entries = [ "%s.%s.%s" % (x, cluster, domain) for x in [ 'api', 'console-openshift-console.apps', 'oauth-openshift.apps', 'prometheus-k8s-openshift-monitoring.apps' ] ] entries = ' '.join(entries) call("sh -c 'echo %s %s >> /etc/hosts'" % (host_ip, entries), shell=True) if os.path.exists('/etcdir/hosts'): call("sh -c 'echo %s %s >> /etcdir/hosts'" % (host_ip, entries), shell=True) if platform in ['kubevirt', 'openstack', 'vsphere']: # bootstrap ignition is too big for kubevirt/openstack/vsphere so we deploy a temporary web server overrides = {} if platform == 'kubevirt': overrides[ 'helper_image'] = "kubevirt/fedora-cloud-container-disk-demo" iptype = "ip" else: if helper_image is None: images = [ v for v in k.volumes() if 'centos' in v.lower() or 'fedora' in v.lower() ] if images: image = os.path.basename(images[0]) else: helper_image = "CentOS-7-x86_64-GenericCloud.qcow2" pprint("Downloading centos helper image", color='blue') result = config.handle_host(pool=config.pool, image="centos7", download=True, update_profile=False) pprint("Using helper image %s" % helper_image, color='blue') else: images = [v for v in k.volumes() if helper_image in v] if not images: pprint( "Missing image %s. Indicate correct helper image in your parameters file" % helper_image, color='red') os._exit(1) iptype = 'ip' if platform == 'openstack': overrides['flavor'] = "m1.medium" iptype = "privateip" overrides['nets'] = [network] overrides['plan'] = cluster bootstrap_helper_name = "%s-bootstrap-helper" % cluster config.create_vm("%s-bootstrap-helper" % cluster, helper_image, overrides=overrides) while bootstrap_api_ip is None: bootstrap_api_ip = k.info(bootstrap_helper_name).get(iptype) pprint("Waiting 5s for bootstrap helper node to be running...", color='blue') sleep(5) sleep(5) cmd = "iptables -F ; yum -y install httpd ; systemctl start httpd" sshcmd = k.ssh(bootstrap_helper_name, user='******', tunnel=config.tunnel, insecure=True, cmd=cmd) os.system(sshcmd) source, destination = "%s/bootstrap.ign" % clusterdir, "/var/www/html/bootstrap" scpcmd = k.scp(bootstrap_helper_name, user='******', source=source, destination=destination, tunnel=config.tunnel, download=False, insecure=True) os.system(scpcmd) sedcmd = 'sed "s@https://api-int.%s.%s:22623/config/master@http://%s/bootstrap@" ' % ( cluster, domain, bootstrap_api_ip) sedcmd += '%s/master.ign' % clusterdir sedcmd += ' > %s/bootstrap.ign' % clusterdir call(sedcmd, shell=True) sedcmd = 'sed -i "s@https://api-int.%s.%s:22623/config@http://%s:8080@"' % ( cluster, domain, api_ip) sedcmd += ' %s/master.ign %s/worker.ign' % (clusterdir, clusterdir) call(sedcmd, shell=True) if platform in cloudplatforms: bootstrap_helper_name = "%s-bootstrap-helper" % cluster overrides = { 'reservedns': True, 'domain': '%s.%s' % (cluster, domain), 'tags': [tag], 'plan': cluster, 'nets': [network] } config.create_vm("%s-bootstrap-helper" % cluster, helper_image, overrides=overrides) status = "" while status != "running": status = k.info(bootstrap_helper_name).get('status') pprint("Waiting 5s for bootstrap helper node to be running...", color='blue') sleep(5) sleep(5) cmd = "iptables -F ; yum -y install httpd ; systemctl start httpd" sshcmd = k.ssh(bootstrap_helper_name, user='******', tunnel=config.tunnel, insecure=True, cmd=cmd) os.system(sshcmd) source, destination = "%s/bootstrap.ign" % clusterdir, "/var/www/html/bootstrap" scpcmd = k.scp(bootstrap_helper_name, user='******', source=source, destination=destination, tunnel=config.tunnel, download=False, insecure=True) os.system(scpcmd) sedcmd = 'sed "s@https://api-int.%s.%s:22623/config/master@' % ( cluster, domain) sedcmd += 'http://%s-bootstrap-helper.%s.%s/bootstrap@ "' % (cluster, domain) sedcmd += '%s/master.ign' % clusterdir sedcmd += ' > %s/bootstrap.ign' % clusterdir call(sedcmd, shell=True) if platform in virtplatforms: config.plan(cluster, inputfile='ocp.yml', overrides=paramdata) call('openshift-install --dir=%s wait-for bootstrap-complete || exit 1' % clusterdir, shell=True) todelete = ["%s-bootstrap" % cluster] if platform in ['kubevirt', 'openstack', 'vsphere']: todelete.append("%s-bootstrap-helper" % cluster) for vm in todelete: pprint("Deleting %s" % vm) k.delete(vm) else: config.plan(cluster, inputfile='ocp_cloud.yml', overrides=paramdata) call('openshift-install --dir=%s wait-for bootstrap-complete || exit 1' % clusterdir, shell=True) todelete = ["%s-bootstrap" % cluster, "%s-bootstrap-helper" % cluster] for vm in todelete: pprint("Deleting %s" % vm) k.delete(vm) if workers == 0: call( "oc adm taint nodes -l node-role.kubernetes.io/master node-role.kubernetes.io/master:NoSchedule-", shell=True) pprint("Deploying certs autoapprover cronjob", color='blue') call("oc create -f autoapprovercron.yml", shell=True) installcommand = 'openshift-install --dir=%s wait-for install-complete' % clusterdir installcommand = "%s | %s" % (installcommand, installcommand) pprint( "Launching install-complete step. Note it will be retried one extra time in case of timeouts", color='blue') call(installcommand, shell=True) if platform in virtplatforms: copy2("%s/worker.ign" % clusterdir, "%s/worker.ign.ori" % clusterdir) with open("%s/worker.ign" % clusterdir, 'w') as w: workerdata = insecure_fetch( "https://api.%s.%s:22623/config/worker" % (cluster, domain)) w.write(str(workerdata)) extrasdir = pwd_path("extras") if os.path.exists(extrasdir): pprint("Deploying extras", color='blue') os.chdir(extrasdir) for entry in sorted(os.listdir('.')): if os.path.isfile(entry) and entry.endswith('sh'): call("bash %s" % entry, shell=True)