Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"validate-connection-info": {
"valid": false,
"message": "Unable to establish connection to http://openstack.awesome.our:5000/v3/auth/tokens: HTTPConnectionPool(host='openstack.awesome.our', port=5000): Max retries exceeded with url: /v3/auth/tokens (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f54631feeb8>: Failed to establish a new connection: [Errno -2] No address found',))"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"validate-connection-info": {
"platform": "openstack",
"connection_info": {
"identity_api_version": 3,
"auth_url": "http://openstack.awesome.our:5000/v3",
"username": "admin",
"password": "Passw0rd",
"project_name": "admin",
"user_domain_name": "default",
"project_domain_name": "default",
"allow_untrusted": true
},
"mapped_regions": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"validate-connection-info": {
"valid": true,
"message": null
}
}
47 changes: 47 additions & 0 deletions coriolis/api-refs/source/endpoint.inc
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,53 @@ Response
.. literalinclude:: ../api_samples/endpoint/endpoint-validate-connection-error-resp.json
:language: javascript

Validate Endpoint Connection Info
=================================

.. rest_method:: POST /endpoints/actions

Validates the given connection info for an endpoint platform. This action does
not depend on an existing endpoint and persists nothing, so it can be used to
validate the connection info of an endpoint before creating or updating it.

Normal response codes: 200

Error response codes: badRequest(400), unauthorized(401), forbidden(403),
itemNotFound(404)

Request
-------

.. rest_parameters:: parameters.yaml

- validate-connection-info : validate_connection_info
- platform : validate_connection_platform
- connection_info : connection_info
- mapped_regions : validate_connection_mapped_regions

**Example of Endpoint Validate Connection Info Request**
.. literalinclude:: ../api_samples/endpoint/endpoint-validate-connection-info-req.json
:language: javascript

Response
--------

.. rest_parameters:: parameters.yaml

- validate-connection-info : validate_connection_info
- valid : valid_connection
- message : validation_message

**Example of Endpoint Validate Connection Info Response**
.. literalinclude:: ../api_samples/endpoint/endpoint-validate-connection-info-resp.json
:language: javascript

.. note:: In case the validation fails, an error message will be returned, as in the example below

**Example of Failed Endpoint Connection Info Validation Response**
.. literalinclude:: ../api_samples/endpoint/endpoint-validate-connection-info-error-resp.json
:language: javascript


Endpoint Minion Pool Options
============================
Expand Down
20 changes: 20 additions & 0 deletions coriolis/api-refs/source/parameters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,26 @@ validate_connection:
in: body
type: object
required: true
validate_connection_info:
description: |
An object that contains the validate connection info action for the
given endpoint connection info.
in: body
type: object
required: true
validate_connection_mapped_regions:
description: |
List of IDs of the Coriolis regions whose workers should be used to
validate the connection. Any worker can be used if omitted.
in: body
type: array
required: false
validate_connection_platform:
description: |
The type of cloud service platform the connection info is for.
in: body
type: string
required: true
validation_message:
description: |
The error message in case of endpoint validation failure.
Expand Down
33 changes: 33 additions & 0 deletions coriolis/api/v1/endpoint_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from coriolis import exception
from coriolis.api import wsgi as api_wsgi
from coriolis.api.v1 import utils as api_utils
from coriolis.endpoints import api
from coriolis.policies import endpoints as endpoint_policies

Expand All @@ -28,6 +29,38 @@ def _validate_connection(self, req, id, body):
except exception.InvalidParameterValue as ex:
raise exc.HTTPNotFound(explanation=ex.msg)

@api_utils.format_keyerror_message(resource='endpoint', method='validate')
def _validate_connection_info_body(self, body):
connection_info_body = body["validate-connection-info"]
if not isinstance(connection_info_body, dict):
raise exception.InvalidInput(
'The "validate-connection-info" body must be an object '
'containing the "platform" and "connection_info" of the endpoint'
)
platform = connection_info_body["platform"]
connection_info = connection_info_body["connection_info"]
mapped_regions = connection_info_body.get("mapped_regions", [])
return (platform, connection_info, mapped_regions)

@api_wsgi.action('validate-connection-info')
def _validate_connection_info(self, req, body):
context = req.environ['coriolis.context']
context.can(
"%s:validate_connection_info" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

)
platform, connection_info, mapped_regions = self._validate_connection_info_body(
body
)
try:
is_valid, message = self._endpoint_api.validate_connection_info(
context, platform, connection_info, mapped_regions
)
return {"validate-connection-info": {"valid": is_valid, "message": message}}
except exception.NotFound as ex:
raise exc.HTTPNotFound(explanation=ex.msg)
except exception.InvalidParameterValue as ex:
raise exc.HTTPNotFound(explanation=ex.msg)


def create_resource():
return api_wsgi.Resource(EndpointActionsController())
7 changes: 7 additions & 0 deletions coriolis/api/v1/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ def _setup_routes(self, mapper, ext_mgr):
action='action',
conditions={'method': 'POST'},
)
mapper.connect(
'endpoint_collection_actions',
'/{project_id}/endpoints/actions',
controller=self.resources['endpoint_actions'],
action='action',
conditions={'method': 'POST'},
)

