Skip to content

Commit

Permalink
fmc_deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
rchrabas committed Jan 10, 2025
1 parent df94fda commit 9ed95df
Show file tree
Hide file tree
Showing 9 changed files with 671 additions and 0 deletions.
39 changes: 39 additions & 0 deletions docs/resources/deploy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "fmc_deploy Resource - terraform-provider-fmc"
subcategory: "Deployment"
description: |-
This resource can manage a Deploy.
---

# fmc_deploy (Resource)

This resource can manage a Deploy.

## Example Usage

```terraform
resource "fmc_deploy" "example" {
ignore_warning = false
device_list = ["2fe9063e-8bd5-11ef-9475-e4aeac78cf37"]
deployment_note = "Terraform initiated deployment"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `device_list` (List of String) List of device ids to be deployed.

### Optional

- `deployment_note` (String) User note.
- `domain` (String) The name of the FMC domain
- `ignore_warning` (Boolean) Ignore warnings during deployment.
- `version` (String) Version to which the deployment should be done in milliseconds unix timestamp. If not provided, the latest version will be used.

### Read-Only

- `id` (String) The id of the object
5 changes: 5 additions & 0 deletions examples/resources/fmc_deploy/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
resource "fmc_deploy" "example" {
ignore_warning = false
device_list = ["2fe9063e-8bd5-11ef-9475-e4aeac78cf37"]
deployment_note = "Terraform initiated deployment"
}
44 changes: 44 additions & 0 deletions gen/definitions/deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: Deploy
rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/deployment/deploymentrequests
no_data_source: true
no_import: true
no_delete: true
no_update: true
doc_category: Deployment
test_tags: [TF_VAR_device_id]
attributes:
- model_name: type
type: String
description: Type of the object; this value is always 'DeploymentRequest'
value: DeploymentRequest
- model_name: version
type: String
description: Version to which the deployment should be done in milliseconds unix timestamp. If not provided, the latest version will be used.
exclude_example: true
exclude_test: true
# Force deploy requires different way of obraining version, as no devices may be in deployable state
#- model_name: forceDeploy
# type: Bool
# description: Force deployment (deploy even if there are no configuration changes).
# example: "false"
- model_name: ignoreWarning
type: Bool
description: Ignore warnings during deployment.
example: "false"
exclude_test: true
- model_name: deviceList
type: List
description: List of device ids to be deployed.
mandatory: true
element_type: String
example: 2fe9063e-8bd5-11ef-9475-e4aeac78cf37
test_value: "[var.device_id]"
- model_name: deploymentNote
type: String
description: User note.
example: Terraform initiated deployment
exclude_test: true
test_prerequisites: |-
variable "device_id" { default = null } // tests will set $TF_VAR_device_id
52 changes: 52 additions & 0 deletions internal/provider/helpers/fmc_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// Licensed under the Mozilla Public 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
//
// https://mozilla.org/MPL/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.
//
// SPDX-License-Identifier: MPL-2.0

package helpers

import (
"context"
"fmt"
"net/url"
"strings"
"time"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/netascode/go-fmc"
)

func FMCWaitForJobToFinish(ctx context.Context, client *fmc.Client, jobId string, reqMods ...func(*fmc.Req)) diag.Diagnostics {
var diag diag.Diagnostics
const atom time.Duration = 5 * time.Second

for i := time.Duration(0); i < 5*time.Minute; i += atom {
task, err := client.Get("/api/fmc_config/v1/domain/{DOMAIN_UUID}/job/taskstatuses/"+url.QueryEscape(jobId), reqMods...)
if err != nil {
diag.AddError("Client Error", fmt.Sprintf("Failed to read object (GET), got error: %s, %s", err, task.String()))
return diag
}
stat := strings.ToUpper(task.Get("status").String())
if stat == "FAILED" {
diag.AddError("Client Error", fmt.Sprintf("API task for the new device failed: %s, %s", task.Get("message"), task.Get("description")))
return diag
}
if stat != "PENDING" && stat != "RUNNING" && stat != "IN_PROGRESS" && stat != "DEPLOYING" {
break
}
time.Sleep(atom)
}
return nil
}
8 changes: 8 additions & 0 deletions internal/provider/helpers/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ func GetStringList(result []gjson.Result) types.List {
return types.ListValueMust(types.StringType, v)
}

func GetStringListFromStringSlice(result []string) types.List {
v := make([]attr.Value, len(result))
for i, e := range result {
v[i] = types.StringValue(e)
}
return types.ListValueMust(types.StringType, v)
}

func GetInt64List(result []gjson.Result) types.List {
v := make([]attr.Value, len(result))
for r := range result {
Expand Down
153 changes: 153 additions & 0 deletions internal/provider/model_fmc_deploy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// Licensed under the Mozilla Public 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
//
// https://mozilla.org/MPL/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.
//
// SPDX-License-Identifier: MPL-2.0

package provider

// Section below is generated&owned by "gen/generator.go". //template:begin imports
import (
"context"

"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/netascode/terraform-provider-fmc/internal/provider/helpers"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
)

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

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

type Deploy struct {
Id types.String `tfsdk:"id"`
Domain types.String `tfsdk:"domain"`
Version types.String `tfsdk:"version"`
IgnoreWarning types.Bool `tfsdk:"ignore_warning"`
DeviceList types.List `tfsdk:"device_list"`
DeploymentNote types.String `tfsdk:"deployment_note"`
}

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

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

func (data Deploy) getPath() string {
return "/api/fmc_config/v1/domain/{DOMAIN_UUID}/deployment/deploymentrequests"
}

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

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

func (data Deploy) toBody(ctx context.Context, state Deploy) string {
body := ""
if data.Id.ValueString() != "" {
body, _ = sjson.Set(body, "id", data.Id.ValueString())
}
body, _ = sjson.Set(body, "type", "DeploymentRequest")
if !data.Version.IsNull() {
body, _ = sjson.Set(body, "version", data.Version.ValueString())
}
if !data.IgnoreWarning.IsNull() {
body, _ = sjson.Set(body, "ignoreWarning", data.IgnoreWarning.ValueBool())
}
if !data.DeviceList.IsNull() {
var values []string
data.DeviceList.ElementsAs(ctx, &values, false)
body, _ = sjson.Set(body, "deviceList", values)
}
if !data.DeploymentNote.IsNull() {
body, _ = sjson.Set(body, "deploymentNote", data.DeploymentNote.ValueString())
}
return body
}

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

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

func (data *Deploy) fromBody(ctx context.Context, res gjson.Result) {
if value := res.Get("version"); value.Exists() {
data.Version = types.StringValue(value.String())
} else {
data.Version = types.StringNull()
}
if value := res.Get("ignoreWarning"); value.Exists() {
data.IgnoreWarning = types.BoolValue(value.Bool())
} else {
data.IgnoreWarning = types.BoolNull()
}
if value := res.Get("deviceList"); value.Exists() {
data.DeviceList = helpers.GetStringList(value.Array())
} else {
data.DeviceList = types.ListNull(types.StringType)
}
if value := res.Get("deploymentNote"); value.Exists() {
data.DeploymentNote = types.StringValue(value.String())
} else {
data.DeploymentNote = types.StringNull()
}
}

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

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

// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to
// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might
// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the
// "managed" elements, instead of all elements.
func (data *Deploy) fromBodyPartial(ctx context.Context, res gjson.Result) {
if value := res.Get("version"); value.Exists() && !data.Version.IsNull() {
data.Version = types.StringValue(value.String())
} else {
data.Version = types.StringNull()
}
if value := res.Get("ignoreWarning"); value.Exists() && !data.IgnoreWarning.IsNull() {
data.IgnoreWarning = types.BoolValue(value.Bool())
} else {
data.IgnoreWarning = types.BoolNull()
}
if value := res.Get("deviceList"); value.Exists() && !data.DeviceList.IsNull() {
data.DeviceList = helpers.GetStringList(value.Array())
} else {
data.DeviceList = types.ListNull(types.StringType)
}
if value := res.Get("deploymentNote"); value.Exists() && !data.DeploymentNote.IsNull() {
data.DeploymentNote = types.StringValue(value.String())
} else {
data.DeploymentNote = types.StringNull()
}
}

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

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

// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON.
// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default).
func (data *Deploy) fromBodyUnknowns(ctx context.Context, res gjson.Result) {
}

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

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

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

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

// End of section. //template:end toBodyNonBulk
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ func (p *FmcProvider) Resources(ctx context.Context) []func() resource.Resource
return []func() resource.Resource{
NewAccessControlPolicyResource,
NewBFDTemplateResource,
NewDeployResource,
NewDeviceResource,
NewDeviceBFDResource,
NewDeviceBGPResource,
Expand Down
Loading

0 comments on commit 9ed95df

Please sign in to comment.