Skip to content
Merged
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
15 changes: 15 additions & 0 deletions operators/o2ims-operator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,20 @@ kind delete cluster -n edge

O2IMS operator listens for ProvisioningRequest CR and once it is created it goes through different stages

Following are the Provisioning Request Phases:



| Status | Description |
| --- | --- |
| `PENDING` | The ProvisioningRequest is waiting to be processed by the O-Cloud (IMS). |
| `PROGRESSING` | The O-Cloud (IMS) is processing the ProvisioningRequest and executing the actions to fulfill it. |
| `FULFILLED` | The ProvisioningRequest has been successfully processed and completed by the O-Cloud (IMS). |
| `FAILED` | The ProvisioningRequest could not be fully processed by the O-Cloud (IMS). |
| `DELETING` | The ProvisioningRequest is in the process of being deleted by the O-Cloud (IMS). |



1. `ProvisioningRequest validation`: The controller [provisioning_request_validation_controller.py](./controllers/provisioning_request_validation_controller.py) validates the provisioning requests. Currently it checks if the field `clusterName` and `clusterProvisioner`. At the moment only `capi` handled clusters are support
2. `ProvisioningRequest creation`: The controller [provisioning_request_controller.py](./controllers/provisioning_request_controller.py) takes care of creating the a package variant for Porch which can be applied to the cluster where porch is running. After applying package variant it waits for the cluster to be created and it follows the creation via querying `clusters.cluster.x-k8s.io` endpoint. Later we will add querying of packageRevisions also but at the moment their is a problem with querying packageRevisions because sometimes Porch is not able to process the request

Expand Down Expand Up @@ -278,3 +292,4 @@ do
kpt alpha rpkg delete $pkg -ndefault
done
```

91 changes: 91 additions & 0 deletions operators/o2ims-operator/api/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from flask import Flask, request, jsonify
from kubernetes import client, config
from kubernetes.client.rest import ApiException
import os
import logging
from datetime import datetime
from controllers.utils import validate_cluster_creation_request
app = Flask(__name__)

@app.route('/O2ims_infrastructureProvisioning/v1/provisioningRequests ', methods=['POST'])
def trigger_action():
data = request.json
logging.info("O2IMS API Received Request Payload Is:", data)
# add validation logic here
now = datetime.now()
dt_string = now.strftime("%Y-%m-%d %H:%M:%S")
try:
validate_cluster_creation_request(params=data)
o2ims_cr={
'apiVersion': 'o2ims.provisioning.oran.org/v1alpha1',
'kind': 'ProvisioningRequest',
'metadata': {
'name': data.get('name'),
'labels':{
'provisioningRequestId': data.get('provisioningRequestId')
}
},
'spec':{
'description': data.get('description'),
'name': data.get('name'),
'templateName': data.get('templateName'),
'templateParameters':data.get('templateParameters'),
'templateVersion': data.get('templateVersion')
}
}
logging.debug("O2IMS CR Payload Is:", o2ims_cr)
config.load_incluster_config()
api = client.CustomObjectsApi()
response = api.create_cluster_custom_object(
group='o2ims.provisioning.oran.org',
version='v1alpha1',
plural='provisioningrequest',
body=o2ims_cr
)
except Exception as e:
logging.error(f"Caught Exception while deploying O2IMS CR ,{e}")
return jsonify({"status":{"updateTime":dt_string,"message":f"O2IMS Deployment Failed,{e}","provisioningPhase":"FAILED"}}),500
return jsonify({"provisioningRequestData": data, "status": {"updateTime":dt_string,"message":"In-Progress","provisioningPhase":"PROGRESSING"},"ProvisionedResourceSet":{"nodeClusterId":"test","infrastructureResourceIds":"sample"}}), 200

@app.route('/O2ims_infrastructureProvisioning/v1/provisioningRequests ', methods=['GET'])
def fetch_status():
now = datetime.now()
dt_string = now.strftime("%Y-%m-%d %H:%M:%S")
logging.info("Received O2IMS GET STATUS API CALL At %s:",dt_string)

try:
config.load_incluster_config()
api = client.CustomObjectsApi()
response = api.list_cluster_custom_object(
group='o2ims.provisioning.oran.org',
version='v1alpha1',
plural='provisioningrequest'
)
data=response.get('items')
if len(data)==0:
status=jsonify({"status":{"updateTime":dt_string,"message":"No ProvisioningRequest Found","provisioningPhase":"FAILED"}})
response_data={"provisioningRequestData": {}, "status": status,"ProvisionedResourceSet":{}}
return response_data, 200
#read all the provisioning requests and create response array from it

for o2ims_cr in data:
status={}
#read o2ims_cr status and update message accordingly
if 'status' in o2ims_cr.keys():
if o2ims_cr['status'].get('provisioningState')=='failed':
status= jsonify({"status":{"updateTime":dt_string,"message":o2ims_cr['status'].get('provisioningMessage'),"provisioningPhase":"FAILED"}})
elif o2ims_cr['status'].get('provisioningState')=='progressing':
status= jsonify({"status":{"updateTime":dt_string,"message":o2ims_cr['status'].get('provisioningMessage'),"provisioningPhase":"PROGRESSING"}})
elif o2ims_cr['status'].get('provisioningState')=='fulfilled':
status= jsonify({"status":{"updateTime":dt_string,"message":o2ims_cr['status'].get('provisioningMessage'),"provisioningPhase":"FULFILLED"}})
else:
status=({"status":{"updateTime":dt_string,"message":"In-Progress","provisioningPhase":"PROGRESSING"}})
# read o2ims_cr spec and update response accordingly
spec=o2ims_cr.get('spec')
provisionedresourceset={"nodeClusterId":"test","infrastructureResourceIds":"sample"}
response_data={"provisioningRequestData": spec, "status": status,"ProvisionedResourceSet":provisionedresourceset}
return response_data, 200
except client.exceptions.ApiException as e:
logging.error(f"Caught Exception while fetching O2IMS CR Status ,{e}")
return jsonify({"status":{"updateTime":dt_string,"message":f"O2IMS Deployment Failed,{e}","provisioningPhase":"FAILED"}}),500

11 changes: 11 additions & 0 deletions operators/o2ims-operator/controllers/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@
import kopf
import os

from flask import Flask
import threading
from api import app # Import the Flask app



# Start Flask in a separate thread
def run_flask():
app.run(host='0.0.0.0', port=5000)

threading.Thread(target=run_flask, daemon=True).star

@kopf.on.startup()
def configure(settings: kopf.OperatorSettings, memo: kopf.Memo, **_):
Expand Down
20 changes: 20 additions & 0 deletions operators/o2ims-operator/controllers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,23 @@ def get_capi_cluster(name: str = None, namespace: str = None, logger=None):
if logger:
logger.debug(f"get_capi_cluster response: {r.json()}")
return response

def validate_cluster_creation_request(params: dict = None):
"""
:param params: parameters of cluster creation request
:type params: dict
:return: None
:rtype: None
"""

# Validate templateName
if not params.get('templateName'):
raise ValueError("Parameter 'templateName' is empty or missing.")

# Validate templateVersion
if not params.get('templateVersion'):
raise ValueError("Parameter 'templateVersion' is empty or missing.")

# Validate templateParameters
if not params.get('templateParameters'):
raise ValueError("Parameter 'templateParameters' is empty or missing.")
3 changes: 2 additions & 1 deletion operators/o2ims-operator/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
jinja2==3.1.6
kopf==1.36.0
requests==2.32.4
python-dateutil
python-dateutil==2.8.2
flask==2.3.3