From 1f90b30a9560cce3171c42f430d27991890484b3 Mon Sep 17 00:00:00 2001 From: cloudguruab Date: Thu, 14 May 2026 01:47:27 +0200 Subject: [PATCH] fix: write heat-stack-info.txt from Go module at the configured output_dir The Ansible copy task used delegate_to: localhost which wrote the file to the controller host rather than where the module runs, causing the reported path to never match the actual file location. Move file writing into create_heat_stack.go via a new output_dir parameter so the file is always created on the same host and at the exact path the user configured. Co-authored-by: Cursor --- plugins/modules/create_heat_stack.py | 11 +++++ .../create_heat_stack/create_heat_stack.go | 22 ++++++++-- roles/import_workloads/tasks/heat_deploy.yml | 41 +------------------ 3 files changed, 31 insertions(+), 43 deletions(-) diff --git a/plugins/modules/create_heat_stack.py b/plugins/modules/create_heat_stack.py index 94501ef6..3ae63053 100644 --- a/plugins/modules/create_heat_stack.py +++ b/plugins/modules/create_heat_stack.py @@ -45,6 +45,12 @@ required: false type: int default: 600 + output_dir: + description: + - Directory where heat-stack-info.txt will be written after successful stack creation. + - When set, the file is written on the same host that runs the module, at the exact path specified. + required: false + type: str """ EXAMPLES = r""" @@ -72,4 +78,9 @@ returned: success type: dict sample: {"id": "stack-uuid", "name": "os-migrate-20240120", "status": "CREATE_COMPLETE"} +info_path: + description: Path to the written heat-stack-info.txt file + returned: when output_dir is provided + type: str + sample: "/opt/os-migrate/heat-stack-info.txt" """ diff --git a/plugins/modules/src/create_heat_stack/create_heat_stack.go b/plugins/modules/src/create_heat_stack/create_heat_stack.go index 4c09fa29..987d59da 100644 --- a/plugins/modules/src/create_heat_stack/create_heat_stack.go +++ b/plugins/modules/src/create_heat_stack/create_heat_stack.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "time" "vmware-migration-kit/plugins/module_utils/ansible" @@ -40,6 +41,7 @@ type ModuleArgs struct { Parameters map[string]interface{} `json:"parameters"` Wait bool `json:"wait"` Timeout int `json:"timeout"` + OutputDir string `json:"output_dir"` } type StackInfo struct { @@ -49,10 +51,11 @@ type StackInfo struct { } type Response struct { - Msg string `json:"msg"` - Changed bool `json:"changed"` - Failed bool `json:"failed"` - Stack StackInfo `json:"stack,omitempty"` + Msg string `json:"msg"` + Changed bool `json:"changed"` + Failed bool `json:"failed"` + Stack StackInfo `json:"stack,omitempty"` + InfoPath string `json:"info_path,omitempty"` } func exitJson(responseBody Response) { @@ -216,5 +219,16 @@ func main() { Status: finalStack.Status, }, } + + if moduleArgs.OutputDir != "" { + infoPath := filepath.Join(moduleArgs.OutputDir, "heat-stack-info.txt") + content := fmt.Sprintf("Stack Name: %s\nStack ID: %s\nStatus: %s\nTemplate: %s\n", + finalStack.Name, finalStack.ID, finalStack.Status, moduleArgs.TemplatePath) + if err := os.WriteFile(infoPath, []byte(content), 0644); err != nil { + ansible.FailJson(ansible.Response{Msg: "Failed to write stack info file: " + err.Error()}) + } + response.InfoPath = infoPath + } + exitJson(response) } diff --git a/roles/import_workloads/tasks/heat_deploy.yml b/roles/import_workloads/tasks/heat_deploy.yml index d8ad0558..526cbdd0 100644 --- a/roles/import_workloads/tasks/heat_deploy.yml +++ b/roles/import_workloads/tasks/heat_deploy.yml @@ -86,6 +86,7 @@ parameters: "{{ heat_template_generated.parameters }}" wait: true timeout: 600 + output_dir: "{{ os_migrate_vmw_data_dir }}" register: heat_stack_created when: import_workloads_heat_auto_deploy | default(true) | bool @@ -101,45 +102,7 @@ View events: openstack stack event list {{ heat_stack_created.stack.id }} when: heat_stack_created is defined and not heat_stack_created.failed -- name: Save Heat stack information to file - ansible.builtin.copy: - content: | - # Heat Stack Information - Stack Name: {{ heat_stack_created.stack.name }} - Stack ID: {{ heat_stack_created.stack.id }} - Status: {{ heat_stack_created.stack.status }} - Template: {{ heat_template_generated.template_path }} - - ## Migrated VMs - {% for vm in heat_vms_data %} - - {{ vm.name }}: - Boot Volume: {{ vm.boot_volume_id }} - Flavor: {{ vm.flavor }} - Network: {{ vm.network }} - {% endfor %} - - ## Heat Management Commands - # View stack details - openstack stack show {{ heat_stack_created.stack.id }} - - # List stack resources - openstack stack resource list {{ heat_stack_created.stack.id }} - - # View stack events - openstack stack event list {{ heat_stack_created.stack.id }} - - # Update stack (with template changes) - openstack stack update {{ heat_stack_created.stack.id }} -t {{ heat_template_generated.template_path }} - - # Delete stack (WARNING: This will delete managed resources - instances and ports) - # Note: Cinder volumes are external and will NOT be deleted - openstack stack delete {{ heat_stack_created.stack.id }} - dest: "{{ os_migrate_vmw_data_dir }}/heat-stack-info.txt" - mode: '0644' - when: heat_stack_created is defined and not heat_stack_created.failed - delegate_to: localhost - - name: Display saved stack info location ansible.builtin.debug: - msg: "Stack information saved to {{ os_migrate_vmw_data_dir }}/heat-stack-info.txt" + msg: "Stack information saved to {{ heat_stack_created.info_path }}" when: heat_stack_created is defined and not heat_stack_created.failed