Skip to content

Commit

Permalink
appEndpoint v4 APIs
Browse files Browse the repository at this point in the history
Change-Id: I2a5426097b00a7af812e1e01eba69b4779eff7ff
Reviewed-on: https://review.couchbase.org/c/CapellaRESTAPIs/+/221722
Tested-by: VIPUL BHARDWAJ <vipul.bhardwaj@couchbase.com>
Reviewed-by: VIPUL BHARDWAJ <vipul.bhardwaj@couchbase.com>
  • Loading branch information
vipbhardwaj committed Jan 10, 2025
1 parent ee10d35 commit a8f980c
Show file tree
Hide file tree
Showing 2 changed files with 307 additions and 5 deletions.
297 changes: 297 additions & 0 deletions capella/dedicated/CapellaAPI_v4.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,12 @@ def __init__(self, url, secret, access, bearer_token):

self.index_endpoint = self.cluster_endpoint + "/{}/queryService/indexes"
self.index_build_status_endpoint = self.cluster_endpoint + "/{}/queryService/indexBuildStatus"
self.bulk_index_check_endpoint = self.cluster_endpoint + "/{}/queryService/bulkIndexCheck"

self.app_endpoints_endpoint = self.cluster_appservice_api + "/{}/appEndpoints"
self.app_endpoint_on_off_endpoint = self.app_endpoints_endpoint + "/{}/activationStatus"
self.app_endpoint_resync_endpoint = self.app_endpoints_endpoint + "/{}/resync"
self.import_filter_endpoint = self.app_endpoints_endpoint + "/{}/importFilter"

def create_app_endpoint(
self,
Expand Down Expand Up @@ -397,6 +400,300 @@ def pause_app_endpoint(
appEndpointName), params, headers)
return resp

def fetch_app_endpoint_resync_info(
self,
organizationId,
projectId,
clusterId,
appServiceId,
appEndpointName,
headers=None,
**kwargs):
"""
Fetches the Resync status of the given App Endpoint.
If no resync operation was triggered, the response will say the status is completed with 0 values for other properties.
Args:
organizationId: The ID of the tenant. (UUID)
projectId: ID of the project inside the tenant. (UUID)
clusterId: ID of the cluster inside the project in which the app service is present. (UUID)
appServiceId: ID of the app service for which app endpoint are to be listed. (UUID)
appEndpointName: Name of the App Endpoint to be paused. (string)
headers: Headers to be sent with the API call. (dict)
**kwargs: Do not use this under normal circumstances. This is only to test negative scenarios. (dict)
Returns:
Success : Status Code and response (JSON).
Error : message, hint, code, HttpStatusCode
"""
self.cluster_ops_API_log.info(
"Fetching resync status for appEndpoint: {}, inside appService: "
"{}, linked to cluster: {}, inside project: {}, inside tenant: {}"
.format(appEndpointName, appServiceId, clusterId, projectId,
organizationId))
if kwargs:
params = kwargs
else:
params = None

resp = self.api_get(self.app_endpoint_resync_endpoint.format(
organizationId, projectId, clusterId, appServiceId,
appEndpointName), params, headers)
return resp

def start_resync(
self,
organizationId,
projectId,
clusterId,
appServiceId,
appEndpointName,
scopes,
headers=None,
**kwargs):
"""
Initialises the Resync operation for the given collections.
By default, all collections that require resync will be resynced unless they are specified in the scopes property, in which case only the specified collections that require resync will be resynced.
Args:
organizationId: The ID of the tenant. (UUID)
projectId: ID of the project inside the tenant. (UUID)
clusterId: ID of the cluster inside the project in which the app service is present. (UUID)
appServiceId: ID of the app service for which app endpoint are to be listed. (UUID)
appEndpointName: Name of the App Endpoint to be paused. (string)
scopes: The scopes that need to be included in the resync operation. (obj: map[string]{}interface)
headers: Headers to be sent with the API call. (dict)
**kwargs: Do not use this under normal circumstances. This is only to test negative scenarios. (dict)
Returns:
Success : Status Code and response (JSON).
Error : message, hint, code, HttpStatusCode
"""
self.cluster_ops_API_log.info(
"Starting resync for appEndpoint: {}, inside appService: {}, "
"linked to cluster: {}, inside project: {}, inside tenant: {}"
.format(appEndpointName, appServiceId, clusterId, projectId,
organizationId))
params = {
"scopes": scopes,
}
for k, v in kwargs.items():
params[k] = v

