Feature 11073. Enhanced OSM declarative modelling for applications. App as first... 33/15333/1
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Thu, 7 Aug 2025 17:57:11 +0000 (19:57 +0200)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Fri, 8 Aug 2025 14:50:18 +0000 (16:50 +0200)
Change-Id: Icb8b48fc740a82b0a6bc58578a1b3f9a2ced86ed
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
installers/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-app-management-wft.yaml [new file with mode: 0644]

diff --git a/installers/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-app-management-wft.yaml b/installers/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-app-management-wft.yaml
new file mode 100644 (file)
index 0000000..e5ded97
--- /dev/null
@@ -0,0 +1,586 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# ===========================================================================================
+# OSM Application Management Workflow Template 
+# ===========================================================================================
+#
+# PREREQUISITES:
+# - PVC containing application model and parameters must exist
+# - Required files: app_instance_model.yaml, parameters/clear/environment.yaml, parameters/secret/environment.yaml
+# - Git repositories for Fleet and SW-Catalogs must be accessible
+#
+# USAGE:
+# Use the launcher workflows (launcher-app.yaml) or create custom workflows that reference
+# this template. Ensure the model_volume_name parameter points to a properly prepared PVC.
+#
+# For volume preparation utilities, see: scripts/library/osm/utils/workflow-pvc
+#
+# ===========================================================================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-app-management-wft
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # === Core Operation Configuration ===
+    - name: command
+      description: |
+        Full command string to execute with the OSM SDK.
+        Examples:
+        - "app create $environment": Deploy new application instance
+        - "app update $environment": Update existing application instance
+        - "app delete $environment": Remove application instance
+        This parameter accepts any valid OSM SDK command for maximum flexibility.
+    
+    # === Volume-Based Data Sources ===
+    - name: model_volume_name
+      description: |
+        Name of the PersistentVolumeClaim containing application models and parameters.
+        The PVC must contain the following structure:
+        - /app_instance_model.yaml: Application instantiation model (required)
+        - /parameters/clear/environment.yaml: Clear text parameters (optional)
+        Secret parameters are mounted separately via the secret_name parameter.
+    - name: secret_name
+      description: |
+        Name of the Kubernetes secret to mount at /model/parameters/secret/environment.yaml.
+        This parameter is optional. When provided, the secret will be mounted as a file
+        containing sensitive configuration parameters for the application.
+        
+    # === Git Repository Configuration ===
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+      value: "/fleet/fleet-osm"
+    - name: git_fleet_cred_secret
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+      value: "/sw-catalogs/sw-catalogs-osm"
+    - name: git_sw_catalogs_cred_secret
+    
+    # === Target Deployment Configuration ===
+    - name: app_name
+    - name: profile_name
+    - name: profile_type
+      value: "app-profiles"
+    - name: project_name
+      value: "osm_admin"
+    
+    # === OSM SDK Container Configuration ===
+    - name: osm_sdk_image_repository
+      value: "ttl.sh/osm-sdk-operations"
+      description: |
+        Repository for the OSM SDK container image. Default is the standardized
+        OSM SDK operations image that provides consistent behavior across workflows.
+    - name: osm_sdk_image_tag
+      value: "24h"
+      description: |
+        Tag for the OSM SDK container image. Default is '24h' which provides
+        a stable, time-limited image for workflow execution.
+    
+    # === Workflow Execution Control ===
+    - name: debug
+      value: "false"
+      description: |
+        Enable debug mode for detailed workflow execution information.
+        When set to 'true', additional debug steps will execute to provide:
+        - Volume mount status and accessibility checks
+        - Model content analysis and validation
+        - Repository structure inspection
+        - Embedded operations testing
+        Set to 'true' for troubleshooting workflow issues.
+    - name: dry_run
+      value: "false"
+      description: |
+        Enable dry-run mode to validate operations without making changes.
+        When set to 'true', the workflow will:
+        - Perform all validation and preparation steps
+        - Execute app operations in dry-run mode (no actual changes)
+        - Skip Git commit and push operations
+        Use this mode to test workflow configuration and validate models.
+
+  # === Workflow Lifecycle Management ===
+  # TTL strategy for automatic cleanup of completed workflow instances
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # 100 minutes - Time to live after workflow completion
+    secondsAfterSuccess: 6000     # 100 minutes - Time to live after successful execution
+    secondsAfterFailure: 9000     # 150 minutes - Extended time for failure analysis
+
+  # Main entry point for the workflow template
+  entrypoint: app-management
+
+  templates:
+  # === Main Application Management Template ===
+  # This template orchestrates the complete application lifecycle management process
+  # using a volume-based approach for application models and parameters.
+  - name: app-management
+    inputs:
+      parameters:
+      # Core operation configuration
+      - name: command
+      # Volume-based data sources
+      - name: model_volume_name
+      - name: secret_name
+      # Git repository configuration for Fleet and SW-Catalogs
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Target deployment configuration
+      - name: app_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+      # OSM SDK container configuration with standardized defaults
+      - name: osm_sdk_image_repository
+      - name: osm_sdk_image_tag
+      # Workflow execution control flags
+      - name: debug
+      - name: dry_run
+
+    steps:
+    # === PHASE 1: Parameter Validation ===
+    # Validate that all required parameters are provided for volume-based workflow execution
+    - - name: validate-parameters
+        inline:
+          container:
+            image: alpine:latest
+            command: [sh, -c]
+            args:
+              - |
+                set -e
+                echo "=== Volume-Based Workflow Parameter Validation ==="
+                echo "Validating required parameters for application management..."
+
+                # Validate core volume parameter
+                if [ -z "{{inputs.parameters.model_volume_name}}" ]; then
+                  echo "ERROR: model_volume_name parameter is required for volume-based workflow"
+                  echo "Please provide a PVC name containing the application model and parameters"
+                  exit 1
+                fi
+
+                # Validate Git repository parameters
+                if [ -z "{{inputs.parameters.git_fleet_url}}" ]; then
+                  echo "ERROR: git_fleet_url parameter is required for Fleet repository access"
+                  exit 1
+                fi
+
+                if [ -z "{{inputs.parameters.git_sw_catalogs_url}}" ]; then
+                  echo "ERROR: git_sw_catalogs_url parameter is required for SW-Catalogs repository access"
+                  exit 1
+                fi
+
+                # Validate target deployment parameters
+                if [ -z "{{inputs.parameters.app_name}}" ]; then
+                  echo "ERROR: app_name parameter is required for application identification"
+                  exit 1
+                fi
+
+                if [ -z "{{inputs.parameters.profile_name}}" ]; then
+                  echo "ERROR: profile_name parameter is required for deployment profile"
+                  exit 1
+                fi
+
+                echo "✓ All required parameters validated successfully"
+                echo "Configuration Summary:"
+                echo "  Command: {{inputs.parameters.command}}"
+                echo "  Model Volume: {{inputs.parameters.model_volume_name}}"
+                echo "  Secret Name: {{inputs.parameters.secret_name}}"
+                echo "  Application: {{inputs.parameters.app_name}}"
+                echo "  Profile: {{inputs.parameters.profile_name}} ({{inputs.parameters.profile_type}})"
+                echo "  Project: {{inputs.parameters.project_name}}"
+                echo "  OSM SDK: {{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
+                echo "  Debug Mode: {{inputs.parameters.debug}}"
+                echo "  Dry Run: {{inputs.parameters.dry_run}}"
+    
+    # === PHASE 2: Volume Preparation ===
+    # Generate temporary volumes for Git repository operations
+    # These volumes will store cloned Fleet and SW-Catalogs repositories during workflow execution
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'  # Sufficient space for Fleet repository content
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'  # Sufficient space for SW-Catalogs repository content
+    
+    # === PHASE 3: Git Repository Cloning ===
+    # Clone the required Git repositories for application modeling and deployment
+    # These repositories provide the templates and target locations for GitOps operations
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+
+    # === PHASE 4: Debug Information (Optional) ===
+    # Comprehensive debugging information for volume-based workflow troubleshooting
+    # Executed only when debug parameter is set to true
+    - - name: debug-info
+        when: "{{inputs.parameters.debug}} == true"
+        inline:
+          container:
+            image: "{{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
+            args:
+              - "nu"
+              - "-c"
+              - |
+                echo "=== OSM App Modeling Debug Information (Volume-Based) ==="
+                echo $"Command: {{inputs.parameters.command}}"
+                echo $"SDK Image: {{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
+                echo $"Model Volume: {{inputs.parameters.model_volume_name}}"
+                echo $"Secret Name: {{inputs.parameters.secret_name}}"
+                echo $"Timestamp: (date now | format date '%Y-%m-%d %H:%M:%S')"
+                echo ""
+
+                echo "=== Volume Mount Status and Accessibility ==="
+                echo "Checking volume mount accessibility..."
+
+                # Check model volume mount
+                echo "Model volume mount status:"
+                if (ls /model | length) > 0 {
+                  echo "✓ Model volume mounted successfully at /model"
+                  echo $"  Files found: (ls /model | length)"
+                } else {
+                  echo "✗ Model volume mount failed or empty"
+                }
+
+                # Check fleet volume mount
+                echo "Fleet volume mount status:"
+                if (ls /repos/fleet-osm | length) > 0 {
+                  echo "✓ Fleet volume mounted successfully at /repos/fleet-osm"
+                  echo $"  Files found: (ls /repos/fleet-osm | length)"
+                } else {
+                  echo "✗ Fleet volume mount failed or empty"
+                }
+
+                # Check sw-catalogs volume mount
+                echo "SW-Catalogs volume mount status:"
+                if (ls /repos/sw-catalogs-osm | length) > 0 {
+                  echo "✓ SW-Catalogs volume mounted successfully at /repos/sw-catalogs-osm"
+                  echo $"  Files found: (ls /repos/sw-catalogs-osm | length)"
+                } else {
+                  echo "✗ SW-Catalogs volume mount failed or empty"
+                }
+                echo ""
+
+                echo "=== Model Volume Contents and Structure ==="
+                echo "Model volume directory structure:"
+                try {
+                  ls /model -la | select name type size permissions | table
+                } catch {
+                  echo "Error accessing model volume contents"
+                }
+                echo ""
+
+                echo "=== Required Model Files Validation ==="
+                # Check app_instance_model.yaml
+                if ("/model/app_instance_model.yaml" | path exists) {
+                  echo "✓ app_instance_model.yaml found"
+                  try {
+                    let file_size = (ls /model/app_instance_model.yaml | get size | first)
+                    echo $"  Size: ($file_size) bytes"
+                  } catch {
+                    echo "  Warning: Could not read file size"
+                  }
+                } else {
+                  echo "✗ app_instance_model.yaml missing"
+                }
+
+                # Check clear parameters
+                if ("/model/parameters/clear/environment.yaml" | path exists) {
+                  echo "✓ Clear parameters file found"
+                  try {
+                    let file_size = (ls /model/parameters/clear/environment.yaml | get size | first)
+                    echo $"  Size: ($file_size) bytes"
+                  } catch {
+                    echo "  Warning: Could not read file size"
+                  }
+                } else {
+                  echo "ℹ Clear parameters file missing (optional)"
+                }
+
+                # Check secret parameters
+                if ("/model/parameters/secret/environment.yaml" | path exists) {
+                  echo "✓ Secret parameters file found"
+                  try {
+                    let file_size = (ls /model/parameters/secret/environment.yaml | get size | first)
+                    echo $"  Size: ($file_size) bytes"
+                  } catch {
+                    echo "  Warning: Could not read file size"
+                  }
+                } else {
+                  echo "ℹ Secret parameters file missing (optional)"
+                }
+
+                echo "=== Model Content Analysis ==="
+                echo "App Instance Model (first 30 lines):"
+                try {
+                  open /model/app_instance_model.yaml | lines | first 30 | str join "\n"
+                } catch {
+                  echo "Error reading app_instance_model.yaml"
+                }
+                echo ""
+
+                echo "Clear Parameters Content:"
+                try {
+                  open /model/parameters/clear/environment.yaml | to yaml
+                } catch {
+                  echo "Clear parameters not available"
+                }
+                echo ""
+
+                echo "Secret Parameters Content (masked for security):"
+                try {
+                  if ("/model/parameters/secret/environment.yaml" | path exists) {
+                    echo "Secret file exists - content masked for security"
+                  } else {
+                    echo "Secret parameters not available"
+                  }
+                } catch {
+                  echo "Error checking secret parameters"
+                }
+                echo ""
+
+                echo "=== Loaded Model Instance from Volume ==="
+                try {
+                  $model_instance | to yaml | lines | first 30 | str join "\n"
+                } catch {
+                  echo "Error loading model instance"
+                }
+                echo ""
+
+                echo "=== Environment Parameters from Volume ==="
+                try {
+                  $environment | to yaml | lines | first 30 | str join "\n"
+                } catch {
+                  echo "Error loading environment"
+                }
+                echo ""
+
+                echo "=== Repository Structure ==="
+                echo "Fleet repo contents:"
+                try {
+                  ls /repos/fleet-osm | select name type size | first 10 | table
+                } catch {
+                  echo "Error accessing fleet repository"
+                }
+                echo ""
+                echo "SW-Catalogs repo contents:"
+                try {
+                  ls /repos/sw-catalogs-osm | select name type size | first 10 | table
+                } catch {
+                  echo "Error accessing sw-catalogs repository"
+                }
+                echo ""
+
+                echo "=== Embedded Operations Validation ==="
+                echo "App Operations Library Status:"
+                try {
+                  help app | lines | first 10 | str join "\n"
+                } catch {
+                  echo "Error accessing app operations library"
+                }
+                echo ""
+
+                echo "=== Dry Run Test ==="
+                echo "Testing command execution with volume-mounted data..."
+                try {
+                  echo $"Command to execute: {{inputs.parameters.command}}"
+                  echo "✓ Command validation successful with volume-based data"
+                } catch {
+                  echo $"✗ Command validation failed: ($in)"
+                }
+                echo ""
+
+                echo "=== Volume Permissions Check ==="
+                echo "Model volume permissions:"
+                try {
+                  ls -la /model | head -5 | each { |item| echo $"  ($item.name): ($item.permissions)" } | str join "\n"
+                } catch {
+                  echo "Error checking model volume permissions"
+                }
+                echo ""
+
+                echo "=== Debug Information Complete ==="
+            volumeMounts:
+            - name: model-volume
+              mountPath: /model
+            - name: fleet-volume
+              mountPath: /repos/fleet-osm
+              subPath: fleet-osm
+            - name: sw-catalogs-volume
+              mountPath: /repos/sw-catalogs-osm
+              subPath: sw-catalogs-osm
+            # Mount secret volume when secret_name is provided
+            - name: secret-volume
+              mountPath: /model/parameters/secret
+              readOnly: true
+          volumes:
+          - name: model-volume
+            persistentVolumeClaim:
+              claimName: "{{inputs.parameters.model_volume_name}}"
+          - name: fleet-volume
+            persistentVolumeClaim:
+              claimName: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw-catalogs-volume
+            persistentVolumeClaim:
+              claimName: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: secret-volume
+            secret:
+              secretName: "{{inputs.parameters.secret_name}}"
+              optional: true
+
+    # === PHASE 5: Application Operations ===
+    # This phase performs the actual create/update/delete operations on the application model
+    - - name: run-app-operation
+        when: "{{inputs.parameters.dry_run}} != true"
+        inline:
+          container:
+            image: "{{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
+            args: ["{{inputs.parameters.command}}"]         # Full command string to execute
+            volumeMounts:
+            # Mount model volume containing application data
+            - name: model-volume
+              mountPath: /model
+            # Mount Fleet repository for GitOps target
+            - name: fleet-volume
+              mountPath: /repos/fleet-osm
+              subPath: fleet-osm
+            # Mount SW-Catalogs repository for application templates
+            - name: sw-catalogs-volume
+              mountPath: /repos/sw-catalogs-osm
+              subPath: sw-catalogs-osm
+            # Mount secret volume when secret_name is provided
+            - name: secret-volume
+              mountPath: /model/parameters/secret
+              readOnly: true
+          volumes:
+          - name: model-volume
+            persistentVolumeClaim:
+              claimName: "{{inputs.parameters.model_volume_name}}"
+          - name: fleet-volume
+            persistentVolumeClaim:
+              claimName: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw-catalogs-volume
+            persistentVolumeClaim:
+              claimName: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: secret-volume
+            secret:
+              secretName: "{{inputs.parameters.secret_name}}"
+              optional: true
+      # Dry-run variant of the app operation for validation without changes
+      - name: run-app-operation-dry-run
+        when: "{{inputs.parameters.dry_run}} == true"
+        inline:
+          container:
+            image: "{{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
+            args: ["{{inputs.parameters.command}} --dry-run"] # Full command string with dry-run flag
+            volumeMounts:
+            # Same volume mounts as regular operation for consistency
+            - name: model-volume
+              mountPath: /model
+            - name: fleet-volume
+              mountPath: /repos/fleet-osm
+              subPath: fleet-osm
+            - name: sw-catalogs-volume
+              mountPath: /repos/sw-catalogs-osm
+              subPath: sw-catalogs-osm
+            # Mount secret volume when secret_name is provided
+            - name: secret-volume
+              mountPath: /model/parameters/secret
+              readOnly: true
+          volumes:
+          - name: model-volume
+            persistentVolumeClaim:
+              claimName: "{{inputs.parameters.model_volume_name}}"
+          - name: fleet-volume
+            persistentVolumeClaim:
+              claimName: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw-catalogs-volume
+            persistentVolumeClaim:
+              claimName: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: secret-volume
+            secret:
+              secretName: "{{inputs.parameters.secret_name}}"
+              optional: true
+
+    # === PHASE 7: GitOps Commit and Push ===
+    # Commit and push the generated application manifests to the Fleet repository
+    # This completes the GitOps workflow by updating the target repository with changes
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Execute '{{inputs.parameters.command}}' for App '{{inputs.parameters.app_name}}' in {{inputs.parameters.profile_name}} profile ({{inputs.parameters.profile_type}}) @ {{inputs.parameters.project_name}} project [Volume-Based Workflow]"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"