242 lines
7.1 KiB
Python
242 lines
7.1 KiB
Python
|
#!/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 <joshua@boniface.me>
|
||
|
#
|
||
|
# 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 <https://www.gnu.org/licenses/>.
|
||
|
#
|
||
|
###############################################################################
|
||
|
|
||
|
import flask
|
||
|
import json
|
||
|
|
||
|
from pvcbootstrapd.Daemon import config
|
||
|
|
||
|
import pvcbootstrapd.lib.lib as lib
|
||
|
|
||
|
from flask_restful import Resource, Api
|
||
|
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)
|
||
|
logger.debug(task)
|
||
|
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:
|
||
|
logger.warning(f"Invalid JSON data, setting action to None: {e}")
|
||
|
data = {"action": None}
|
||
|
logger.info(f"Handling Host checkin for: {data}")
|
||
|
|
||
|
task = host_checkin.delay(data)
|
||
|
logger.debug(task)
|
||
|
return {"message": "received checkin from Host"}, 200
|
||
|
|
||
|
|
||
|
api.add_resource(API_Checkin_Host, "/checkin/host")
|