resp = self.api_post(self.app_endpoint_resync_endpoint.format(
organizationId, projectId, clusterId, appServiceId,
appEndpointName), params, headers)
return resp

def stop_resync(
self,
organizationId,
projectId,
clusterId,
appServiceId,
appEndpointName,
headers=None,
**kwargs):
"""
Stops the Resync operation. When stopping resync, it will be stopped for all collections being processed.
Args:
organizationId: The ID of the tenant. (UUID)
projectId: ID of the project inside the tenant. (UUID)
clusterId: ID of the cluster inside the project in which the app service is present. (UUID)
appServiceId: ID of the app service for which app endpoint are to be listed. (UUID)
appEndpointName: Name of the App Endpoint to be paused. (string)
headers: Headers to be sent with the API call. (dict)
**kwargs: Do not use this under normal circumstances. This is only to test negative scenarios. (dict)
Returns:
Success : Status Code and response (JSON).
Error : message, hint, code, HttpStatusCode
"""
self.cluster_ops_API_log.info(
"Stopping resync for appEndpoint: {}, inside appService: {}, "
"linked to cluster: {}, inside project: {}, inside tenant: {}"
.format(appEndpointName, appServiceId, clusterId, projectId,
organizationId))
if kwargs:
params = kwargs
else:
params = None

resp = self.api_del(self.app_endpoint_resync_endpoint.format(
organizationId, projectId, clusterId, appServiceId,
appEndpointName), params, headers)
return resp

def fetch_import_filter_info(
self,
organizationId,
projectId,
clusterId,
appServiceId,
appEndpointKeyspace,
headers=None,
**kwargs):
"""
Retrieves the Import Filter for the given keyspace.
Args:
organizationId: The tenant ID for the path. (UUID)
projectId: ID of the project inside the tenant. (UUID)
clusterId: ID of the cluster which has the app service inside it. (UUID)
appServiceId: ID of the app service linked to the cluster. (UUID)
appEndpointKeyspace:
headers:
**kwargs:
Returns:
Success : Status Code and response (JSON).
Error : message, hint, code, HttpStatusCode
"""
self.cluster_ops_API_log.info(
"Fetching the importFilter info in appEndpointKeyspace: {} in "
"appService: {} in cluster: {} in project: {} in tenant: {}"
.format(appEndpointKeyspace, appServiceId, clusterId, projectId,
organizationId))

if kwargs:
params = kwargs
else:
params = None

resp = self.api_get(self.import_filter_endpoint.format(
organizationId, projectId, clusterId, appServiceId,
appEndpointKeyspace), params, headers)
return resp

def delete_import_filter(
self,
organizationId,
projectId,
clusterId,
appServiceId,
appEndpointKeyspace,
headers=None,
**kwargs):
"""
Retrieves the Import Filter for the given keyspace.
Args:
organizationId: The tenant ID for the path. (UUID)
projectId: ID of the project inside the tenant. (UUID)
clusterId: ID of the cluster which has the app service inside it. (UUID)
appServiceId: ID of the app service linked to the cluster. (UUID)
appEndpointKeyspace:
headers: Headers to be sent with the API call. (dict)
**kwargs: Do not use this under normal circumstances. This is only to test negative scenarios. (dict)
Returns:
Success : Status Code and response (JSON).
Error : message, hint, code, HttpStatusCode
"""

self.cluster_ops_API_log.info(
"Deleting the importFilter for appEndpointKeyspace: {} in "
"appService: {} in cluster:{} in project: {} in tenant: {}"
.format(appEndpointKeyspace, appServiceId, clusterId, projectId,
organizationId))

if kwargs:
params = kwargs
else:
params = None

