#!/usr/bin/env python3 # pvcbootstrapd.py - PVC Cluster Auto-bootstrap # Part of the Parallel Virtual Cluster (PVC) system # # Copyright (C) 2018-2021 Joshua M. Boniface # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ############################################################################### import flask import json from pvcbootstrapd.Daemon import config, API_VERSION import pvcbootstrapd.lib.dnsmasq as dnsmasq import pvcbootstrapd.lib.lib as lib import pvcbootstrapd.lib.db as db import pvcbootstrapd.lib.git as git import pvcbootstrapd.lib.ansible as ansible from time import sleep from threading import Thread, Event from dataclasses import dataclass from flask_restful import Resource, Api, abort from celery import Celery from celery.utils.log import get_task_logger logger = get_task_logger(__name__) # Create Flask app and set config values app = flask.Flask(__name__) blueprint = flask.Blueprint('api', __name__, url_prefix='') api = Api(blueprint) app.register_blueprint(blueprint) app.config["CELERY_BROKER_URL"] = f"redis://{config['queue_address']}:{config['queue_port']}{config['queue_path']}" celery = Celery(app.name, broker=app.config["CELERY_BROKER_URL"]) celery.conf.update(app.config) # # Celery functions # @celery.task(bind=True) def dnsmasq_checkin(self, data): lib.dnsmasq_checkin(config, data) @celery.task(bind=True) def host_checkin(self, data): lib.host_checkin(config, data) # # API routes # class API_Root(Resource): def get(self): """ Return basic details of the API --- tags: - root responses: 200: description: OK schema: type: object id: Message properties: message: type: string description: A text message describing the result example: "The foo was successfully maxed" """ return { "message": "pvcbootstrapd API" }, 200 api.add_resource(API_Root, '/') class API_Checkin(Resource): def get(self): """ Return checkin details of the API --- tags: - checkin responses: 200: description: OK schema: type: object id: Message """ return { "message": "pvcbootstrapd API Checkin interface" }, 200 api.add_resource(API_Checkin, '/checkin') class API_Checkin_DNSMasq(Resource): def post(self): """ Register a checkin from the DNSMasq subsystem --- tags: - checkin consumes: - application/json parameters: - in: body name: dnsmasq_checkin_event description: An event checkin from an external bootstrap tool component. schema: type: object required: - action properties: action: type: string description: The action of the event. example: "add" macaddr: type: string description: (add, old) The MAC address from a DHCP request. example: "ff:ff:ff:ab:cd:ef" ipaddr: type: string description: (add, old) The IP address from a DHCP request. example: "10.199.199.10" hostname: type: string description: (add, old) The client hostname from a DHCP request. example: "pvc-installer-live" client_id: type: string description: (add, old) The client ID from a DHCP request. example: "01:ff:ff:ff:ab:cd:ef" vendor_class: type: string description: (add, old) The DHCP vendor-class option from a DHCP request. example: "CPQRIB3 (HP Proliant DL360 G6 iLO)" user_class: type: string description: (add, old) The DHCP user-class option from a DHCP request. example: None responses: 200: description: OK schema: type: object id: Message """ try: data = json.loads(flask.request.data) except Exception as e: logger.warn(e) data = { 'action': None } logger.info(f"Handling DNSMasq checkin for: {data}") task = dnsmasq_checkin.delay(data) return { "message": "received checkin from DNSMasq" }, 200 api.add_resource(API_Checkin_DNSMasq, '/checkin/dnsmasq') class API_Checkin_Host(Resource): def post(self): """ Register a checkin from the Host subsystem --- tags: - checkin consumes: - application/json parameters: - in: body name: host_checkin_event description: An event checkin from an external bootstrap tool component. schema: type: object required: - action properties: action: type: string description: The action of the event. example: "begin" hostname: type: string description: The system hostname. example: "hv1.mydomain.tld" host_macaddr: type: string description: The MAC address of the system provisioning interface. example: "ff:ff:ff:ab:cd:ef" host_ipaddr: type: string description: The IP address of the system provisioning interface. example: "10.199.199.11" bmc_macaddr: type: string description: The MAC address of the system BMC interface. example: "ff:ff:ff:01:23:45" bmc_ipaddr: type: string description: The IP addres of the system BMC interface. example: "10.199.199.10" responses: 200: description: OK schema: type: object id: Message """ try: data = json.loads(flask.request.data) except Exception as e: data = { 'action': None } logger.info(f"Handling Host checkin for: {data}") task = host_checkin.delay(data) return { "message": "received checkin from Host" }, 200 api.add_resource(API_Checkin_Host, '/checkin/host')