Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ test/pango: codegen assets
cd $(GENERATED_OUT_PATH)/pango && \
go test -v ./...

.PHONY: test/pango-movement
test/pango-movement: codegen assets
cd $(GENERATED_OUT_PATH)/pango && \
go test -v ./movement/

.PHONY: test/pango-example
test/pango-example:
cd $(GENERATED_OUT_PATH)/pango && \
Expand Down
11 changes: 10 additions & 1 deletion assets/terraform/internal/manager/uuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ func (o *UuidObjectManager[E, L, S]) ReadMany(ctx context.Context, location L, s
for idx, elt := range stateEntries {
stateEntriesByName[elt.EntryName()] = uuidObjectWithState[E]{
Entry: elt,
State: entryUnknown,
State: entryMissing,
StateIdx: idx,
}
}
Expand All @@ -661,10 +661,19 @@ func (o *UuidObjectManager[E, L, S]) ReadMany(ctx context.Context, location L, s
}

common := make([]E, commonCount)
var stateEntriesMissing bool
for _, elt := range stateEntriesByName {
if elt.State == entryOk {
common[elt.StateIdx] = elt.Entry
}

if elt.State == entryMissing {
stateEntriesMissing = true
}
}

if stateEntriesMissing {
return common, false, nil
}

actions, err := movement.MoveGroup(position, stateEntries, existing)
Expand Down
30 changes: 30 additions & 0 deletions assets/terraform/internal/manager/uuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,36 @@ var _ = Describe("Server", func() {
Expect(processed).To(MatchEntries(entries))
})
})

Context("when some of the entries were removed from the server", func() {
BeforeEach(func() {
initial = []*MockUuidObject{{Name: "1", Value: "A"}, {Name: "3", Value: "C"}}
client = NewMockUuidClient(initial)
service = NewMockUuidService[*MockUuidObject, MockLocation](client)
var ok bool
if mockService, ok = service.(*MockUuidService[*MockUuidObject, MockLocation]); !ok {
panic("failed to cast service to mockService")
}
manager = sdkmanager.NewUuidObjectManager(client, service, batchSize, MockUuidSpecifier, MockUuidMatcher)

})

It("should recreate missing entries on the server based on the state", func() {
entries := []*MockUuidObject{{Name: "1", Value: "A"}, {Name: "2", Value: "B"}, {Name: "3", Value: "C"}}

processed, moveRequired, err := manager.ReadMany(ctx, location, entries, sdkmanager.NonExhaustive, movement.PositionLast{})

Expect(err).ToNot(HaveOccurred())
Expect(moveRequired).To(BeFalse())
Expect(processed).To(HaveLen(2))

processed, err = manager.UpdateMany(ctx, location, []string{}, processed, entries, sdkmanager.NonExhaustive, movement.PositionLast{})
Expect(client.list()).To(HaveLen(3))
Expect(err).ToNot(HaveOccurred())
Expect(processed).To(HaveLen(3))
Expect(processed).To(MatchEntries(entries))
})
})
})

Context("initially has some entries", func() {
Expand Down
67 changes: 67 additions & 0 deletions assets/terraform/test/resource_security_policy_rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,73 @@ func TestAccSecurityPolicyRules_Hierarchy_UniqueNames(t *testing.T) {
testAccSecurityPolicyRules_Hierarchy(t, parentRules, childRules)
}

const securityPolicyRules_UpdateMissing_Tmpl = `
variable "prefix" { type = string }
variable "rule_names" { type = list(string) }

resource "panos_security_policy_rules" "policy" {
location = { device_group = { name = format("%s-dg", var.prefix) }}

position = { where = "first" }

rules = [
for index, name in var.rule_names: {
name = name

source_zones = ["any"]
source_addresses = ["any"]

destination_zones = ["any"]
destination_addresses = ["any"]

services = ["any"]
applications = ["any"]
}
]
}
`

func TestAccSecurityPolicyRules_UpdateMissing(t *testing.T) {
t.Parallel()

nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum)
prefix := fmt.Sprintf("test-acc-%s", nameSuffix)
rules := []string{"rule-1", "rule-2", "rule-3"}

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)

},
ProtoV6ProviderFactories: testAccProviders,
Steps: []resource.TestStep{
{
Config: securityPolicyRules_UpdateMissing_Tmpl,
ConfigVariables: map[string]config.Variable{
"prefix": config.StringVariable(prefix),
"rule_names": config.ListVariable(withPrefix(prefix, rules)...),
},
ConfigStateChecks: []statecheck.StateCheck{
ExpectServerSecurityRulesOrder(prefix, rules),
},
},
{
Config: securityPolicyRules_UpdateMissing_Tmpl,
ConfigVariables: map[string]config.Variable{
"prefix": config.StringVariable(prefix),
"rule_names": config.ListVariable(withPrefix(prefix, rules)...),
},
PreConfig: func() {
DeleteServerSecurityRules(prefix, []string{"rule-2"})
},
ConfigStateChecks: []statecheck.StateCheck{
ExpectServerSecurityRulesOrder(prefix, rules),
},
},
},
})
}

func mergeConfigs(configs ...string) string {
return strings.Join(configs, "\n")
}
107 changes: 89 additions & 18 deletions assets/terraform/test/resource_security_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ import (
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
)

