Skip to content

Commit

Permalink
list refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoineJac committed Nov 28, 2024
1 parent 6125315 commit 00e7c4a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 91 deletions.
30 changes: 25 additions & 5 deletions cmd/gateway_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import (
)

var (
validateCmdKongStateFile []string
validateCmdKongStateFile []string
validateCmdOnlineEntitiesFilter []string
validateCmdRBACResourcesOnly bool
validateCmdCheckOnlinePluginsOnly bool
validateOnline bool
validateWorkspace string
validateParallelism int
Expand Down Expand Up @@ -211,6 +211,26 @@ this command unless --online flag is used.
if len(validateCmdKongStateFile) == 0 {
validateCmdKongStateFile = []string{"-"}
}

if validateCmdOnlineEntitiesFilter != nil {

Check failure on line 215 in cmd/gateway_validate.go

View workflow job for this annotation

GitHub Actions / lint

S1031: unnecessary nil check around range (gosimple)
// Iterate over the input values and validate them against the keys in entityMap
for _, value := range validateCmdOnlineEntitiesFilter {
// Check if the value is valid by comparing it with keys in entityMap
isValid := false
for key := range validate.EntityMap {
if value == key {
isValid = true
break
}
}

if !isValid {
// Generate an error message stating that the value should be part of Kong entities
return fmt.Errorf("invalid value '%s' for --check-online-plugins-only; it should be a valid Kong entity",
value)
}
}
}
return preRunSilenceEventsFlag()
}

Expand Down Expand Up @@ -238,8 +258,8 @@ this command unless --online flag is used.

validateCmd.Flags().BoolVar(&validateCmdRBACResourcesOnly, "rbac-resources-only",
false, "indicate that the state file(s) contains RBAC resources only (Kong Enterprise only).")
validateCmd.Flags().BoolVar(&validateCmdCheckOnlinePluginsOnly, "check-online-plugins-only",
false, "indicate that the online validation will be done only on plugins.")
validateCmd.Flags().StringSliceVarP(&validateCmdOnlineEntitiesFilter, "online-entities-list",
"", []string{}, "indicate the list of entitied that should be validate online validation.")
if deprecated {
validateCmd.Flags().StringSliceVarP(&validateCmdKongStateFile,
"state", "s", []string{"kong.yaml"}, "file(s) containing Kong's configuration.\n"+
Expand Down Expand Up @@ -287,7 +307,7 @@ func validateWithKong(
Client: kongClient,
Parallelism: validateParallelism,
RBACResourcesOnly: validateCmdRBACResourcesOnly,
CheckOnlinePluginsOnly: validateCmdCheckOnlinePluginsOnly,
OnlineEntitiesFilter: validateCmdOnlineEntitiesFilter,
}
validator := validate.NewValidator(opts)
return validator.Validate(parsedFormatVersion)
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ func Test_Validate_File(t *testing.T) {
additionalArgs: []string{"--rbac-resources-only"},
},
{
name: "file validate with --check-online-plugins-only",
name: "file validate with --online-entities-list",
stateFile: "testdata/validate/kong3x.yaml",
additionalArgs: []string{"--check-online-plugins-only"},
additionalArgs: []string{"--online-entities-list Service,Routes"},
},
}

Expand Down
161 changes: 77 additions & 84 deletions validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,55 @@ import (
)

type Validator struct {
ctx context.Context
state *state.KongState
client *kong.Client
parallelism int
rbacResourcesOnly bool
CheckOnlinePluginsOnly bool
ctx context.Context
state *state.KongState
client *kong.Client
parallelism int
rbacResourcesOnly bool
onlineEntitiesFilter []string
}

type ValidatorOpts struct {
Ctx context.Context
State *state.KongState
Client *kong.Client
Parallelism int
RBACResourcesOnly bool
CheckOnlinePluginsOnly bool
Ctx context.Context
State *state.KongState
Client *kong.Client
Parallelism int
RBACResourcesOnly bool
OnlineEntitiesFilter []string
}

// Define a map of entity object field names and their corresponding string names
var EntityMap = map[string]string{
"RBACEndpointPermissions": "rbac-endpointpermission",
"RBACRoles": "rbac-role",
"Plugins": "plugins",
"Services": "services",
"ACLGroups": "acls",
"BasicAuths": "basicauth_credentials",
"CACertificates": "ca_certificates",
"Certificates": "certificates",
"Consumers": "consumers",
"Documents": "documents",
"HMACAuths": "hmacauth_credentials",
"JWTAuths": "jwt_secrets",
"KeyAuths": "keyauth_credentials",
"Oauth2Creds": "oauth2_credentials",
"Routes": "routes",
"SNIs": "snis",
"Targets": "targets",
"Upstreams": "upstreams",
"FilterChains": "filter_chains",
"Vaults": "vaults",
}

func NewValidator(opt ValidatorOpts) *Validator {
return &Validator{
ctx: opt.Ctx,
state: opt.State,
client: opt.Client,
parallelism: opt.Parallelism,
rbacResourcesOnly: opt.RBACResourcesOnly,
CheckOnlinePluginsOnly: opt.CheckOnlinePluginsOnly,
ctx: opt.Ctx,
state: opt.State,
client: opt.Client,
parallelism: opt.Parallelism,
rbacResourcesOnly: opt.RBACResourcesOnly,
onlineEntitiesFilter: opt.OnlineEntitiesFilter,
}
}

Expand Down Expand Up @@ -122,76 +146,45 @@ func (v *Validator) entities(obj interface{}, entityType string) []error {
func (v *Validator) Validate(formatVersion semver.Version) []error {
allErr := []error{}

// validate RBAC resources first.
if err := v.entities(v.state.RBACEndpointPermissions, "rbac-endpointpermission"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.RBACRoles, "rbac-role"); err != nil {
allErr = append(allErr, err...)
}
if v.rbacResourcesOnly {
// validate RBAC resources first.
if err := v.entities(v.state.RBACEndpointPermissions, "rbac-endpointpermission"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.RBACRoles, "rbac-role"); err != nil {
allErr = append(allErr, err...)
}
return allErr
}

// validate Plugins resources then.
if err := v.entities(v.state.Plugins, "plugins"); err != nil {
allErr = append(allErr, err...)
}
if v.CheckOnlinePluginsOnly {
return allErr
}

if err := v.entities(v.state.Services, "services"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.ACLGroups, "acls"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.BasicAuths, "basicauth_credentials"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.CACertificates, "ca_certificates"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.Certificates, "certificates"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.Consumers, "consumers"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.Documents, "documents"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.HMACAuths, "hmacauth_credentials"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.JWTAuths, "jwt_secrets"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.KeyAuths, "keyauth_credentials"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.Oauth2Creds, "oauth2_credentials"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.Routes, "routes"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.SNIs, "snis"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.Targets, "targets"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.Upstreams, "upstreams"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.FilterChains, "filter_chains"); err != nil {
allErr = append(allErr, err...)
}
if err := v.entities(v.state.Vaults, "vaults"); err != nil {
allErr = append(allErr, err...)
}
// Create a copy of entityMap with only the specififed resources to check online.
filteredEntityMap := make(map[string]string)
if v.onlineEntitiesFilter != nil {
for _, value := range v.onlineEntitiesFilter {
for key, entityName := range EntityMap {
if value == entityName {
filteredEntityMap[key] = entityName
}
}
}
} else {
// If no filter is specified, use the original entityMap.
filteredEntityMap = EntityMap
}


// Validate each entity using the filtered entityMap
for fieldName, entityName := range filteredEntityMap {
// Use reflection to get the value of the field from v.state
fieldValue := reflect.ValueOf(v.state).FieldByName(fieldName)
if fieldValue.IsValid() && fieldValue.CanInterface() {
if err := v.entities(fieldValue.Interface(), entityName); err != nil {
allErr = append(allErr, err...)
}
} else {
allErr = append(allErr, fmt.Errorf("invalid field '%s' in state", fieldName))
}
}

// validate routes format with Kong 3.x
parsed30, err := semver.ParseTolerant(utils.FormatVersion30)
Expand Down

0 comments on commit 00e7c4a

Please sign in to comment.