diff --git a/.gitignore b/.gitignore index ad7fb7cb..c4587232 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store .vscode/ +.idea/ bin/* coverage/* dist/* @@ -8,5 +9,5 @@ tmp/* vendor/* *.json *.yaml -*.yml +^(g)*.yml testdata/schema.json diff --git a/.tutone.yml b/.tutone.yml new file mode 100644 index 00000000..dd876426 --- /dev/null +++ b/.tutone.yml @@ -0,0 +1,61 @@ +--- +# Log level for running tutone +# Default: info +log_level: debug + +# Cache for storing a GraphQL schema +cache: + # Default: schema.json + schema_file: schema.json + +# GraphQL endpoint to query for schema +# Required +endpoint: https://api.newrelic.com/graphql + +# How to authenticate to the API +auth: + # Header set with the API key for authentication + # Default: Api-Key + header: Api-Key + + # Environment variable to get the API key from + # Default: TUTONE_API_KEY + api_key_env_var: NEW_RELIC_API_KEY + +packages: + - name: newrelic + path: tmp + generators: + - terraform + imports: + - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + - "github.com/newrelic/newrelic-client-go/v2/newrelic" + - "github.com/newrelic/newrelic-client-go/v2/pkg/alerts" + # - nrErrors "github.com/newrelic/newrelic-client-go/v2/pkg/errors" + resources: + - name: AlertsPolicy + fileName: resource_alert_policy.go + clientPackageName: alerts + clientMethod: + - CreatePolicyMutationWithContext + - GetPolicyMutationWithContext + - UpdatePolicyMutationWithContext + - DeletePolicyMutationWithContext + createMutation: "alertsPolicyCreate" + # graphqlPath: "" + # clientPackage: "alerts" + # clientMethod: "CreatePolicyMutation" + # read: + # update: + # delete: + +generators: + - name: typegen + fileName: "types.go" + - name: nerdgraphclient + fileName: "{{.PackageName}}_api.go" + - name: terraform + templateDir: "templates/terraform" + templateName: "resource.go.tmpl" \ No newline at end of file diff --git a/go.mod b/go.mod index 2a07371f..af4ea108 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1 github.com/huandu/xstrings v1.3.2 github.com/iancoleman/strcase v0.2.0 + github.com/newrelic/newrelic-client-go/v2 v2.7.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.13.0 @@ -27,11 +28,14 @@ require ( github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.1.2 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect github.com/hashicorp/go-hclog v1.2.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -39,7 +43,7 @@ require ( github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-plugin-go v0.14.1 // indirect github.com/hashicorp/terraform-plugin-log v0.7.0 // indirect - github.com/imdario/mergo v0.3.11 // indirect + github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-colorable v0.1.12 // indirect @@ -49,7 +53,6 @@ require ( github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -60,6 +63,8 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.1 // indirect + github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect + github.com/valyala/fastjson v1.6.3 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect github.com/vmihailenco/tagparser v0.1.1 // indirect @@ -70,7 +75,6 @@ require ( golang.org/x/sys v0.1.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3166dde9..8418669c 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -152,12 +154,18 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw= github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= +github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= @@ -184,8 +192,9 @@ github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHL github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -227,8 +236,9 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/newrelic/newrelic-client-go/v2 v2.7.0 h1:5qrw8OJagLCbUU6ufA8cA0ANh5A7X9AVeqnXMVaG6uE= +github.com/newrelic/newrelic-client-go/v2 v2.7.0/go.mod h1:xDZ6IDWI6fpl7MhTI4Hk75alJLAIfXzOt/rINEolxhQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -291,6 +301,10 @@ github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= +github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc= +github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= @@ -615,7 +629,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= diff --git a/internal/config/config.go b/internal/config/config.go index e57d7c07..6d665c3c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -65,11 +65,11 @@ type PackageConfig struct { } type ResourceConfig struct { - Name string `yaml:"name"` - FileName string `yaml:"fileName"` - ClientPackageName string `yaml:"clientPackageName"` - ClientMethod string `yaml:"clientMethod,omitempty"` - CreateMutation string `yaml:"createMutation,omitempty"` + Name string `yaml:"name"` + FileName string `yaml:"fileName"` + ClientPackageName string `yaml:"clientPackageName"` + ClientMethod []string `yaml:"clientMethod,omitempty"` + CreateMutation string `yaml:"createMutation,omitempty"` } // Query is the information necessary to build a query method. The Paths diff --git a/pkg/lang/terraform.go b/pkg/lang/terraform.go index c2c1e921..22632573 100644 --- a/pkg/lang/terraform.go +++ b/pkg/lang/terraform.go @@ -21,7 +21,7 @@ type Resource struct { FileName string Attributes []TerraformSchemaAttribute ClientPackageName string - ClientMethod string + ClientMethod []string InputObject string } @@ -79,7 +79,7 @@ func GenerateSchemaAttributes(s *schema.Schema, resourceConfig *config.ResourceC if arg.Type.OfType.Kind == schema.KindScalar { attr := TerraformSchemaAttribute{ Key: strcase.ToSnake(arg.Name), - Type: "schema.TypeInt", + Type: arg.Type.OfType.Name, Description: arg.Description, } @@ -103,12 +103,12 @@ func GenerateSchemaAttributes(s *schema.Schema, resourceConfig *config.ResourceC for _, field := range t.InputFields { attr := TerraformSchemaAttribute{ Key: strcase.ToSnake(field.Name), - Type: "schema.TypeString", + Type: "String", Description: strings.Trim(field.GetDescription(), "/ "), } if field.IsEnum() { - attr.Type = "schema.TypeString" + attr.Type = "String" } if field.IsRequired() { diff --git a/templates/terraform/resource.go.tmpl b/templates/terraform/resource.go.tmpl index 374f01de..83d94f17 100644 --- a/templates/terraform/resource.go.tmpl +++ b/templates/terraform/resource.go.tmpl @@ -24,7 +24,7 @@ func resource{{$pkgResourceName}}() *schema.Resource { Schema: map[string]*schema.Schema{ {{- range .Attributes }} "{{.Key}}": { - Type: {{.Type}}, + Type: schema.Type{{.Type}}, Description: {{.Description | quote}}, {{- if .Required }} Required: true, @@ -43,15 +43,103 @@ func resource{{$pkgResourceName}}Create(ctx context.Context, d *schema.ResourceD accountID := selectAccountID(providerConfig, d) + log.Printf("[INFO] Creating New Relic One {{.Name}}") + createInput := {{.ClientPackageName | lower }}.{{.InputObject | title }}{} - created, err := client.{{.ClientPackageName | title}}.{{.ClientMethod}}(ctx, accountID, createInput) + {{- range .Attributes }} + if attr, ok := d.GetOK({{.Key | quote}}); ok{ + createInput.{{.Key | camelcase}} = attr.({{.Type | lower}}) + } + {{- end}} + + created, err := client.{{.ClientPackageName | title}}.{{index .ClientMethod 0}}(ctx, accountID, createInput) if err != nil { return diag.FromErr(err) } if created == nil { - return diag.Errorf("err: {{.ClientMethod }} result wasn't returned or not created.") + return diag.Errorf("err: {{index .ClientMethod 0}} result wasn't returned or not created.") } d.SetId(created.ID) return resource{{$pkgResourceName}}Read(ctx, d, meta) } + +func resource{{$pkgResourceName}}Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + providerConfig := meta.(*ProviderConfig) + client := providerConfig.NewClient + + accountID := selectAccountID(providerConfig, d) + + log.Printf("[INFO] Getting New Relic One {{.Name}}") + + resourceID := d.Id() + + resp, err := client.{{.ClientPackageName | title}}.{{index .ClientMethod 1}}(ctx, accountID, resourceID) + + if err != nil && resp == nil { + d.SetId("") + return nil + } + + //Set values for import + //err = set{{$pkgResourceName}}Attributes(d, map[string]string{ + {{- range .Attributes }} + // {{.Key | quote}}: , + {{- end}} + //}) + //return diag.FromErr(flatten{{$pkgResourceName}}(resp, d)) + return diag.FromErr(err) +} + +func resource{{$pkgResourceName}}Update(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + providerConfig := meta.(*ProviderConfig) + client := providerConfig.NewClient + + accountID := selectAccountID(providerConfig, d) + + log.Printf("[INFO] Updating New Relic One {{.Name}}") + + updateInput := {{.ClientPackageName | lower }}.{{.InputObject | title }}{} + //Check for the values to be updated + + updated, err := client.{{.ClientPackageName | title}}.{{index .ClientMethod 2}}(ctx, accountID, updateInput) + if err != nil { + return diag.FromErr(err) + } + + if updated == nil { + return diag.Errorf("err: {{index .ClientMethod 2}} result wasn't returned or not updated.") + } + + return resource{{$pkgResourceName}}Read(ctx, d, meta) +} + +func resource{{$pkgResourceName}}Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + providerConfig := meta.(*ProviderConfig) + client := providerConfig.NewClient + + accountID := selectAccountID(providerConfig, d) + + log.Printf("[INFO] Deleting New Relic One {{.Name}}") + + resourceID := d.Id() + + _, err := client.{{.ClientPackageName | title}}.{{index .ClientMethod 3}}(ctx, accountID, resourceID) + + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func set{{$pkgResourceName}}Attributes(d *schema.ResourceData, attributes map[string]string) error { + for key := range attributes { + err := d.Set(key, attributes[key]) + if err != nil { + return err + } + } + + return nil +} \ No newline at end of file