resp = self.api_del(self.import_filter_endpoint.format(
organizationId, projectId, clusterId, appServiceId,
appEndpointKeyspace), params, headers)
return resp

def update_import_filter(
self,
organizationId,
projectId,
clusterId,
appServiceId,
appEndpointKeyspace,
headers=None,
**kwargs):
"""
Updates the Import Filter for the given keyspace.
By default, there is no import filter and all documents are imported.
Import Filters identify the subset of documents eligible to be replicated by App services based on user-defined requirements.
This subset is applied to all future mutations.
Once the document has been imported and processed by the App Endpoint, changing the Import Filter will not remove it, even if the updated import filters would prevent newer mutations or iterations of the document from getting imported.
Args:
organizationId: The tenant ID for the path. (UUID)
projectId: ID of the project inside the tenant. (UUID)
clusterId: ID of the cluster which has the app service inside it. (UUID)
appServiceId: ID of the app service linked to the cluster. (UUID)
appEndpointKeyspace:
headers: Headers to be sent with the API call. (dict)
**kwargs: Do not use this under normal circumstances. This is only to test negative scenarios. (dict)
Returns:
Success : Status Code and response (JSON).
Error : message, hint, code, HttpStatusCode
"""
self.cluster_ops_API_log.info(
"Updating the importFilter in appEndpointKeyspace: {} in "
"appService: {} in cluster: {} in project: {} in tenant: {}"
.format(appEndpointKeyspace, appServiceId, clusterId, projectId,
organizationId))

if kwargs:
params = kwargs
else:
params = None

resp = self.api_put(self.import_filter_endpoint.format(
organizationId, projectId, clusterId, appServiceId,
appEndpointKeyspace), None, headers, params)
return resp

def bulk_index_check(
self,
organizationId,
projectId,
clusterId,
state,
indexes,
headers=None,
**kwargs):
"""
Monitor the build status of a list of indexes. It returns the number of indexes in the desired state.
Args:
organizationId: The ID of the tenant. (UUID)
projectId: ID of the project inside the tenant. (UUID)
clusterId: ID of the cluster inside the project in which the app service is present. (UUID)
state: The desired state which the indexes are expected to be in. (string)
indexes: The list of indexes to be matched against that state. (list)
headers: Headers to be sent with the API call. (dict)
**kwargs: Do not use this under normal circumstances. This is only to test negative scenarios. (dict)
Returns:
Success : Status Code and response (JSON).
Error : message, hint, code, HttpStatusCode
"""
self.cluster_ops_API_log.info(
"Fetching bulk index status for indices: {}, in the cluster: {}, "
"in the project: {}, in the tenant: {}"
.format(indexes, clusterId, projectId, organizationId))

params = {
"state": state,
"indexes": indexes
}
for k, v in kwargs.items():
params[k] = v

resp = self.api_post(self.bulk_index_check_endpoint.format(
organizationId, projectId, clusterId), params, headers)
return resp

def fetch_index_props(
self,
organizationId,
Expand Down
15 changes: 10 additions & 5 deletions capella/lib/APIRequests.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,27 @@ def api_post(self, api_endpoint, request_body, headers=None):

return (cbc_api_response)

def api_put(self, api_endpoint, request_body, headers=None):
def api_put(self, api_endpoint, json_request_body=None, headers=None,
data_request_body=None):
cbc_api_response = None

self._log.info(api_endpoint)
self._log.debug("Request body: " + str(request_body))

if json_request_body:
self._log.debug("Request body: " + str(json_request_body))
if data_request_body:
self._log.debug("Request body: " + str(data_request_body))
try:
if headers and "Authorization" in headers:
cbc_api_response = self.network_session.put(
self.API_BASE_URL + api_endpoint,
json=request_body,
json=json_request_body,
data=data_request_body,
verify=False, headers=headers)
else:
cbc_api_response = self.network_session.put(
self.API_BASE_URL + api_endpoint,
json=request_body,
json=json_request_body,
data=data_request_body,
auth=APIAuth(
self.SECRET, self.ACCESS, self.bearer_token),
verify=False, headers=headers)
Expand Down

0 comments on commit a8f980c

Please sign in to comment.