e5ded974b6103d6dd6f350eafc1a6e3f96047552
[osm/devops.git] /
1 #######################################################################################
2 # Copyright ETSI Contributors and Others.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #######################################################################################
17
18 # ===========================================================================================
19 # OSM Application Management Workflow Template 
20 # ===========================================================================================
21 #
22 # PREREQUISITES:
23 # - PVC containing application model and parameters must exist
24 # - Required files: app_instance_model.yaml, parameters/clear/environment.yaml, parameters/secret/environment.yaml
25 # - Git repositories for Fleet and SW-Catalogs must be accessible
26 #
27 # USAGE:
28 # Use the launcher workflows (launcher-app.yaml) or create custom workflows that reference
29 # this template. Ensure the model_volume_name parameter points to a properly prepared PVC.
30 #
31 # For volume preparation utilities, see: scripts/library/osm/utils/workflow-pvc
32 #
33 # ===========================================================================================
34
35 apiVersion: argoproj.io/v1alpha1
36 kind: WorkflowTemplate
37 metadata:
38   name: full-app-management-wft
39   namespace: osm-workflows
40 spec:
41   arguments:
42     parameters:
43     # === Core Operation Configuration ===
44     - name: command
45       description: |
46         Full command string to execute with the OSM SDK.
47         Examples:
48         - "app create $environment": Deploy new application instance
49         - "app update $environment": Update existing application instance
50         - "app delete $environment": Remove application instance
51         This parameter accepts any valid OSM SDK command for maximum flexibility.
52     
53     # === Volume-Based Data Sources ===
54     - name: model_volume_name
55       description: |
56         Name of the PersistentVolumeClaim containing application models and parameters.
57         The PVC must contain the following structure:
58         - /app_instance_model.yaml: Application instantiation model (required)
59         - /parameters/clear/environment.yaml: Clear text parameters (optional)
60         Secret parameters are mounted separately via the secret_name parameter.
61     - name: secret_name
62       description: |
63         Name of the Kubernetes secret to mount at /model/parameters/secret/environment.yaml.
64         This parameter is optional. When provided, the secret will be mounted as a file
65         containing sensitive configuration parameters for the application.
66         
67     # === Git Repository Configuration ===
68     - name: git_fleet_url
69     - name: fleet_destination_folder
70       value: "/fleet/fleet-osm"
71     - name: git_fleet_cred_secret
72     - name: git_sw_catalogs_url
73     - name: sw_catalogs_destination_folder
74       value: "/sw-catalogs/sw-catalogs-osm"
75     - name: git_sw_catalogs_cred_secret
76     
77     # === Target Deployment Configuration ===
78     - name: app_name
79     - name: profile_name
80     - name: profile_type
81       value: "app-profiles"
82     - name: project_name
83       value: "osm_admin"
84     
85     # === OSM SDK Container Configuration ===
86     - name: osm_sdk_image_repository
87       value: "ttl.sh/osm-sdk-operations"
88       description: |
89         Repository for the OSM SDK container image. Default is the standardized
90         OSM SDK operations image that provides consistent behavior across workflows.
91     - name: osm_sdk_image_tag
92       value: "24h"
93       description: |
94         Tag for the OSM SDK container image. Default is '24h' which provides
95         a stable, time-limited image for workflow execution.
96     
97     # === Workflow Execution Control ===
98     - name: debug
99       value: "false"
100       description: |
101         Enable debug mode for detailed workflow execution information.
102         When set to 'true', additional debug steps will execute to provide:
103         - Volume mount status and accessibility checks
104         - Model content analysis and validation
105         - Repository structure inspection
106         - Embedded operations testing
107         Set to 'true' for troubleshooting workflow issues.
108     - name: dry_run
109       value: "false"
110       description: |
111         Enable dry-run mode to validate operations without making changes.
112         When set to 'true', the workflow will:
113         - Perform all validation and preparation steps
114         - Execute app operations in dry-run mode (no actual changes)
115         - Skip Git commit and push operations
116         Use this mode to test workflow configuration and validate models.
117
118   # === Workflow Lifecycle Management ===
119   # TTL strategy for automatic cleanup of completed workflow instances
120   ttlStrategy:
121     secondsAfterCompletion: 6000  # 100 minutes - Time to live after workflow completion
122     secondsAfterSuccess: 6000     # 100 minutes - Time to live after successful execution
123     secondsAfterFailure: 9000     # 150 minutes - Extended time for failure analysis
124
125   # Main entry point for the workflow template
126   entrypoint: app-management
127
128   templates:
129   # === Main Application Management Template ===
130   # This template orchestrates the complete application lifecycle management process
131   # using a volume-based approach for application models and parameters.
132   - name: app-management
133     inputs:
134       parameters:
135       # Core operation configuration
136       - name: command
137       # Volume-based data sources
138       - name: model_volume_name
139       - name: secret_name
140       # Git repository configuration for Fleet and SW-Catalogs
141       - name: git_fleet_url
142       - name: fleet_destination_folder
143       - name: git_fleet_cred_secret
144       - name: git_sw_catalogs_url
145       - name: sw_catalogs_destination_folder
146       - name: git_sw_catalogs_cred_secret
147       # Target deployment configuration
148       - name: app_name
149       - name: profile_name
150       - name: profile_type
151       - name: project_name
152       # OSM SDK container configuration with standardized defaults
153       - name: osm_sdk_image_repository
154       - name: osm_sdk_image_tag
155       # Workflow execution control flags
156       - name: debug
157       - name: dry_run
158
159     steps:
160     # === PHASE 1: Parameter Validation ===
161     # Validate that all required parameters are provided for volume-based workflow execution
162     - - name: validate-parameters
163         inline:
164           container:
165             image: alpine:latest
166             command: [sh, -c]
167             args:
168               - |
169                 set -e
170                 echo "=== Volume-Based Workflow Parameter Validation ==="
171                 echo "Validating required parameters for application management..."
172
173                 # Validate core volume parameter
174                 if [ -z "{{inputs.parameters.model_volume_name}}" ]; then
175                   echo "ERROR: model_volume_name parameter is required for volume-based workflow"
176                   echo "Please provide a PVC name containing the application model and parameters"
177                   exit 1
178                 fi
179
180                 # Validate Git repository parameters
181                 if [ -z "{{inputs.parameters.git_fleet_url}}" ]; then
182                   echo "ERROR: git_fleet_url parameter is required for Fleet repository access"
183                   exit 1
184                 fi
185
186                 if [ -z "{{inputs.parameters.git_sw_catalogs_url}}" ]; then
187                   echo "ERROR: git_sw_catalogs_url parameter is required for SW-Catalogs repository access"
188                   exit 1
189                 fi
190
191                 # Validate target deployment parameters
192                 if [ -z "{{inputs.parameters.app_name}}" ]; then
193                   echo "ERROR: app_name parameter is required for application identification"
194                   exit 1
195                 fi
196
197                 if [ -z "{{inputs.parameters.profile_name}}" ]; then
198                   echo "ERROR: profile_name parameter is required for deployment profile"
199                   exit 1
200                 fi
201
202                 echo "✓ All required parameters validated successfully"
203                 echo "Configuration Summary:"
204                 echo "  Command: {{inputs.parameters.command}}"
205                 echo "  Model Volume: {{inputs.parameters.model_volume_name}}"
206                 echo "  Secret Name: {{inputs.parameters.secret_name}}"
207                 echo "  Application: {{inputs.parameters.app_name}}"
208                 echo "  Profile: {{inputs.parameters.profile_name}} ({{inputs.parameters.profile_type}})"
209                 echo "  Project: {{inputs.parameters.project_name}}"
210                 echo "  OSM SDK: {{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
211                 echo "  Debug Mode: {{inputs.parameters.debug}}"
212                 echo "  Dry Run: {{inputs.parameters.dry_run}}"
213     
214     # === PHASE 2: Volume Preparation ===
215     # Generate temporary volumes for Git repository operations
216     # These volumes will store cloned Fleet and SW-Catalogs repositories during workflow execution
217     - - name: generate-fleet-volume-repo
218         templateRef:
219           name: k8s-resources-wft
220           template: generate-volume
221         arguments:
222           parameters:
223             - name: pvc-size
224               value: '100Mi'  # Sufficient space for Fleet repository content
225       - name: generate-sw-catalogs-volume-repo
226         templateRef:
227           name: k8s-resources-wft
228           template: generate-volume
229         arguments:
230           parameters:
231             - name: pvc-size
232               value: '100Mi'  # Sufficient space for SW-Catalogs repository content
233     
234     # === PHASE 3: Git Repository Cloning ===
235     # Clone the required Git repositories for application modeling and deployment
236     # These repositories provide the templates and target locations for GitOps operations
237     - - name: clone-fleet
238         templateRef:
239           name: git-wft
240           template: git-clone
241         arguments:
242           parameters:
243           - name: mount_path
244             value: "/fleet"
245           - name: repo_url
246             value: "{{inputs.parameters.git_fleet_url}}"
247           - name: destination_folder
248             value: "{{inputs.parameters.fleet_destination_folder}}"
249           - name: git_cred_secret
250             value: "{{inputs.parameters.git_fleet_cred_secret}}"
251           - name: git_volume_name
252             value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
253       - name: clone-sw-catalogs
254         templateRef:
255           name: git-wft
256           template: git-clone
257         arguments:
258           parameters:
259           - name: mount_path
260             value: "/sw-catalogs"
261           - name: repo_url
262             value: "{{inputs.parameters.git_sw_catalogs_url}}"
263           - name: destination_folder
264             value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
265           - name: git_cred_secret
266             value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
267           - name: git_volume_name
268             value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
269
270     # === PHASE 4: Debug Information (Optional) ===
271     # Comprehensive debugging information for volume-based workflow troubleshooting
272     # Executed only when debug parameter is set to true
273     - - name: debug-info
274         when: "{{inputs.parameters.debug}} == true"
275         inline:
276           container:
277             image: "{{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
278             args:
279               - "nu"
280               - "-c"
281               - |
282                 echo "=== OSM App Modeling Debug Information (Volume-Based) ==="
283                 echo $"Command: {{inputs.parameters.command}}"
284                 echo $"SDK Image: {{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
285                 echo $"Model Volume: {{inputs.parameters.model_volume_name}}"
286                 echo $"Secret Name: {{inputs.parameters.secret_name}}"
287                 echo $"Timestamp: (date now | format date '%Y-%m-%d %H:%M:%S')"
288                 echo ""
289
290                 echo "=== Volume Mount Status and Accessibility ==="
291                 echo "Checking volume mount accessibility..."
292
293                 # Check model volume mount
294                 echo "Model volume mount status:"
295                 if (ls /model | length) > 0 {
296                   echo "✓ Model volume mounted successfully at /model"
297                   echo $"  Files found: (ls /model | length)"
298                 } else {
299                   echo "✗ Model volume mount failed or empty"
300                 }
301
302                 # Check fleet volume mount
303                 echo "Fleet volume mount status:"
304                 if (ls /repos/fleet-osm | length) > 0 {
305                   echo "✓ Fleet volume mounted successfully at /repos/fleet-osm"
306                   echo $"  Files found: (ls /repos/fleet-osm | length)"
307                 } else {
308                   echo "✗ Fleet volume mount failed or empty"
309                 }
310
311                 # Check sw-catalogs volume mount
312                 echo "SW-Catalogs volume mount status:"
313                 if (ls /repos/sw-catalogs-osm | length) > 0 {
314                   echo "✓ SW-Catalogs volume mounted successfully at /repos/sw-catalogs-osm"
315                   echo $"  Files found: (ls /repos/sw-catalogs-osm | length)"
316                 } else {
317                   echo "✗ SW-Catalogs volume mount failed or empty"
318                 }
319                 echo ""
320
321                 echo "=== Model Volume Contents and Structure ==="
322                 echo "Model volume directory structure:"
323                 try {
324                   ls /model -la | select name type size permissions | table
325                 } catch {
326                   echo "Error accessing model volume contents"
327                 }
328                 echo ""
329
330                 echo "=== Required Model Files Validation ==="
331                 # Check app_instance_model.yaml
332                 if ("/model/app_instance_model.yaml" | path exists) {
333                   echo "✓ app_instance_model.yaml found"
334                   try {
335                     let file_size = (ls /model/app_instance_model.yaml | get size | first)
336                     echo $"  Size: ($file_size) bytes"
337                   } catch {
338                     echo "  Warning: Could not read file size"
339                   }
340                 } else {
341                   echo "✗ app_instance_model.yaml missing"
342                 }
343
344                 # Check clear parameters
345                 if ("/model/parameters/clear/environment.yaml" | path exists) {
346                   echo "✓ Clear parameters file found"
347                   try {
348                     let file_size = (ls /model/parameters/clear/environment.yaml | get size | first)
349                     echo $"  Size: ($file_size) bytes"
350                   } catch {
351                     echo "  Warning: Could not read file size"
352                   }
353                 } else {
354                   echo "ℹ Clear parameters file missing (optional)"
355                 }
356
357                 # Check secret parameters
358                 if ("/model/parameters/secret/environment.yaml" | path exists) {
359                   echo "✓ Secret parameters file found"
360                   try {
361                     let file_size = (ls /model/parameters/secret/environment.yaml | get size | first)
362                     echo $"  Size: ($file_size) bytes"
363                   } catch {
364                     echo "  Warning: Could not read file size"
365                   }
366                 } else {
367                   echo "ℹ Secret parameters file missing (optional)"
368                 }
369
370                 echo "=== Model Content Analysis ==="
371                 echo "App Instance Model (first 30 lines):"
372                 try {
373                   open /model/app_instance_model.yaml | lines | first 30 | str join "\n"
374                 } catch {
375                   echo "Error reading app_instance_model.yaml"
376                 }
377                 echo ""
378
379                 echo "Clear Parameters Content:"
380                 try {
381                   open /model/parameters/clear/environment.yaml | to yaml
382                 } catch {
383                   echo "Clear parameters not available"
384                 }
385                 echo ""
386
387                 echo "Secret Parameters Content (masked for security):"
388                 try {
389                   if ("/model/parameters/secret/environment.yaml" | path exists) {
390                     echo "Secret file exists - content masked for security"
391                   } else {
392                     echo "Secret parameters not available"
393                   }
394                 } catch {
395                   echo "Error checking secret parameters"
396                 }
397                 echo ""
398
399                 echo "=== Loaded Model Instance from Volume ==="
400                 try {
401                   $model_instance | to yaml | lines | first 30 | str join "\n"
402                 } catch {
403                   echo "Error loading model instance"
404                 }
405                 echo ""
406
407                 echo "=== Environment Parameters from Volume ==="
408                 try {
409                   $environment | to yaml | lines | first 30 | str join "\n"
410                 } catch {
411                   echo "Error loading environment"
412                 }
413                 echo ""
414
415                 echo "=== Repository Structure ==="
416                 echo "Fleet repo contents:"
417                 try {
418                   ls /repos/fleet-osm | select name type size | first 10 | table
419                 } catch {
420                   echo "Error accessing fleet repository"
421                 }
422                 echo ""
423                 echo "SW-Catalogs repo contents:"
424                 try {
425                   ls /repos/sw-catalogs-osm | select name type size | first 10 | table
426                 } catch {
427                   echo "Error accessing sw-catalogs repository"
428                 }
429                 echo ""
430
431                 echo "=== Embedded Operations Validation ==="
432                 echo "App Operations Library Status:"
433                 try {
434                   help app | lines | first 10 | str join "\n"
435                 } catch {
436                   echo "Error accessing app operations library"
437                 }
438                 echo ""
439
440                 echo "=== Dry Run Test ==="
441                 echo "Testing command execution with volume-mounted data..."
442                 try {
443                   echo $"Command to execute: {{inputs.parameters.command}}"
444                   echo "✓ Command validation successful with volume-based data"
445                 } catch {
446                   echo $"✗ Command validation failed: ($in)"
447                 }
448                 echo ""
449
450                 echo "=== Volume Permissions Check ==="
451                 echo "Model volume permissions:"
452                 try {
453                   ls -la /model | head -5 | each { |item| echo $"  ($item.name): ($item.permissions)" } | str join "\n"
454                 } catch {
455                   echo "Error checking model volume permissions"
456                 }
457                 echo ""
458
459                 echo "=== Debug Information Complete ==="
460             volumeMounts:
461             - name: model-volume
462               mountPath: /model
463             - name: fleet-volume
464               mountPath: /repos/fleet-osm
465               subPath: fleet-osm
466             - name: sw-catalogs-volume
467               mountPath: /repos/sw-catalogs-osm
468               subPath: sw-catalogs-osm
469             # Mount secret volume when secret_name is provided
470             - name: secret-volume
471               mountPath: /model/parameters/secret
472               readOnly: true
473           volumes:
474           - name: model-volume
475             persistentVolumeClaim:
476               claimName: "{{inputs.parameters.model_volume_name}}"
477           - name: fleet-volume
478             persistentVolumeClaim:
479               claimName: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
480           - name: sw-catalogs-volume
481             persistentVolumeClaim:
482               claimName: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
483           - name: secret-volume
484             secret:
485               secretName: "{{inputs.parameters.secret_name}}"
486               optional: true
487
488     # === PHASE 5: Application Operations ===
489     # This phase performs the actual create/update/delete operations on the application model
490     - - name: run-app-operation
491         when: "{{inputs.parameters.dry_run}} != true"
492         inline:
493           container:
494             image: "{{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
495             args: ["{{inputs.parameters.command}}"]         # Full command string to execute
496             volumeMounts:
497             # Mount model volume containing application data
498             - name: model-volume
499               mountPath: /model
500             # Mount Fleet repository for GitOps target
501             - name: fleet-volume
502               mountPath: /repos/fleet-osm
503               subPath: fleet-osm
504             # Mount SW-Catalogs repository for application templates
505             - name: sw-catalogs-volume
506               mountPath: /repos/sw-catalogs-osm
507               subPath: sw-catalogs-osm
508             # Mount secret volume when secret_name is provided
509             - name: secret-volume
510               mountPath: /model/parameters/secret
511               readOnly: true
512           volumes:
513           - name: model-volume
514             persistentVolumeClaim:
515               claimName: "{{inputs.parameters.model_volume_name}}"
516           - name: fleet-volume
517             persistentVolumeClaim:
518               claimName: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
519           - name: sw-catalogs-volume
520             persistentVolumeClaim:
521               claimName: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
522           - name: secret-volume
523             secret:
524               secretName: "{{inputs.parameters.secret_name}}"
525               optional: true
526       # Dry-run variant of the app operation for validation without changes
527       - name: run-app-operation-dry-run
528         when: "{{inputs.parameters.dry_run}} == true"
529         inline:
530           container:
531             image: "{{inputs.parameters.osm_sdk_image_repository}}:{{inputs.parameters.osm_sdk_image_tag}}"
532             args: ["{{inputs.parameters.command}} --dry-run"] # Full command string with dry-run flag
533             volumeMounts:
534             # Same volume mounts as regular operation for consistency
535             - name: model-volume
536               mountPath: /model
537             - name: fleet-volume
538               mountPath: /repos/fleet-osm
539               subPath: fleet-osm
540             - name: sw-catalogs-volume
541               mountPath: /repos/sw-catalogs-osm
542               subPath: sw-catalogs-osm
543             # Mount secret volume when secret_name is provided
544             - name: secret-volume
545               mountPath: /model/parameters/secret
546               readOnly: true
547           volumes:
548           - name: model-volume
549             persistentVolumeClaim:
550               claimName: "{{inputs.parameters.model_volume_name}}"
551           - name: fleet-volume
552             persistentVolumeClaim:
553               claimName: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
554           - name: sw-catalogs-volume
555             persistentVolumeClaim:
556               claimName: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
557           - name: secret-volume
558             secret:
559               secretName: "{{inputs.parameters.secret_name}}"
560               optional: true
561
562     # === PHASE 7: GitOps Commit and Push ===
563     # Commit and push the generated application manifests to the Fleet repository
564     # This completes the GitOps workflow by updating the target repository with changes
565     - - name: push-to-fleet
566         templateRef:
567           name: git-wft
568           template: git-commit-merge-push
569         arguments:
570           parameters:
571           - name: mount_path
572             value: "/fleet"
573           - name: repo_folder
574             value: "{{inputs.parameters.fleet_destination_folder}}"
575           - name: git_cred_secret
576             value: "{{inputs.parameters.git_fleet_cred_secret}}"
577           - name: git_volume_name
578             value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
579           - name: commit_message
580             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]"
581           - name: main_branch
582             value: main
583           - name: contrib_branch
584             value: osm_contrib
585           - name: dry_run
586             value: "{{inputs.parameters.dry_run}}"