func DeleteServerSecurityRules(prefix string, ruleNames []string) {
location := security.NewDeviceGroupLocation()
location.DeviceGroup.DeviceGroup = fmt.Sprintf("%s-dg", prefix)

service := security.NewService(sdkClient)

var names []string
for _, elt := range ruleNames {
names = append(names, prefixed(prefix, elt))
}

err := service.Delete(context.TODO(), *location, names...)
if err != nil {
panic("failed to delete entries from the server")
}

return
}

type expectServerSecurityRulesOrder struct {
Location security.Location
Prefix string
Expand Down Expand Up @@ -516,32 +535,19 @@ func TestAccSecurityPolicyOrdering(t *testing.T) {
rulesInitial := []string{"rule-1", "rule-2", "rule-3", "rule-4", "rule-5"}
rulesReordered := []string{"rule-2", "rule-1", "rule-3", "rule-4", "rule-5"}

prefixed := func(name string) string {
return fmt.Sprintf("%s-%s", prefix, name)
}

withPrefix := func(rules []string) []config.Variable {
var result []config.Variable
for _, elt := range rules {
result = append(result, config.StringVariable(prefixed(elt)))
}

return result
}

stateExpectedRuleName := func(idx int, value string) statecheck.StateCheck {
return statecheck.ExpectKnownValue(
"panos_security_policy.policy",
tfjsonpath.New("rules").AtSliceIndex(idx).AtMapKey("name"),
knownvalue.StringExact(prefixed(value)),
knownvalue.StringExact(prefixed(prefix, value)),
)
}

planExpectedRuleName := func(idx int, value string) plancheck.PlanCheck {
return plancheck.ExpectKnownValue(
"panos_security_policy.policy",
tfjsonpath.New("rules").AtSliceIndex(idx).AtMapKey("name"),
knownvalue.StringExact(prefixed(value)),
knownvalue.StringExact(prefixed(prefix, value)),
)
}

Expand Down Expand Up @@ -573,7 +579,7 @@ func TestAccSecurityPolicyOrdering(t *testing.T) {
Config: securityPolicyOrderingTmpl,
ConfigVariables: map[string]config.Variable{
"prefix": config.StringVariable(prefix),
"rule_names": config.ListVariable(withPrefix(rulesInitial)...),
"rule_names": config.ListVariable(withPrefix(prefix, rulesInitial)...),
},
ConfigStateChecks: []statecheck.StateCheck{
stateExpectedRuleName(0, "rule-1"),
Expand All @@ -589,7 +595,7 @@ func TestAccSecurityPolicyOrdering(t *testing.T) {
Config: securityPolicyOrderingTmpl,
ConfigVariables: map[string]config.Variable{
"prefix": config.StringVariable(prefix),
"rule_names": config.ListVariable(withPrefix(rulesInitial)...),
"rule_names": config.ListVariable(withPrefix(prefix, rulesInitial)...),
},
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
Expand All @@ -601,7 +607,7 @@ func TestAccSecurityPolicyOrdering(t *testing.T) {
Config: securityPolicyOrderingTmpl,
ConfigVariables: map[string]config.Variable{
"prefix": config.StringVariable(prefix),
"rule_names": config.ListVariable(withPrefix(rulesReordered)...),
"rule_names": config.ListVariable(withPrefix(prefix, rulesReordered)...),
},
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
Expand Down Expand Up @@ -641,6 +647,71 @@ func TestAccSecurityPolicyOrdering(t *testing.T) {
})
}

const securityPolicy_UpdateMissing_Tmpl = `
variable "prefix" { type = string }
variable "rule_names" { type = list(string) }

resource "panos_security_policy_rules" "policy" {
location = { device_group = { name = format("%s-dg", var.prefix) }}

rules = [
for index, name in var.rule_names: {
name = name

source_zones = ["any"]
source_addresses = ["any"]

destination_zones = ["any"]
destination_addresses = ["any"]

services = ["any"]
applications = ["any"]
}
]
}
`

func TestAccSecurityPolicy_UpdateMissing(t *testing.T) {
t.Parallel()

nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum)
prefix := fmt.Sprintf("test-acc-%s", nameSuffix)
rules := []string{"rule-1", "rule-2", "rule-3"}

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)

},
ProtoV6ProviderFactories: testAccProviders,
Steps: []resource.TestStep{
{
Config: securityPolicyRules_UpdateMissing_Tmpl,
ConfigVariables: map[string]config.Variable{
"prefix": config.StringVariable(prefix),
"rule_names": config.ListVariable(withPrefix(prefix, rules)...),
},
ConfigStateChecks: []statecheck.StateCheck{
ExpectServerSecurityRulesOrder(prefix, rules),
},
},
{
Config: securityPolicyRules_UpdateMissing_Tmpl,
ConfigVariables: map[string]config.Variable{
"prefix": config.StringVariable(prefix),
"rule_names": config.ListVariable(withPrefix(prefix, rules)...),
},
PreConfig: func() {
DeleteServerSecurityRules(prefix, []string{"rule-2"})
},
ConfigStateChecks: []statecheck.StateCheck{
ExpectServerSecurityRulesOrder(prefix, rules),
},
},
},
})
}

func securityPolicyPreCheck(prefix string) {
service := security.NewService(sdkClient)
ctx := context.TODO()
Expand Down