diff --git a/language/init_const.go b/language/init_const.go index e3fba7b..be0b285 100644 --- a/language/init_const.go +++ b/language/init_const.go @@ -39,6 +39,9 @@ const ( ErrorParameterReplicas = "parameter 'replicas' is required and must be an integer" ErrorParameterNewImage = "parameter 'newImage' is required and must be a string" ErrorParameterContainerName = "parameter 'containerName' is required and must be a string" + ErrorParameterStorageClassName = "parameter 'storageClassName' is required and must be a string" + ErrorParameterpvcName = "parameter 'pvcName' is required and must be a string" + ErrorparameterstorageSize = "parameter 'storageSize' is required and must be a string" ErrorConflict = "Conflict detected when scaling deployment '%s', resolving..." FailedToScaleDeployment = "Failed to scale deployment '%s' to '%d' after %d retries: %v" FailedTOScallEdDeployment = "Failed to scale deployment '%s' to '%d': %v" @@ -49,6 +52,9 @@ const ( ErrorFailedToUpdateImage = "Failed to update image for deployment %s: %v" ErrorFailedToUpdateImageAfterRetries = "Failed to update image for deployment %s after %d retries" ErrorFailedToUpdateDeployImage = "Failed to update deployment image" + ErrorCreatingPvc = "Error creating pvc: %w" + ErrorCreatingStorageClass = "Error creating storage class: %w" + ErrorFailedToCreatePvc = "Failed to create PVC '%s': %v" ) const ( @@ -86,9 +92,11 @@ const ( TaskManageDeployments = "ManageDeployments" TaskScaleDeployment = "ScaleDeployment" TaskUpdateDeploymentImage = "UpdateDeploymentImage" + TaskCreatePVC = "CreatePVCStorage" ScalingDeployment = "Crew Worker %d: Scaling deployments" ManagingDeployments = "Crew Worker %d: Managing deployments" UpdatingImage = "Crew Worker %d: Updating deployment image" + CreatePVCStorage = "Crew Worker %d: Creating PVC storage" ) const ( @@ -108,6 +116,7 @@ const ( ImageSuccessfully = "Image updated successfully for deployment %s to %s" DeploymentImageUpdated = "Deployment image updated successfully" UpdatingDeploymentImage = "Updating deployment image" + WorkerSucessfullyCreatePVC = "Successfully created PVC '%s' in namespace '%s'" ) const ( diff --git a/worker/cmd_constant.go b/worker/cmd_constant.go index d8e0a9b..6b43a78 100644 --- a/worker/cmd_constant.go +++ b/worker/cmd_constant.go @@ -15,19 +15,22 @@ const ( // defined object const ( - metaData = "metadata" - labeLs = "labels" - labeLKey = "labelKey" - labeLValue = "labelValue" - labelSelector = "labelSelector" - fieldSelector = "fieldSelector" - limIt = "limit" - deploYmentName = "deploymentName" - contaInerName = "containerName" - newImAge = "newImage" - repliCas = "replicas" - deploymenT = "deployment" - scalE = "scale" + metaData = "metadata" + labeLs = "labels" + labeLKey = "labelKey" + labeLValue = "labelValue" + labelSelector = "labelSelector" + fieldSelector = "fieldSelector" + limIt = "limit" + deploYmentName = "deploymentName" + contaInerName = "containerName" + newImAge = "newImage" + repliCas = "replicas" + deploymenT = "deployment" + scalE = "scale" + storageClassName = "storageClassName" + pvcName = "pvcName" + storageSize = "storageSize" ) // defined notice message just like human would type diff --git a/worker/docs.go b/worker/docs.go index 2bc2eb2..934b654 100644 --- a/worker/docs.go +++ b/worker/docs.go @@ -1,7 +1,8 @@ // Package worker provides a set of tools designed to facilitate the interaction with // Kubernetes resources from within a cluster. It offers a convenient abstraction for // managing Kubernetes operations, focusing on pod health checks, pod labeling, structured logging, -// scaling deployments, updating deployment images, and task configuration through YAML or JSON files. +// scaling deployments, updating deployment images, creating PersistentVolumeClaims (PVCs), +// and task configuration through YAML or JSON files. // // The package is intended for applications running as pods within Kubernetes clusters // and leverages in-cluster configuration to establish a clientset for API interactions. @@ -31,21 +32,26 @@ // within deployments. This includes handling retries on update conflicts and reporting // the outcome of the operation. // +// - Creation of PersistentVolumeClaims (PVCs) is now supported, allowing for dynamic +// provisioning of storage resources within the cluster. The process is logged with +// emojis to indicate success or failure, improving the visibility of the operation's outcome. +// // # Functions // // - NewKubernetesClient: Creates a new Kubernetes clientset configured for in-cluster // communication with the Kubernetes API server. // // - CrewWorker: Orchestrates a worker process to perform tasks such as health checks, -// labeling of pods, scaling deployments, updating deployment images, and other configurable tasks within a specified namespace. +// labeling of pods, scaling deployments, updating deployment images, creating PVCs, +// and other configurable tasks within a specified namespace. // It includes retry logic to handle transient errors and respects cancellation and timeout contexts. -// Structured logging is used to provide detailed contextual information. +// Structured logging is used to provide detailed contextual information, now with emojis for better visual cues. // // - LoadTasksFromYAML: Loads task configurations from a YAML file, allowing for // dynamic task management based on external configuration. // // - CrewGetPods: Retrieves all pods within a given namespace, logging the attempt -// and outcome of the operation. +// and outcome of the operation, now with emojis for quick status recognition. // // - CrewProcessPods: Iterates over a collection of pods, assessing their health, // updating labels, and reporting the status to a results channel. It also handles context cancellation. @@ -63,11 +69,15 @@ // - UpdateDeploymentImage: Updates the image of a specified container within a deployment, // handling retries on conflicts and reporting the outcome through a results channel. // +// - CrewCreatePVCStorage: Creates a PersistentVolumeClaim in the specified namespace, +// allowing for storage provisioning according to the parameters provided. +// The creation process is logged with success and error emojis for immediate feedback. +// // Usage: // // Initialize the Kubernetes client using NewKubernetesClient, then leverage the client // to perform operations such as retrieving and processing pods within a namespace, scaling -// deployments, and updating deployment images as required. Contexts are used to manage the +// deployments, updating deployment images, and creating PVCs as required. Contexts are used to manage the // lifecycle of the worker processes, including graceful shutdowns and cancellation. Task // configurations can be loaded from a YAML file for enhanced flexibility. // @@ -96,11 +106,11 @@ // // # Enhancements // -// - The package now includes structured logging capabilities, enhancing traceability +// - The package now includes structured logging capabilities, enhanced with emojis, improving traceability // and aiding in debugging efforts by providing detailed contextual information. // // - Logging functionality is customizable, allowing different workers to provide -// unique contextual information, such as worker indices or specific namespaces. +// unique contextual information, such as worker indices or specific namespaces, with visual cues. // // - The dynamic task execution model supports adding new tasks and task runners // without changing existing code, facilitating scalability and extensibility. @@ -114,6 +124,9 @@ // - Image update functionality has been added to modify the image of a container within // a deployment, with built-in retry logic for handling update conflicts. // +// - The introduction of PVC creation allows for dynamic storage provisioning, complete with +// emoji-based logging for immediate operation feedback. +// // # TODO // // - Extend the functionality of the CrewWorker function to support a wider range diff --git a/worker/init.go b/worker/init.go index 2a4b259..270599d 100644 --- a/worker/init.go +++ b/worker/init.go @@ -29,4 +29,7 @@ func init() { // Register the new TaskRunner for updating image deployments. RegisterTaskRunner("CrewUpdateImageDeployments", func() TaskRunner { return &CrewUpdateImageDeployments{} }) + // Register the new TaskRunner for create storage pvc + RegisterTaskRunner("CrewCreatePVCStorage", func() TaskRunner { return &CrewCreatePVCStorage{} }) + } diff --git a/worker/pvc_storage.go b/worker/pvc_storage.go new file mode 100644 index 0000000..5a533b6 --- /dev/null +++ b/worker/pvc_storage.go @@ -0,0 +1,54 @@ +package worker + +import ( + "context" + "fmt" + + "github.com/H0llyW00dzZ/K8sBlackPearl/language" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// createPVC creates a persistent volume claim (PVC) in the specified namespace. +// +// Parameters: +// - ctx: Context for cancellation and timeout. +// - clientset: A Kubernetes clientset to interact with the Kubernetes API. +// - shipsNamespace: The Kubernetes namespace in which to create the PVC. +// - storageClassName: The name of the storage class to use for the PVC. +// - pvcName: The name of the PVC to create. +// - storageSize: The size of the PVC in gigabytes. +// +// Returns an error if the PVC cannot be created. +func createPVC(ctx context.Context, clientset *kubernetes.Clientset, shipsNamespace, storageClassName, pvcName, storageSize string) error { + // Define the PVC object. + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: v1.ObjectMeta{ + Name: pvcName, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + // Specify the storage class to use. + StorageClassName: &storageClassName, + // Request read/write access to the PVC. + AccessModes: []corev1.PersistentVolumeAccessMode{ + corev1.ReadWriteOnce, + }, + // Define the requested storage size. + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse(storageSize), + }, + }, + }, + } + + // Create the PVC using the Kubernetes API. + _, err := clientset.CoreV1().PersistentVolumeClaims(shipsNamespace).Create(ctx, pvc, v1.CreateOptions{}) + if err != nil { + return fmt.Errorf(language.ErrorCreatingPvc, err) + } + + return nil +} diff --git a/worker/tasks_crew.go b/worker/tasks_crew.go index f30c145..1a20b8f 100644 --- a/worker/tasks_crew.go +++ b/worker/tasks_crew.go @@ -310,6 +310,70 @@ func (c *CrewUpdateImageDeployments) Run(ctx context.Context, clientset *kuberne return nil } +// CrewCreatePVCStorage is an implementation of TaskRunner that creates a PersistentVolumeClaim. +// +// This struct is responsible for creating PVCs (PersistentVolumeClaims) in a Kubernetes cluster. +// It extracts the necessary parameters from the task parameters, calls the createPVC function to create the PVC, +// and handles logging and error handling during the process. +type CrewCreatePVCStorage struct { + // shipsNamespace specifies the Kubernetes namespace where the PVC will be created. + shipsNamespace string + + // workerIndex is an identifier for the worker that is executing the task. + // This can be used for logging and tracking the progress of the task across multiple workers. + workerIndex int +} + +// Run creates a PersistentVolumeClaim in the specified namespace using the provided parameters. +// +// This method orchestrates the task execution by extracting the required parameters, +// invoking the createPVC function to create the PVC, and handling any errors or logging messages. +func (c *CrewCreatePVCStorage) Run(ctx context.Context, clientset *kubernetes.Clientset, shipsNamespace string, taskName string, parameters map[string]interface{}, workerIndex int) error { + // Define logging fields for structured logging + fields := navigator.CreateLogFields( + language.TaskCreatePVC, + shipsNamespace, + navigator.WithAnyZapField(zap.String(language.Task_Name, taskName)), + ) + + // Log the start of the PVC creation operation + navigator.LogInfoWithEmoji( + language.PirateEmoji, + fmt.Sprintf(language.CreatePVCStorage, workerIndex), + fields..., + ) + + // Extract the necessary parameters from the task parameters + storageClassName, ok := parameters[storageClassName].(string) + if !ok { + return fmt.Errorf(language.ErrorParameterStorageClassName) + } + pvcName, ok := parameters[pvcName].(string) + if !ok { + return fmt.Errorf(language.ErrorParameterpvcName) + } + storageSize, ok := parameters[storageSize].(string) + if !ok { + return fmt.Errorf(language.ErrorparameterstorageSize) + } + + // Call the createPVC function with the extracted parameters to create the PVC + err := createPVC(ctx, clientset, shipsNamespace, storageClassName, pvcName, storageSize) + if err != nil { + // Log the error and return + errorFields := append(fields, zap.String(language.Error, err.Error())) + failedMessage := fmt.Sprintf(language.ErrorFailedToCreatePvc, pvcName, err) + navigator.LogErrorWithEmojiRateLimited(constant.ErrorEmoji, failedMessage, errorFields...) + return err + } + + // Log the successful creation of the PVC + successMessage := fmt.Sprintf(language.WorkerSucessfullyCreatePVC, pvcName, shipsNamespace) + navigator.LogInfoWithEmoji(constant.SuccessEmoji, successMessage, fields...) + + return nil +} + // getLatestVersionOfPod fetches the latest version of the Pod from the Kubernetes API. func getLatestVersionOfPod(ctx context.Context, clientset *kubernetes.Clientset, namespace string, podName string) (*corev1.Pod, error) { // Fetch the latest version of the Pod using the clientset.