Skip to content

Commit

Permalink
Merge branch 'main' into ay/feat/provider/resource/agent-group-assign…
Browse files Browse the repository at this point in the history
…ment/delete
  • Loading branch information
1riatsila1 authored Nov 13, 2024
2 parents a0ea530 + af5f89c commit e053812
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 75 deletions.
88 changes: 35 additions & 53 deletions internal/provider/resources/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,6 @@ type agentResourceModel struct {
PCapMode types.String `tfsdk:"pcap_mode"`
}

// TODO: Switch this to use the Client Model when that becomes available
type AgentResponseModel struct {
UID string
Serial string
Name string
ModelNumber string
WifiMacAddress string
EthernetMacAddress string
Notes string
PCapMode string
}

// TODO: Switch this to use the Client Model when that becomes available
type AgentUpdateRequestModel struct {
Name string
Notes string
PCapMode string
}

func NewAgentResource() resource.Resource {
return &agentResource{}
}
Expand Down Expand Up @@ -142,7 +123,7 @@ func (r *agentResource) Read(
request := r.client.ConfigurationAPI.
AgentsGet(ctx).
Id(state.ID.ValueString())
sensorResponse, response, err := util.RetryFor429(request.Execute)
agentResponse, response, err := util.RetryFor429(request.Execute)
errorPresent, errorDetail := util.RaiseForStatus(response, err)

errorSummary := util.GenerateErrorSummary("read", "uxi_agent")
Expand All @@ -152,16 +133,16 @@ func (r *agentResource) Read(
return
}

if len(sensorResponse.Items) != 1 {
if len(agentResponse.Items) != 1 {
resp.State.RemoveResource(ctx)
return
}
sensor := sensorResponse.Items[0]
agent := agentResponse.Items[0]

state.ID = types.StringValue(sensor.Id)
state.Name = types.StringValue(sensor.Name)
state.Notes = types.StringPointerValue(sensor.Notes.Get())
state.PCapMode = types.StringPointerValue(sensor.PcapMode.Get())
state.ID = types.StringValue(agent.Id)
state.Name = types.StringValue(agent.Name)
state.Notes = types.StringPointerValue(agent.Notes.Get())
state.PCapMode = types.StringPointerValue(agent.PcapMode.Get())

diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
Expand All @@ -183,18 +164,35 @@ func (r *agentResource) Update(
return
}

// Update existing item
response := UpdateAgent(AgentUpdateRequestModel{
Name: plan.Name.ValueString(),
Notes: plan.Notes.ValueString(),
PCapMode: plan.PCapMode.ValueString(),
})
patchRequest := config_api_client.NewAgentsPatchRequest()
patchRequest.Name = plan.Name.ValueStringPointer()
if !plan.Notes.IsUnknown() {
patchRequest.Notes = plan.Notes.ValueStringPointer()
}
if !plan.PCapMode.IsUnknown() {
patchRequest.PcapMode = plan.PCapMode.ValueStringPointer()
}
request := r.client.ConfigurationAPI.
AgentsPatch(ctx, plan.ID.ValueString()).
AgentsPatchRequest(*patchRequest)
agent, response, err := util.RetryFor429(request.Execute)

// Update resource state with updated items
plan.ID = types.StringValue(response.UID)
plan.Name = types.StringValue(response.Name)
plan.Notes = types.StringValue(response.Notes)
plan.PCapMode = types.StringValue(response.PCapMode)
errorPresent, errorDetail := util.RaiseForStatus(response, err)

if errorPresent {
resp.Diagnostics.AddError(util.GenerateErrorSummary("update", "uxi_agent"), errorDetail)
return
}

// Update the state to match the plan (replace with response from client)
plan.ID = types.StringValue(agent.Id)
plan.Name = types.StringValue(agent.Name)
if agent.Notes.Get() != nil {
plan.Notes = types.StringValue(*agent.Notes.Get())
}
if agent.PcapMode.Get() != nil {
plan.PCapMode = types.StringValue(*agent.PcapMode.Get())
}

// Set state to fully populated data
diags = resp.State.Set(ctx, plan)
Expand Down Expand Up @@ -235,19 +233,3 @@ func (r *agentResource) ImportState(
) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

// Update the agent using the configuration-api client
var UpdateAgent = func(request AgentUpdateRequestModel) AgentResponseModel {
// TODO: Query the agent using the client

return AgentResponseModel{
UID: "mock_uid",
Serial: "mock_serial",
Name: request.Name,
ModelNumber: "mock_model_number",
WifiMacAddress: "mock_wifi_mac_address",
EthernetMacAddress: "mock_ethernet_mac_address",
Notes: request.Notes,
PCapMode: request.PCapMode,
}
}
87 changes: 83 additions & 4 deletions test/mocked/resources/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"regexp"
"testing"

"github.com/aruba-uxi/terraform-provider-hpeuxi/internal/provider/resources"
"github.com/aruba-uxi/terraform-provider-hpeuxi/test/mocked/provider"
"github.com/aruba-uxi/terraform-provider-hpeuxi/test/mocked/util"
"github.com/h2non/gock"
Expand Down Expand Up @@ -90,9 +89,12 @@ func TestAgentResource(t *testing.T) {
),
1,
)
resources.UpdateAgent = func(request resources.AgentUpdateRequestModel) resources.AgentResponseModel {
return util.GenerateMockedAgentResponseModel("uid", "_2")
}
util.MockUpdateAgent(
"uid",
util.GenerateAgentRequestUpdateModel("_2"),
util.GenerateAgentResponseModel("uid", "_2"),
1,
)
// updated
util.MockGetAgent(
"uid",
Expand Down Expand Up @@ -175,6 +177,50 @@ func TestAgentResource429Handling(t *testing.T) {
},
),
},
// Update testing
{
PreConfig: func() {
// original
util.MockGetAgent(
"uid",
util.GeneratePaginatedResponse(
[]map[string]interface{}{util.GenerateAgentResponseModel("uid", "")},
),
1,
)
request429 = gock.New("https://test.api.capenetworks.com").
Patch("/networking-uxi/v1alpha1/agents").
Reply(429).
SetHeaders(util.RateLimitingHeaders)
util.MockUpdateAgent(
"uid",
util.GenerateAgentRequestUpdateModel("_2"),
util.GenerateAgentResponseModel("uid", "_2"),
1,
)
// updated
util.MockGetAgent(
"uid",
util.GeneratePaginatedResponse(
[]map[string]interface{}{util.GenerateAgentResponseModel("uid", "_2")},
),
1,
)
},
Config: provider.ProviderConfig + `
resource "uxi_agent" "my_agent" {
name = "name_2"
notes = "notes_2"
pcap_mode = "light_2"
}`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("uxi_agent.my_agent", "name", "name_2"),
func(s *terraform.State) error {
st.Assert(t, request429.Mock.Request().Counter, 0)
return nil
},
),
},
// Delete testing
{
PreConfig: func() {
Expand Down Expand Up @@ -292,6 +338,39 @@ func TestAgentResourceHttpErrorHandling(t *testing.T) {
resource.TestCheckResourceAttr("uxi_agent.my_agent", "id", "uid"),
),
},
// update 4xx
{
PreConfig: func() {
// original
util.MockGetAgent(
"uid",
util.GeneratePaginatedResponse(
[]map[string]interface{}{util.GenerateAgentResponseModel("uid", "")},
),
1,
)
// patch agent - with error
gock.New("https://test.api.capenetworks.com").
Patch("/networking-uxi/v1alpha1/agents/uid").
Reply(422).
JSON(map[string]interface{}{
"httpStatusCode": 422,
"errorCode": "HPE_GL_UXI_INVALID_PCAP_MODE_ERROR",
"message": "Unable to update agent - pcap_mode must be one the following ['light', 'full', 'off'].",
"debugId": "12312-123123-123123-1231212",
"type": "hpe.greenlake.uxi.invalid_pcap_mode",
})
},
Config: provider.ProviderConfig + `
resource "uxi_agent" "my_agent" {
name = "name_2"
notes = "notes_2"
pcap_mode = "light_2"
}`,
ExpectError: regexp.MustCompile(
`(?s)Unable to update agent - pcap_mode must be one the following \['light',\s*'full', 'off'\].\s*DebugID: 12312-123123-123123-1231212`,
),
},
// Delete 4xx
{
PreConfig: func() {
Expand Down
45 changes: 27 additions & 18 deletions test/mocked/util/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,21 @@ func GenerateSensorResponseModel(uid string, postfix string) map[string]interfac

func GenerateSensorRequestUpdateModel(postfix string) map[string]interface{} {
return map[string]interface{}{
"name": "name_2",
"name": "name" + postfix,
"addressNote": "address_note" + postfix,
"notes": "notes" + postfix,
"pcapMode": "light" + postfix,
}
}

func GenerateAgentRequestUpdateModel(postfix string) map[string]interface{} {
return map[string]interface{}{
"name": "name" + postfix,
"notes": "notes" + postfix,
"pcapMode": "light" + postfix,
}
}

func GenerateAgentResponseModel(uid string, postfix string) map[string]interface{} {
return map[string]interface{}{
"id": uid,
Expand All @@ -47,19 +55,6 @@ func GenerateAgentResponseModel(uid string, postfix string) map[string]interface
}
}

func GenerateMockedAgentResponseModel(uid string, postfix string) resources.AgentResponseModel {
return resources.AgentResponseModel{
UID: uid,
Serial: "serial" + postfix,
Name: "name" + postfix,
ModelNumber: "model_number" + postfix,
WifiMacAddress: "wifi_mac_address" + postfix,
EthernetMacAddress: "ethernet_mac_address" + postfix,
Notes: "notes" + postfix,
PCapMode: "light" + postfix,
}
}

func GenerateNonRootGroupResponseModel(
uid string,
nonReplacementFieldPostfix string,
Expand Down Expand Up @@ -252,6 +247,22 @@ func MockDeleteAgent(uid string, times int) {
Reply(204)
}

func MockUpdateAgent(
uid string,
request map[string]interface{},
response map[string]interface{},
times int,
) {
gock.New("https://test.api.capenetworks.com").
Patch("/networking-uxi/v1alpha1/agents/"+uid).
MatchHeader("Content-Type", "application/merge-patch+json").
MatchHeader("Authorization", "mock_token").
JSON(request).
Times(times).
Reply(200).
JSON(response)
}

func MockPostGroup(request map[string]interface{}, response map[string]interface{}, times int) {
gock.New("https://test.api.capenetworks.com").
Post("/networking-uxi/v1alpha1/groups").
Expand Down Expand Up @@ -314,13 +325,11 @@ func MockUpdateSensor(
response map[string]interface{},
times int,
) {
// body, _ := json.Marshal(request)
gock.New("https://test.api.capenetworks.com").
Patch("/networking-uxi/v1alpha1/sensors/"+uid).
// TODO: uncomment this once the patch endpoint uses correct header and body casing
// MatchHeader("Content-Type", "application/merge-patch+json").
MatchHeader("Content-Type", "application/merge-patch+json").
MatchHeader("Authorization", "mock_token").
// BodyString(string(body)).
JSON(request).
Times(times).
Reply(200).
JSON(response)
Expand Down

0 comments on commit e053812

Please sign in to comment.