Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add fmc_deploy #210

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
WIP: code for delete resource (rollback)
  • Loading branch information
wojciech-bainhelixpe committed Dec 6, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 25e964c19348b9fc23917ce2be17d5b4097f519d
5 changes: 2 additions & 3 deletions gen/definitions/deploy_device.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
name: Deployment
rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/deployment/deploymentrequests
no_delete: true
no_update: true
no_data_source: true
no_import: true
@@ -30,8 +29,8 @@ attributes:
description: Ignore warnings during deployment.
mandatory: false
exclude_example: true
test_value: true
minimum_test_value: true
test_value: "true"
minimum_test_value: "true"
- model_name: deviceList
tf_name: device_list
type: List
155 changes: 148 additions & 7 deletions internal/provider/resource_fmc_deployment.go
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@ import (
"encoding/json"
"fmt"

// "net/url"

// "net/url"
"strings"

@@ -219,6 +221,7 @@ JobIdLookup:
continue
}

// *** It has to be fixed to add device list rather than single device
deviceList, ok := itemMap["deviceList"].([]interface{})

jobId, ok := itemMap["id"].(string)
@@ -238,6 +241,7 @@ JobIdLookup:
continue
}

// *** It has to be fixed to add device list rather than single device
if contains(interfaceUUIDList, deviceUUID) {
plan.Id = types.StringValue(jobId)
matchingData = append(matchingData, deviceMap)
@@ -298,7 +302,7 @@ func resJson2Map(res gjson.Result) (map[string]interface{}, error) {
return resMap, nil
}

// Fubnction to check if item belongs to list
// Function to check if item belongs to list
func contains(list []string, item string) bool {
for _, v := range list {
if v == item {
@@ -536,8 +540,6 @@ func (r *DeploymentResource) Update(ctx context.Context, req resource.UpdateRequ

// End of section. //template:end update

// Section below is generated&owned by "gen/generator.go". //template:begin delete

func (r *DeploymentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state Deployment

@@ -554,13 +556,152 @@ func (r *DeploymentResource) Delete(ctx context.Context, req resource.DeleteRequ
}

tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString()))
// res, err := r.client.Delete(state.getPath()+"/"+url.QueryEscape(state.Id.ValueString()), reqMods...)
// if err != nil {
// resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to delete object (DELETE), got error: %s, %s", err, res.String()))
// return
// }

// As there are no DELETE api call for /api/fmc_config/v1/domain/{domainUUID}/deployment/deploymentrequests
// we can only roblback deployemnt to previous state
// we can use /api/fmc_config/v1/domain/{domainUUID}/deployment/rollbackrequests to execute rolback
// first we need to get deployemnt id and device list from state
// next get deployemnt job id to rollback to, it can be retrieved from deployemnt job history
// /api/fmc_config/v1/domain/{domainUUID}/deployment/jobhistories API
// next initiate rollback api and wait until the job is finished

// Get data from state
stateDeviceList, err := extractDeviceList(state.DeviceList)
if err != nil {
tflog.Debug(ctx, fmt.Sprintf("%s: Error getting device list from state", ""))
return
}
stateDeploymentJobId := state.Id.String()
var rollbackToDeploymentJobId string

tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString()))
// Read deployment history
urlPath := "/api/fmc_config/v1/domain/{DOMAIN_UUID}/deployment/jobhistories?expanded=true"
res, err := r.client.Get(urlPath, reqMods...)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to read deployment history (POST/PUT), got error: %s, %s", err, res.String()))
return
}
resMap, err := resJson2Map(res)
if err != nil {
tflog.Debug(ctx, fmt.Sprintf("%s: Error getting job histories", ""))
return
}

resp.State.RemoveResource(ctx)
}
// Access "items"
items, ok := resMap["items"].([]interface{})
if !ok {
tflog.Debug(ctx, fmt.Sprintf("%s: Error: 'items' is not a valid array", ""))
}

// Iterate over items to find JobID for rollback based on latest deployment job id and devices UUID
// stateDeploymentJobId
JobIdLookup:
for _, item := range items {
itemMap, ok := item.(map[string]interface{})
if !ok {
continue
}

if itemMap["jobType"].(interface{}).(string) != "DEPLOYMENT" {
continue
}

if (itemMap["jobId"].(interface{}).(string) != stateDeploymentJobId) || (rollbackToDeploymentJobId == "") {
continue
}

// End of section. //template:end delete
deviceList, ok := itemMap["deviceList"].([]interface{})
if !ok {
continue
}

// Iterate over deviceData to check deviceUUID belongs to deployment
for _, device := range deviceList {
deviceMap, ok := device.(map[string]interface{})
if !ok {
continue
}

// *** It has to be fixed to add device list rather than single device
deviceUUID, ok := deviceMap["deviceUUID"].(interface{}).(string)
if !ok {
continue
}

// *** It has to be fixed to add device list rather than single device
if contains(stateDeviceList, deviceUUID) {
// set rollbackToDeploymentJobId to be equal fo stateDeploymentJobId
// and continuse to iterate to find previous deployemnt
if rollbackToDeploymentJobId == "" {
rollbackToDeploymentJobId = stateDeploymentJobId
continue
} else {
rollbackToDeploymentJobId = itemMap["jobId"].(interface{}).(string)
break JobIdLookup
}
}
}
}

// Trigger rollback
if rollbackToDeploymentJobId != "" {

urlPath = "/api/fmc_config/v1/domain/{domainUUID}/deployment/rollbackrequests"
body := `{ ` + "\n"
body += ` "type": "RollbackRequest",` + "\n"
body += ` "rollbackDeviceList": [` + "\n"
body += ` {` + "\n"
body += ` "deploymentJobId": "` + rollbackToDeploymentJobId + `",` + "\n"
// *** It has to be fixed to add device list rather than single device
body += ` "deviceList": [` + "\n"
body += ` "` + stateDeviceList[0] + `"` + "\n"
body += ` ]` + "\n"
body += ` }` + "\n"
body += ` ]` + "\n"
body += `}` + "\n"

res, err = r.client.Post(urlPath, body, reqMods...)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String()))
return
}

resDeployment, err := resJson2Map(res)
if err != nil {
tflog.Debug(ctx, fmt.Sprintf("%s: Error getting task url", ""))
return
}
deploymentTaskId := resDeployment["metadata"].(map[string]interface{})["task"].(map[string]interface{})["id"].(interface{}).(string)

// Get task status
for {
urlPath := "/api/fmc_config/v1/domain/{DOMAIN_UUID}/job/taskstatuses/" + deploymentTaskId
res, err = r.client.Get(urlPath, reqMods...)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to read job task status (POST/PUT), got error: %s, %s", err, res.String()))
return
}
resTaskstaus, err := resJson2Map(res)
if err != nil {
tflog.Debug(ctx, fmt.Sprintf("%s: Error getting task status", ""))
return
}
if resTaskstaus["status"].(interface{}).(string) == "Deployed" {
break
}
}

tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString()))
resp.State.RemoveResource(ctx)
} else {
tflog.Debug(ctx, fmt.Sprintf("%s: Delete failed. Could not trigger rollback", state.Id.ValueString()))
}
}

// Section below is generated&owned by "gen/generator.go". //template:begin import
// End of section. //template:end import
Loading