self.resources['endpoint_instances'] = endpoint_instances.create_resource()
mapper.resource(
Expand Down
1 change: 1 addition & 0 deletions coriolis/api/v1/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def _build_keyerror_message(resource, method, key):
method_mapping = {
"create": "creation",
"update": "update",
"validate": "validation",
}

if resource == key:
Expand Down
11 changes: 11 additions & 0 deletions coriolis/conductor/rpc/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,17 @@ def get_endpoint_inventory_csv(self, ctxt, endpoint_id, source_environment):
def validate_endpoint_connection(self, ctxt, endpoint_id):
return self._call(ctxt, 'validate_endpoint_connection', endpoint_id=endpoint_id)

def validate_endpoint_connection_info(
self, ctxt, platform, connection_info, mapped_regions=None
):
return self._call(
ctxt,
'validate_endpoint_connection_info',
platform=platform,
connection_info=connection_info,
mapped_regions=mapped_regions,
)

def validate_endpoint_target_environment(self, ctxt, endpoint_id, target_env):
return self._call(
ctxt,
Expand Down
25 changes: 20 additions & 5 deletions coriolis/conductor/rpc/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,16 +725,31 @@ def get_endpoint_inventory_csv(self, ctxt, endpoint_id, source_environment):
def validate_endpoint_connection(self, ctxt, endpoint_id):
endpoint = self.get_endpoint(ctxt, endpoint_id)

return self._validate_endpoint_connection_info(
ctxt,
endpoint.type,
endpoint.connection_info,
[reg.id for reg in endpoint.mapped_regions],
)

def validate_endpoint_connection_info(
self, ctxt, platform, connection_info, mapped_regions=None
):
return self._validate_endpoint_connection_info(
ctxt, platform, connection_info, mapped_regions
)

def _validate_endpoint_connection_info(
self, ctxt, platform, connection_info, mapped_regions=None
):
worker_rpc = self._get_worker_service_rpc_for_specs(
ctxt,
enabled=True,
region_sets=[[reg.id for reg in endpoint.mapped_regions]],
provider_requirements={endpoint.type: [constants.PROVIDER_TYPE_ENDPOINT]},
region_sets=[mapped_regions or []],
provider_requirements={platform: [constants.PROVIDER_TYPE_ENDPOINT]},
)

return worker_rpc.validate_endpoint_connection(
ctxt, endpoint.type, endpoint.connection_info
)
return worker_rpc.validate_endpoint_connection(ctxt, platform, connection_info)

def validate_endpoint_target_environment(self, ctxt, endpoint_id, target_env):
endpoint = self.get_endpoint(ctxt, endpoint_id)
Expand Down
7 changes: 7 additions & 0 deletions coriolis/endpoints/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ def validate_connection(self, ctxt, endpoint_id):
ctxt, endpoint_id
)

def validate_connection_info(
self, ctxt, platform, connection_info, mapped_regions=None
):
return self._rpc_conductor_client.validate_endpoint_connection_info(
ctxt, platform, connection_info, mapped_regions
)

@utils.bad_request_on_error("Invalid destination environment: %s")
def validate_target_environment(self, ctxt, endpoint_id, target_env):
return self._rpc_conductor_client.validate_endpoint_target_environment(
Expand Down
6 changes: 6 additions & 0 deletions coriolis/policies/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ def get_endpoints_policy_label(rule_label):
"Validate endpoint connection info",
[{"path": "/endpoints/{endpoint_id}/actions", "method": "POST"}],
),
policy.DocumentedRuleDefault(
get_endpoints_policy_label('validate_connection_info'),
ENDPOINTS_POLICY_DEFAULT_RULE,
"Validate the given endpoint connection info without an endpoint",
[{"path": "/endpoints/actions", "method": "POST"}],
),
policy.DocumentedRuleDefault(
get_endpoints_policy_label('list_instances'),
ENDPOINTS_POLICY_DEFAULT_RULE,
Expand Down
Loading
Loading