1 package bannerctl
2
3 import (
4 "context"
5 "database/sql"
6 "errors"
7 "flag"
8 "fmt"
9 "time"
10
11 "github.com/peterbourgon/ff/v3"
12
13 bsltypes "edge-infra.dev/pkg/edge/api/bsl/types"
14 "edge-infra.dev/pkg/edge/bsl"
15 "edge-infra.dev/pkg/edge/gcpinfra/constants"
16 "edge-infra.dev/pkg/lib/gcp/cloudsql"
17 "edge-infra.dev/pkg/lib/logging"
18 )
19
20 var (
21
22 ErrNoBillingAccount = errors.New("no billing account provided")
23
24 ErrNoFolderID = errors.New("no folder id provided")
25
26 ErrNoDomain = errors.New("no domain provided")
27
28 ErrNoDatasyncDNSName = errors.New("datasync dns name is not provided")
29
30
31 ErrNoDatasyncDNSZone = errors.New("datasync dns zone is not provided")
32 )
33
34
35 type Config struct {
36 ProjectBootstrapping *ProjectBootstrappingConfig
37 ForemanProjectID string
38 PlatInfraProjectID string
39 EdgeAPI string
40 TotpSecret string
41 Domain string
42 DatasyncDNSName string
43 DatasyncDNSZone string
44 MetricsAddr string
45 DB *sql.DB
46 DatabaseName string
47 BSLAccessKey bsl.AccessKey
48 BSLConfig bsltypes.BSPConfig
49 GCPRegion string
50 GCPZone string
51 GCPForemanProjectNumber string
52 EdgeSecOptInCompliance bool
53 EdgeSecMaxLeasePeriod string
54 EdgeSecMaxValidityPeriod string
55
56 RequeueTime time.Duration
57 IntervalTime time.Duration
58 ResourceTimeout time.Duration
59 }
60
61
62
63
64
65 type ProjectBootstrappingConfig struct {
66 BillingAccount string
67 FolderID string
68 }
69
70
71
72
73
74 func NewConfig(args []string) (Config, *flag.FlagSet, error) {
75
76 config := Config{
77 ProjectBootstrapping: &ProjectBootstrappingConfig{},
78 }
79
80 fs := flag.NewFlagSet("bannerctl", flag.ExitOnError)
81
82 var SQLUser, SQLConnection string
83
84 fs.StringVar(
85 &config.ProjectBootstrapping.FolderID,
86 "gcp-tenants-folder-id",
87 "",
88 "folder id to store created gcp projects in",
89 )
90 fs.StringVar(
91 &config.ProjectBootstrapping.BillingAccount,
92 "gcp-billing-account",
93 constants.DefaultBillingAccountID,
94 "billing account id to use for created gcp projects",
95 )
96 fs.StringVar(
97 &config.ForemanProjectID,
98 "gcp-foreman-project-id",
99 "",
100 "foreman gcp project id that bannerctl will be running from -- not required "+
101 "for enterprise cluster deployments",
102 )
103 fs.StringVar(
104 &config.PlatInfraProjectID,
105 "gcp-plat-infra-project-id",
106 "",
107 "platform infrastructure (dns, artifact registry, etc) project",
108 )
109 fs.StringVar(
110 &config.EdgeAPI,
111 "edge-api",
112 "",
113 "api for edge env",
114 )
115 fs.StringVar(
116 &config.TotpSecret,
117 "totp-secret-key",
118 "",
119 "totp secret for validating totp token",
120 )
121 fs.StringVar(
122 &config.Domain,
123 "domain",
124 "",
125 "top level edge domain name",
126 )
127 fs.StringVar(
128 &config.DatasyncDNSName,
129 "datasync-dns-name",
130 "",
131 "exact dns name know as shown in gcp, remove the ending dot(.). e.g.. 'datasync-preprod.dev'",
132 )
133 fs.StringVar(
134 &config.DatasyncDNSZone,
135 "datasync-dns-zone",
136 "",
137 "datasync dns zone as shown in gcp console. e.g.. 'edge-preprod-datasync-dns-zone'",
138 )
139 fs.StringVar(
140 &config.MetricsAddr,
141 "metrics-address",
142 ":8080",
143 "Address to bind metrics endpoint (/metrics) to",
144 )
145 fs.StringVar(
146 &config.DatabaseName,
147 "sql-db-name",
148 "",
149 "SQL Database Name",
150 )
151 fs.StringVar(
152 &SQLUser,
153 "sql-user",
154 "",
155 "SQL User",
156 )
157 fs.StringVar(
158 &SQLConnection,
159 "sql-connection-name",
160 "",
161 "SQL Connection Name",
162 )
163
164 fs.StringVar(&config.BSLAccessKey.SecretKey,
165 "edge-bsl-secret-key",
166 "",
167 "secret key for access the bsl",
168 )
169
170 fs.StringVar(&config.BSLAccessKey.SharedKey,
171 "edge-bsl-shared-key",
172 "",
173 "shared key for access the bsl",
174 )
175
176 fs.StringVar(
177 &config.BSLConfig.Endpoint,
178 "bsl-endpoint",
179 "",
180 "bsl endpoint for a specific environment",
181 )
182
183 fs.StringVar(
184 &config.BSLConfig.Root,
185 "bsl-root-org",
186 "",
187 "bsl root org",
188 )
189
190 fs.StringVar(
191 &config.BSLConfig.OrganizationPrefix,
192 "bsp-organization-prefix",
193 "",
194 "bsl organization prefix for a specific environment",
195 )
196 fs.StringVar(
197 &config.GCPRegion,
198 "gcp-region",
199 "",
200 "GCP region - ex: us-east1",
201 )
202 fs.StringVar(
203 &config.GCPZone,
204 "gcp-zone",
205 "",
206 "GCP zone - ex: a/b/c",
207 )
208
209 fs.StringVar(
210 &config.GCPForemanProjectNumber,
211 "gcp-foreman-project-number",
212 "",
213 "GCP Project Number for all Foreman Projects",
214 )
215
216 fs.BoolVar(
217 &config.EdgeSecOptInCompliance,
218 "edge-sec-opt-in-compliance",
219 false,
220 "Edge Security compliance setting",
221 )
222
223 fs.StringVar(
224 &config.EdgeSecMaxLeasePeriod,
225 "edge-sec-max-lease-period",
226 "",
227 "Maximum secret lease period",
228 )
229
230 fs.StringVar(
231 &config.EdgeSecMaxValidityPeriod,
232 "edge-sec-max-validity-period",
233 "",
234 "Maximum secret validity period",
235 )
236
237 fs.DurationVar(
238 &config.IntervalTime,
239 "interval-time",
240 2*time.Minute,
241 "interval for processing",
242 )
243 fs.DurationVar(
244 &config.RequeueTime,
245 "requeue-time",
246 20*time.Second,
247 "requeue interval for errors",
248 )
249 fs.DurationVar(
250 &config.ResourceTimeout,
251 "resource-timeout",
252 20*time.Second,
253 "timeout for kms resource",
254 )
255
256 if err := ff.Parse(fs, args[1:], ff.WithEnvVarNoPrefix()); err != nil {
257 return Config{}, &flag.FlagSet{}, err
258 }
259
260
261 log := logging.NewLogger().WithName("bannerctl")
262 db, err := cloudsql.GCPPostgresConnection(SQLConnection).
263 DBName(config.DatabaseName).
264 Username(SQLUser).
265 NewConnection()
266
267 if err != nil {
268 log.Error(err, "could not create sql connection")
269 } else {
270 var pingCtx, cancel = context.WithTimeout(context.Background(), 3*time.Second)
271 if err := db.PingContext(pingCtx); err != nil {
272 log.Error(err, "could not ping sql connection")
273 } else {
274 config.DB = db
275 }
276 cancel()
277 }
278 log.Info("Infra status recording feature", "enabled", config.DB != nil)
279
280 if err := config.Validate(); err != nil {
281 return Config{}, &flag.FlagSet{}, err
282 }
283
284 return config, fs, nil
285 }
286
287
288 func (f Config) Validate() error {
289 if f.Domain == "" {
290 return fmt.Errorf("%w", ErrNoDomain)
291 }
292 if f.DatasyncDNSName == "" {
293 return ErrNoDatasyncDNSName
294 }
295 if f.DatasyncDNSZone == "" {
296 return ErrNoDatasyncDNSZone
297 }
298
299 if f.BSLAccessKey.SecretKey == "" {
300 return fmt.Errorf("misisng bsl access secret key")
301 }
302
303 if f.BSLAccessKey.SharedKey == "" {
304 return fmt.Errorf("missing bsl access shared key")
305 }
306
307 if f.BSLConfig.Endpoint == "" {
308 return fmt.Errorf("missing bsl endpoint")
309 }
310
311 if f.BSLConfig.Root == "" {
312 return fmt.Errorf("missing bsl root org")
313 }
314
315 if f.BSLConfig.OrganizationPrefix == "" {
316 return fmt.Errorf("missing bsl org prefix")
317 }
318 if f.GCPRegion == "" {
319 return fmt.Errorf("missing gcp region")
320 }
321 if f.GCPZone == "" {
322 return fmt.Errorf("missing gcp zone")
323 }
324 if f.GCPForemanProjectNumber == "" {
325 return fmt.Errorf("missing gcp foreman project number")
326 }
327 if f.EdgeSecMaxLeasePeriod == "" {
328 return fmt.Errorf("missing edge security max secret lease period")
329 }
330 if f.EdgeSecMaxValidityPeriod == "" {
331 return fmt.Errorf("missing edge security max secret validity period")
332 }
333
334 if f.IntervalTime == 0 {
335 return fmt.Errorf("missing INTERVAL_TIME environment variable")
336 }
337 if f.RequeueTime == 0 {
338 return fmt.Errorf("missing REQUEUE_TIME environment variable")
339 }
340 if f.ResourceTimeout == 0 {
341 return fmt.Errorf("missing RESOURCE_TIMEOUT environment variable")
342 }
343
344 return f.ProjectBootstrapping.Validate()
345 }
346
347
348
349 func (f ProjectBootstrappingConfig) Validate() error {
350 if f.BillingAccount == "" {
351 return fmt.Errorf("%w", ErrNoBillingAccount)
352 }
353
354 if f.FolderID == "" {
355 return fmt.Errorf("%w", ErrNoFolderID)
356 }
357
358 return nil
359 }
360
View as plain text