Skip to content

Commit 63b825a

Browse files
authored
tgc: manage cmd in magic-modules (GoogleCloudPlatform#15705)
1 parent 61c9f9e commit 63b825a

20 files changed

Lines changed: 2296 additions & 0 deletions

GNUmakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ clean-tgc:
120120
find ./tfplan2cai/test/** -type f -exec git rm {} \; > /dev/null;\
121121
rm -rf ./pkg/*;\
122122
rm -rf ./test/*;\
123+
rm -rf ./cmd/*;\
123124

124125
tgc:
125126
cd mmv1;\

mmv1/provider/terraform_tgc.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,13 @@ func (tgc TerraformGoogleConversion) CopyCommonFiles(outputFolder string, genera
437437
"converters/google/resources/services/logging/logging_project_sink.go": "third_party/tgc/services/logging/logging_project_sink.go",
438438
"converters/google/resources/services/logging/logging_folder_sink.go": "third_party/tgc/services/logging/logging_folder_sink.go",
439439
"converters/google/resources/services/logging/logging_organization_sink.go": "third_party/tgc/services/logging/logging_organization_sink.go",
440+
"../cmd/tfplan2cai/convert.go": "third_party/tgc/cmd/tfplan2cai/convert.go",
441+
"../cmd/tfplan2cai/convert_test.go": "third_party/tgc/cmd/tfplan2cai/convert_test.go",
442+
"../cmd/tfplan2cai/list_supported_resources.go": "third_party/tgc/cmd/tfplan2cai/list_supported_resources.go",
443+
"../cmd/tfplan2cai/logger.go": "third_party/tgc/cmd/tfplan2cai/logger.go",
444+
"../cmd/tfplan2cai/logger_test.go": "third_party/tgc/cmd/tfplan2cai/logger_test.go",
445+
"../cmd/tfplan2cai/main.go": "third_party/tgc/cmd/tfplan2cai/main.go",
446+
"../cmd/tfplan2cai/root.go": "third_party/tgc/cmd/tfplan2cai/root.go",
440447
}
441448
tgc.CopyFileList(outputFolder, resourceConverters)
442449
}
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"context"
19+
"encoding/json"
20+
"fmt"
21+
"os"
22+
23+
"github.com/GoogleCloudPlatform/terraform-google-conversion/v7/caiasset"
24+
"github.com/GoogleCloudPlatform/terraform-google-conversion/v7/tfplan2cai"
25+
"github.com/pkg/errors"
26+
"github.com/spf13/cobra"
27+
"go.uber.org/zap"
28+
)
29+
30+
const convertDesc = `
31+
This command will convert a Terraform plan file into CAI (Cloud Asset Inventory)
32+
resources and output them as a JSON array.
33+
34+
Note:
35+
Only supported resources will be converted. Non supported resources are
36+
omitted from results.
37+
Run "tfplan2cai list-supported-resources" to see all supported
38+
resources.
39+
40+
Example:
41+
tfplan2cai convert ./example/terraform.tfplan --project my-project \
42+
--ancestry organization/my-org/folder/my-folder
43+
`
44+
45+
func multiEnvSearch(ks []string) string {
46+
for _, k := range ks {
47+
if v := os.Getenv(k); v != "" {
48+
return v
49+
}
50+
}
51+
return ""
52+
}
53+
54+
type convertOptions struct {
55+
project string
56+
ancestry string
57+
offline bool
58+
rootOptions *rootOptions
59+
outputPath string
60+
dryRun bool
61+
}
62+
63+
var origConvertFunc = func(ctx context.Context, path, project, zone, region string, ancestry map[string]string, offline, convertUnchanged bool, errorLogger *zap.Logger, userAgent string) ([]caiasset.Asset, error) {
64+
jsonPlan, err := os.ReadFile(path)
65+
if err != nil {
66+
return nil, fmt.Errorf("error reading file %s: %s", path, err)
67+
}
68+
69+
return tfplan2cai.Convert(ctx, jsonPlan, &tfplan2cai.Options{
70+
ConvertUnchanged: false,
71+
ErrorLogger: errorLogger,
72+
Offline: offline,
73+
DefaultProject: project,
74+
DefaultRegion: region,
75+
DefaultZone: zone,
76+
UserAgent: userAgent,
77+
AncestryCache: ancestry,
78+
})
79+
}
80+
81+
var convertFunc = origConvertFunc
82+
83+
func newConvertCmd(rootOptions *rootOptions) *cobra.Command {
84+
o := &convertOptions{
85+
rootOptions: rootOptions,
86+
}
87+
88+
cmd := &cobra.Command{
89+
Use: "convert TFPLAN_JSON",
90+
Short: "convert a Terraform plan to Google CAI assets",
91+
Long: convertDesc,
92+
PreRunE: func(c *cobra.Command, args []string) error {
93+
return o.validateArgs(args)
94+
},
95+
RunE: func(c *cobra.Command, args []string) error {
96+
if o.dryRun {
97+
return nil
98+
}
99+
return o.run(args[0])
100+
},
101+
}
102+
103+
cmd.Flags().StringVar(&o.project, "project", "", "Provider project override (override the default project configuration assigned to the google terraform provider when converting resources)")
104+
cmd.Flags().StringVar(&o.ancestry, "ancestry", "", "Override the ancestry location of the project when validating resources")
105+
cmd.Flags().BoolVar(&o.offline, "offline", false, "Do not make network requests")
106+
cmd.Flags().StringVar(&o.outputPath, "output-path", "", "If specified, write the convert result into the specified output file")
107+
cmd.Flags().BoolVar(&o.dryRun, "dry-run", false, "Only parse & validate args")
108+
cmd.Flags().MarkHidden("dry-run")
109+
110+
return cmd
111+
}
112+
113+
func (o *convertOptions) validateArgs(args []string) error {
114+
if len(args) != 1 {
115+
return errors.New("missing required argument TFPLAN_JSON")
116+
}
117+
if o.offline && o.ancestry == "" {
118+
return errors.New("please set ancestry via --ancestry in offline mode")
119+
}
120+
return nil
121+
}
122+
123+
func (o *convertOptions) run(plan string) error {
124+
ctx := context.Background()
125+
ancestryCache := map[string]string{}
126+
if o.project != "" {
127+
ancestryCache[o.project] = o.ancestry
128+
}
129+
zone := multiEnvSearch([]string{
130+
"GOOGLE_ZONE",
131+
"GCLOUD_ZONE",
132+
"CLOUDSDK_COMPUTE_ZONE",
133+
})
134+
135+
region := multiEnvSearch([]string{
136+
"GOOGLE_REGION",
137+
"GCLOUD_REGION",
138+
"CLOUDSDK_COMPUTE_REGION",
139+
})
140+
userAgent := "tfplan2cai"
141+
assets, err := convertFunc(ctx, plan, o.project, zone, region, ancestryCache, o.offline, false, o.rootOptions.errorLogger, userAgent)
142+
if err != nil {
143+
return err
144+
}
145+
146+
if len(o.outputPath) > 0 {
147+
f, err := os.OpenFile(o.outputPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
148+
if err != nil {
149+
return err
150+
}
151+
defer f.Close()
152+
153+
if err := json.NewEncoder(f).Encode(assets); err != nil {
154+
return fmt.Errorf("encoding json: %w", err)
155+
}
156+
return nil
157+
}
158+
159+
if o.rootOptions.useStructuredLogging {
160+
o.rootOptions.outputLogger.Info(
161+
"converted resources",
162+
zap.Any("resource_body", assets),
163+
)
164+
return nil
165+
}
166+
167+
// Legacy behavior
168+
if err := json.NewEncoder(os.Stdout).Encode(assets); err != nil {
169+
return fmt.Errorf("encoding json: %w", err)
170+
}
171+
return nil
172+
}

0 commit comments

Comments
 (0)