Skip to content
Snippets Groups Projects
Commit 7b40e942 authored by Erik Reid's avatar Erik Reid
Browse files

failed draft using wso product block

parent d5214a8a
No related branches found
No related tags found
1 merge request!9Feature/nat 146 device endpoint skeleton
...@@ -19,12 +19,12 @@ def playbook_launch_error(reason: str) -> PlaybookLaunchResponse: ...@@ -19,12 +19,12 @@ def playbook_launch_error(reason: str) -> PlaybookLaunchResponse:
return PlaybookLaunchResponse(status='ERROR', info=reason) return PlaybookLaunchResponse(status='ERROR', info=reason)
# TODO: add callback logic
def _run_playbook_proc( def _run_playbook_proc(
playbook: str, playbook: str,
extra_vars: dict, extra_vars: dict,
inventory: str, inventory: str,
private_data_dir: str = '/opt/geant-gap-ansible', # TODO callback: str,
private_data_dir: str = '/opt/geant-gap-ansible', # TODO???
): ):
r = ansible_runner.run( r = ansible_runner.run(
private_data_dir=private_data_dir, private_data_dir=private_data_dir,
...@@ -32,19 +32,23 @@ def _run_playbook_proc( ...@@ -32,19 +32,23 @@ def _run_playbook_proc(
inventory=inventory, inventory=inventory,
extravars=extra_vars) extravars=extra_vars)
return {"dry_run_output": r.stdout.read().splitlines(), "return_code": r.rc} # TODO: add callback logic
output = r.stdout.read().splitlines()
return_code = r.rc
def run_playbook( def run_playbook(
playbook: str, playbook: str,
extra_vars: dict, extra_vars: dict,
inventory: str) -> PlaybookLaunchResponse: inventory: str,
callback: str) -> PlaybookLaunchResponse:
t = threading.Thread( t = threading.Thread(
target=_run_playbook_proc, target=_run_playbook_proc,
kwargs={ kwargs={
'playbook': playbook, 'playbook': playbook,
'inventory': inventory, 'inventory': inventory,
'extra_vars': extra_vars 'extra_vars': extra_vars,
'callback': callback
}) })
t.start() t.start()
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Routes for handling device/base_config-related requests Routes for handling device/base_config-related requests
""" """
from fastapi import APIRouter from fastapi import APIRouter
from fastapi.responses import JSONResponse import pydantic
from lso.routes import common from lso.routes import common
from gso.products.product_types.device import DeviceBlockProvisioning from gso.products.product_types.device import DeviceBlockProvisioning
...@@ -10,26 +10,36 @@ from gso.products.product_types.device import DeviceBlockProvisioning ...@@ -10,26 +10,36 @@ from gso.products.product_types.device import DeviceBlockProvisioning
router = APIRouter() router = APIRouter()
class NodeProvisioningParams(pydantic.BaseModel):
# TODO: define and document callback spec
callback: pydantic.HttpUrl
data: DeviceBlockProvisioning
@router.post('/') @router.post('/')
async def provision_node(device: DeviceBlockProvisioning) -> JSONResponse: async def provision_node(params: NodeProvisioningParams) \
-> common.PlaybookLaunchResponse:
""" """
runs the base_config playbook Launches a playbook to provision a new node.
The response will contain either a job id or error information.
:return: A `JSONResponse` that will report on successful executing of a :param device: NodeProvisioningParams
:return: PlaybookLaunchResponse
""" """
device = params.data.device
extra_vars = { extra_vars = {
'lo_ipv4_address': str(device.device.lo_ipv4_address), 'lo_ipv4_address': str(device.lo_ipv4_address),
'lo_ipv6_address': str(device.device.lo_ipv6_address), 'lo_ipv6_address': str(device.lo_ipv6_address),
'lo_iso_address': device.device.lo_iso_address, 'lo_iso_address': device.lo_iso_address,
'snmp_location': device.device.snmp_location, 'snmp_location': device.snmp_location,
'si_ipv4_network': str(device.device.si_ipv4_network), 'si_ipv4_network': str(device.si_ipv4_network),
'lt_ipv4_network': str(device.device.ias_lt_ipv4_network), 'lt_ipv4_network': str(device.ias_lt_ipv4_network),
'lt_ipv6_network': str(device.device.ias_lt_ipv6_network), 'lt_ipv6_network': str(device.ias_lt_ipv6_network),
'site_country_code': device.device.site_country_code, 'site_country_code': device.site_country_code,
'verb': 'deploy'} 'verb': 'deploy'}
return common.run_playbook( return common.run_playbook(
playbook = 'base_config.yaml', # TODO: config playbook='base_config.yaml',
inventory = device.device.fqdn, inventory=device.fqdn,
extra_vars = extra_vars) extra_vars=extra_vars,
callback=params.callback)
...@@ -66,8 +66,9 @@ def temp_ansible_env(): ...@@ -66,8 +66,9 @@ def temp_ansible_env():
@pytest.fixture @pytest.fixture
def good_config_data(): def config_data():
"""Example of correct data used for testing """
valid config data used to start the server
""" """
return { return {
'collection': { 'collection': {
...@@ -78,44 +79,23 @@ def good_config_data(): ...@@ -78,44 +79,23 @@ def good_config_data():
@pytest.fixture @pytest.fixture
def bad_config_data(): def config_file(config_data):
"""Example of incorrect data used for testing
""" """
return { Fixture that yields a filename that contains a valid configuration
'bogus-key': 'nothing useful'
}
@pytest.fixture
def config_file(good_config_data):
"""Fixture that yields a filename that contains a valid configuration
:return: Path to valid configuration file :return: Path to valid configuration file
""" """
with tempfile.NamedTemporaryFile(mode='w') as file: with tempfile.NamedTemporaryFile(mode='w') as file:
file.write(json.dumps(good_config_data)) file.write(json.dumps(config_data))
file.flush() file.flush()
os.environ['SETTINGS_FILENAME'] = file.name
yield file.name
@pytest.fixture
def invalid_config_file(bad_config_data):
"""Fixture that yields a filename that contains invalid configuration
:return: Path to invalid configuration file
"""
with tempfile.NamedTemporaryFile(mode='w') as file:
file.write(json.dumps(bad_config_data))
file.flush()
os.environ['SETTINGS_FILENAME'] = file.name
yield file.name yield file.name
@pytest.fixture @pytest.fixture
def client(config_file): def client(config_file):
"""Fixture that yields an instance of LSO
""" """
os.environ['SETTINGS_FILE'] = config_file returns a client that can be used to test the server
"""
os.environ['SETTINGS_FILENAME'] = config_file
app = lso.create_app() app = lso.create_app()
yield TestClient(app) # wait here until calling context ends yield TestClient(app) # wait here until calling context ends
import jsonschema
from lso.routes.device import NodeProvisioningParams
from lso.routes.common import PlaybookLaunchResponse
def test_nominal_node_provisioning(client):
params = {
'callback': 'http://fqdn:12345',
'data': {
'device': {
'fqdn': 'test.example.com',
'lo_ipv4_address': '1.2.3.4',
'lo_ipv6_address': '2001:db8::1',
'lo_iso_address': '1.2.3.4.5.6',
'snmp_location': 'city,country[1.2,3.4]',
'si_ipv4_network': '1.2.3.0/24',
'ias_lt_ipv4_network': '1.2.3.0/24',
'ias_lt_ipv6_network': '2001:db8::/64',
'site_country_code': 'FR'
}
}
}
rv = client.post(f'/api/device', json=params)
assert rv.status_code == 200
response = rv.json()
jsonschema.validate(response, PlaybookLaunchResponse.schema())
assert response['status'] == 'OK'
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment