@@ -6,25 +6,30 @@ import (
6
6
"github.com/kong/deck/dump"
7
7
"github.com/kong/deck/file"
8
8
"github.com/kong/deck/state"
9
+ "github.com/kong/deck/utils"
10
+ "github.com/kong/deck/validate"
9
11
"github.com/spf13/cobra"
10
12
)
11
13
12
14
var (
13
15
validateCmdKongStateFile []string
14
16
validateCmdRBACResourcesOnly bool
17
+ validateOnline bool
18
+ validateWorkspace string
19
+ validateParallelism int
15
20
)
16
21
17
22
// validateCmd represents the diff command
18
23
var validateCmd = & cobra.Command {
19
24
Use : "validate" ,
20
25
Short : "Validate the state file" ,
21
26
Long : `The validate command reads the state file and ensures validity.
22
-
23
27
It reads all the specified state files and reports YAML/JSON
24
28
parsing issues. It also checks for foreign relationships
25
29
and alerts if there are broken relationships, or missing links present.
30
+
26
31
No communication takes places between decK and Kong during the execution of
27
- this command.
32
+ this command unless --online flag is used .
28
33
` ,
29
34
Args : validateNoArgs ,
30
35
RunE : func (cmd * cobra.Command , args []string ) error {
@@ -51,11 +56,16 @@ this command.
51
56
return err
52
57
}
53
58
// this catches foreign relation errors
54
- _ , err = state .Get (rawState )
59
+ ks , err : = state .Get (rawState )
55
60
if err != nil {
56
61
return err
57
62
}
58
63
64
+ if validateOnline {
65
+ if errs := validateWithKong (cmd , ks , targetContent ); len (errs ) != 0 {
66
+ return validate.ErrorsWrapper {Errors : errs }
67
+ }
68
+ }
59
69
return nil
60
70
},
61
71
PreRunE : func (cmd * cobra.Command , args []string ) error {
@@ -67,6 +77,107 @@ this command.
67
77
},
68
78
}
69
79
80
+ func validateWithKong (cmd * cobra.Command , ks * state.KongState , targetContent * file.Content ) []error {
81
+ ctx := cmd .Context ()
82
+ // make sure we are able to connect to Kong
83
+ _ , err := fetchKongVersion (ctx , rootConfig )
84
+ if err != nil {
85
+ return []error {fmt .Errorf ("couldn't fetch Kong version: %w" , err )}
86
+ }
87
+
88
+ workspaceName := validateWorkspace
89
+ if validateWorkspace != "" {
90
+ // check if workspace exists
91
+ workspaceName := getWorkspaceName (validateWorkspace , targetContent )
92
+ workspaceExists , err := workspaceExists (ctx , rootConfig , workspaceName )
93
+ if err != nil {
94
+ return []error {err }
95
+ }
96
+ if ! workspaceExists {
97
+ return []error {fmt .Errorf ("workspace doesn't exist: %s" , workspaceName )}
98
+ }
99
+ }
100
+
101
+ wsConfig := rootConfig .ForWorkspace (workspaceName )
102
+ kongClient , err := utils .GetKongClient (wsConfig )
103
+ if err != nil {
104
+ return []error {err }
105
+ }
106
+
107
+ opts := validate.ValidatorOpts {
108
+ Ctx : ctx ,
109
+ State : ks ,
110
+ Client : kongClient ,
111
+ Parallelism : validateParallelism ,
112
+ RBACResourcesOnly : validateCmdRBACResourcesOnly ,
113
+ }
114
+ validator := validate .NewValidator (opts )
115
+ return validator .Validate ()
116
+ }
117
+
118
+ // ensureGetAllMethod ensures at init time that `GetAll()` method exists on the relevant structs.
119
+ // If the method doesn't exist, the code will panic. This increases the likelihood of catching such an
120
+ // error during manual testing.
121
+ func ensureGetAllMethods () error {
122
+ // let's make sure ASAP that all resources have the expected GetAll method
123
+ dummyEmptyState , _ := state .NewKongState ()
124
+ if _ , err := utils .CallGetAll (dummyEmptyState .Services ); err != nil {
125
+ return err
126
+ }
127
+ if _ , err := utils .CallGetAll (dummyEmptyState .ACLGroups ); err != nil {
128
+ return err
129
+ }
130
+ if _ , err := utils .CallGetAll (dummyEmptyState .BasicAuths ); err != nil {
131
+ return err
132
+ }
133
+ if _ , err := utils .CallGetAll (dummyEmptyState .CACertificates ); err != nil {
134
+ return err
135
+ }
136
+ if _ , err := utils .CallGetAll (dummyEmptyState .Certificates ); err != nil {
137
+ return err
138
+ }
139
+ if _ , err := utils .CallGetAll (dummyEmptyState .Consumers ); err != nil {
140
+ return err
141
+ }
142
+ if _ , err := utils .CallGetAll (dummyEmptyState .Documents ); err != nil {
143
+ return err
144
+ }
145
+ if _ , err := utils .CallGetAll (dummyEmptyState .HMACAuths ); err != nil {
146
+ return err
147
+ }
148
+ if _ , err := utils .CallGetAll (dummyEmptyState .JWTAuths ); err != nil {
149
+ return err
150
+ }
151
+ if _ , err := utils .CallGetAll (dummyEmptyState .KeyAuths ); err != nil {
152
+ return err
153
+ }
154
+ if _ , err := utils .CallGetAll (dummyEmptyState .Oauth2Creds ); err != nil {
155
+ return err
156
+ }
157
+ if _ , err := utils .CallGetAll (dummyEmptyState .Plugins ); err != nil {
158
+ return err
159
+ }
160
+ if _ , err := utils .CallGetAll (dummyEmptyState .Routes ); err != nil {
161
+ return err
162
+ }
163
+ if _ , err := utils .CallGetAll (dummyEmptyState .SNIs ); err != nil {
164
+ return err
165
+ }
166
+ if _ , err := utils .CallGetAll (dummyEmptyState .Targets ); err != nil {
167
+ return err
168
+ }
169
+ if _ , err := utils .CallGetAll (dummyEmptyState .Upstreams ); err != nil {
170
+ return err
171
+ }
172
+ if _ , err := utils .CallGetAll (dummyEmptyState .RBACEndpointPermissions ); err != nil {
173
+ return err
174
+ }
175
+ if _ , err := utils .CallGetAll (dummyEmptyState .RBACRoles ); err != nil {
176
+ return err
177
+ }
178
+ return nil
179
+ }
180
+
70
181
func init () {
71
182
rootCmd .AddCommand (validateCmd )
72
183
validateCmd .Flags ().BoolVar (& validateCmdRBACResourcesOnly , "rbac-resources-only" ,
@@ -75,4 +186,18 @@ func init() {
75
186
"state" , "s" , []string {"kong.yaml" }, "file(s) containing Kong's configuration.\n " +
76
187
"This flag can be specified multiple times for multiple files.\n " +
77
188
"Use '-' to read from stdin." )
189
+ validateCmd .Flags ().BoolVar (& validateOnline , "online" ,
190
+ false , "perform validations against Kong API. When this flag is used, validation is done\n " +
191
+ "via communication with Kong. This increases the time for validation but catches \n " +
192
+ "significant errors. No resource is created in Kong." )
193
+ validateCmd .Flags ().StringVarP (& validateWorkspace , "workspace" , "w" ,
194
+ "" , "validate configuration of a specific workspace " +
195
+ "(Kong Enterprise only).\n " +
196
+ "This takes precedence over _workspace fields in state files." )
197
+ validateCmd .Flags ().IntVar (& validateParallelism , "parallelism" ,
198
+ 10 , "Maximum number of concurrent requests to Kong." )
199
+
200
+ if err := ensureGetAllMethods (); err != nil {
201
+ panic (err .Error ())
202
+ }
78
203
}
0 commit comments