--- /dev/null
+#######################################################################################
+# 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}}"