Skip to content

[patch] patch postgredb-tekton-results-postgres-0 PVC with storageclass when no default available #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: stable
Choose a base branch
from
66 changes: 64 additions & 2 deletions src/mas/devops/mas.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import re
import yaml
from os import path
from time import sleep
from types import SimpleNamespace
from kubernetes.dynamic.resource import ResourceInstance
from openshift.dynamic import DynamicClient
Expand Down Expand Up @@ -145,8 +146,8 @@ def verifyMasInstance(dynClient: DynamicClient, instanceId: str) -> bool:
except ResourceNotFoundError:
# The MAS Suite CRD has not even been installed in the cluster
return False
except UnauthorizedError:
logger.error("Error: Unable to verify MAS instance due to failed authorization: {e}")
except UnauthorizedError as e:
logger.error(f"Error: Unable to verify MAS instance due to failed authorization: {e}")
return False


Expand Down Expand Up @@ -194,3 +195,64 @@ def updateIBMEntitlementKey(dynClient: DynamicClient, namespace: str, icrUsernam

secret = secretsAPI.apply(body=secret, namespace=namespace)
return secret


def waitForPVC(dynClient: DynamicClient, namespace: str, pvcName: str) -> bool:
pvcAPI = dynClient.resources.get(api_version="v1", kind="PersistentVolumeClaim")
maxRetries = 60
foundReadyPVC = False
retries = 0
while not foundReadyPVC and retries < maxRetries:
retries += 1
try:
pvc = pvcAPI.get(name=pvcName, namespace=namespace)
if pvc.status.phase == "Bound":
foundReadyPVC = True
else:
logger.debug(f"Waiting 5s for PVC {pvcName} to be ready before checking again ...")
sleep(5)
except NotFoundError:
logger.debug(f"Waiting 5s for PVC {pvcName} to be created before checking again ...")
sleep(5)

return foundReadyPVC


def patchPendingPVC(dynClient: DynamicClient, namespace: str, pvcName: str, storageClassName: str = None) -> bool:
pvcAPI = dynClient.resources.get(api_version="v1", kind="PersistentVolumeClaim")
try:
pvc = pvcAPI.get(name=pvcName, namespace=namespace)
if pvc.status.phase == "Pending" and pvc.spec.storageClassName is None:
if storageClassName is not None and storageClassName(dynClient, name=storageClassName) is not None:
pvc.spec.storageClassName = storageClassName
else:
defaultStorageClasses = getDefaultStorageClasses(dynClient)
if defaultStorageClasses.provider is not None:
pvc.spec.storageClassName = defaultStorageClasses.rwo
else:
logger.error(f"Unable to set storageClassName in PVC {pvcName}.")
return False

pvcAPI.patch(body=pvc, namespace=namespace)

maxRetries = 60
foundReadyPVC = False
retries = 0
while not foundReadyPVC and retries < maxRetries:
retries += 1
try:
patchedPVC = pvcAPI.get(name=pvcName, namespace=namespace)
if patchedPVC.status.phase == "Bound":
foundReadyPVC = True
else:
logger.debug(f"Waiting 5s for PVC {pvcName} to be bound before checking again ...")
sleep(5)
except NotFoundError:
logger.error(f"The patched PVC {pvcName} does not exist.")
return False

return foundReadyPVC

except NotFoundError:
logger.error(f"PVC {pvcName} does not exist")
return False
4 changes: 2 additions & 2 deletions src/mas/devops/ocp.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ def waitForDeployment(dynClient: DynamicClient, namespace: str, deploymentName:
# NoneType and int comparison TypeError
foundReadyDeployment = True
else:
logger.debug("Waiting 5s for deployment {deploymentName} to be ready before checking again ...")
logger.debug(f"Waiting 5s for deployment {deploymentName} to be ready before checking again ...")
sleep(5)
except NotFoundError:
logger.debug("Waiting 5s for deployment {deploymentName} to be created before checking again ...")
logger.debug(f"Waiting 5s for deployment {deploymentName} to be created before checking again ...")
sleep(5)
return foundReadyDeployment

Expand Down
26 changes: 24 additions & 2 deletions src/mas/devops/tekton.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
from jinja2 import Environment, FileSystemLoader

from .ocp import getConsoleURL, waitForCRD, waitForDeployment, crdExists
from .mas import waitForPVC, patchPendingPVC

logger = logging.getLogger(__name__)


def installOpenShiftPipelines(dynClient: DynamicClient) -> bool:
# customStorageClassName is used when no default Storageclass is available on cluster,
# openshift-pipelines creates PVC which looks for default. customStorageClassName is patched into PVC when default is unavailable.
def installOpenShiftPipelines(dynClient: DynamicClient, customStorageClassName: str = None) -> bool:
"""
Install the OpenShift Pipelines Operator and wait for it to be ready to use
"""
Expand Down Expand Up @@ -79,11 +82,30 @@ def installOpenShiftPipelines(dynClient: DynamicClient) -> bool:
foundReadyWebhook = waitForDeployment(dynClient, namespace="openshift-pipelines", deploymentName="tekton-pipelines-webhook")
if foundReadyWebhook:
logger.info("OpenShift Pipelines Webhook is installed and ready")
return True
else:
logger.error("OpenShift Pipelines Webhook is NOT installed and ready")
return False

# Wait for the postgredb-tekton-results-postgres-0 PVC to be ready
# this PVC doesn't come up when there's no default storage class is in the cluster,
# this is causing the pvc to be in pending state and causing the tekton-results-postgres statefulSet in pending,
# due to these resources not coming up, the MAS pre-install check in the pipeline times out checking the health of this statefulSet,
# causing failure in pipeline.
# Refer https://github.com/ibm-mas/cli/issues/1511
logger.debug("Waiting for postgredb-tekton-results-postgres-0 PVC to be ready")
foundReadyPVC = waitForPVC(dynClient, namespace="openshift-pipelines", pvcName="postgredb-tekton-results-postgres-0")
if foundReadyPVC:
logger.info("OpenShift Pipelines postgres is installed and ready")
return True
else:
patchedPVC = patchPendingPVC(dynClient, namespace="openshift-pipelines", pvcName="postgredb-tekton-results-postgres-0", storageClassName=customStorageClassName)
if patchedPVC:
logger.info("OpenShift Pipelines postgres is installed and ready")
return True
else:
logger.error("OpenShift Pipelines postgres PVC is NOT ready")
return False


def updateTektonDefinitions(namespace: str, yamlFile: str) -> None:
"""
Expand Down