diff --git a/.gitignore b/.gitignore index 11434969..07664737 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ website/node_modules .terraform/ *.log *.bak +.env *~ .*.swp .idea diff --git a/README.md b/README.md index f9e230e6..65f8f053 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,7 @@ If you create a new one, be sure to add the file to the [genqlient.yaml](jupiter You should always generate the gql client from the production api so that you do not include any in-progress work from dev. Set these environment variables before running the next commands. ```shell -export JUPITERONE_ACCOUNT=:your_account_id +export JUPITERONE_ACCOUNT_ID=:your_account_id export JUPITERONE_API_KEY=:your_api_key export JUPITERONE_REGION=us ``` diff --git a/examples/resources/jupiterone_smart_class/resource.tf b/examples/resources/jupiterone_smart_class/resource.tf new file mode 100644 index 00000000..2281ea48 --- /dev/null +++ b/examples/resources/jupiterone_smart_class/resource.tf @@ -0,0 +1,31 @@ +resource "jupiterone_smart_class" "example" { + tag_name = "example" + description = "Example smart class" +} + +resource "jupiterone_smart_class_query" "query1" { + smart_class_id = jupiterone_smart_class.example.id + query = "Find User" + description = "Example query" +} + +resource "jupiterone_smart_class_query" "query2" { + smart_class_id = jupiterone_smart_class.example.id + query = "Find Person" + description = "Example query" +} + +resource "jupiterone_smart_class_tag" "tag1" { + smart_class_id = jupiterone_smart_class.example.id + name = "person" + type = "boolean" + value = "true" +} + +resource "jupiterone_smart_class_tag" "tag2" { + smart_class_id = jupiterone_smart_class.example.id + name = "user" + type = "boolean" + value = "true" +} + diff --git a/jupiterone/cassettes/TestSmartClass_Basic.yaml b/jupiterone/cassettes/TestSmartClass_Basic.yaml new file mode 100644 index 00000000..2797c38e --- /dev/null +++ b/jupiterone/cassettes/TestSmartClass_Basic.yaml @@ -0,0 +1,3 @@ +--- +version: 2 +interactions: [] diff --git a/jupiterone/cassettes/TestSmartClass_BasicImport.yaml b/jupiterone/cassettes/TestSmartClass_BasicImport.yaml new file mode 100644 index 00000000..9fe74078 --- /dev/null +++ b/jupiterone/cassettes/TestSmartClass_BasicImport.yaml @@ -0,0 +1,81 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 303 + transfer_encoding: [] + trailer: {} + host: graphql.dev.jupiterone.io + remote_addr: "" + request_uri: "" + body: '{"query":"\nmutation CreateSmartClass ($input: CreateSmartClassInput!) {\n\tcreateSmartClass(input: $input) {\n\t\tid\n\t\ttagName\n\t\tdescription\n\t}\n}\n","variables":{"input":{"tagName":"TfProviderTestImport","description":"description of TfProviderTestImport"}},"operationName":"CreateSmartClass"}' + form: {} + headers: + Cache-Control: + - no-cache + Content-Type: + - application/json + url: https://graphql.dev.jupiterone.io/ + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 161 + uncompressed: false + body: | + {"data":{"createSmartClass":{"id":"3f40b190-bbfc-477a-bf41-a9e8900437b2","tagName":"TfProviderTestImport","description":"description of TfProviderTestImport"}}} + headers: + Access-Control-Allow-Credentials: + - "true" + Content-Length: + - "161" + Content-Security-Policy: + - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' + Content-Type: + - application/json + Cross-Origin-Embedder-Policy: + - require-corp + Cross-Origin-Opener-Policy: + - same-origin + Cross-Origin-Resource-Policy: + - same-origin + Expect-Ct: + - max-age=0 + Origin-Agent-Cluster: + - ?1 + Ratelimit-Limit: + - "1000" + Ratelimit-Remaining: + - "999" + Ratelimit-Requested: + - "1" + Ratelimit-Reset: + - "1" + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=15552000; includeSubDomains + Vary: + - Origin + X-Content-Type-Options: + - nosniff + X-Dns-Prefetch-Control: + - "off" + X-Download-Options: + - noopen + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 1.049610292s diff --git a/jupiterone/internal/client/generated.go b/jupiterone/internal/client/generated.go index e0bc13e3..72ae9391 100644 --- a/jupiterone/internal/client/generated.go +++ b/jupiterone/internal/client/generated.go @@ -1177,6 +1177,137 @@ func (v *CreateResourceGroupResponse) GetCreateResourceGroup() CreateResourceGro return v.CreateResourceGroup } +// CreateSmartClassCreateSmartClass includes the requested fields of the GraphQL type SmartClass. +type CreateSmartClassCreateSmartClass struct { + Id string `json:"id"` + TagName string `json:"tagName"` + Description string `json:"description"` +} + +// GetId returns CreateSmartClassCreateSmartClass.Id, and is useful for accessing the field via an interface. +func (v *CreateSmartClassCreateSmartClass) GetId() string { return v.Id } + +// GetTagName returns CreateSmartClassCreateSmartClass.TagName, and is useful for accessing the field via an interface. +func (v *CreateSmartClassCreateSmartClass) GetTagName() string { return v.TagName } + +// GetDescription returns CreateSmartClassCreateSmartClass.Description, and is useful for accessing the field via an interface. +func (v *CreateSmartClassCreateSmartClass) GetDescription() string { return v.Description } + +type CreateSmartClassInput struct { + TagName string `json:"tagName"` + Description string `json:"description"` +} + +// GetTagName returns CreateSmartClassInput.TagName, and is useful for accessing the field via an interface. +func (v *CreateSmartClassInput) GetTagName() string { return v.TagName } + +// GetDescription returns CreateSmartClassInput.Description, and is useful for accessing the field via an interface. +func (v *CreateSmartClassInput) GetDescription() string { return v.Description } + +// CreateSmartClassQueryCreateSmartClassQuery includes the requested fields of the GraphQL type SmartClassQuery. +type CreateSmartClassQueryCreateSmartClassQuery struct { + Id string `json:"id"` + Query string `json:"query"` + SmartClassId string `json:"smartClassId"` + Description string `json:"description"` +} + +// GetId returns CreateSmartClassQueryCreateSmartClassQuery.Id, and is useful for accessing the field via an interface. +func (v *CreateSmartClassQueryCreateSmartClassQuery) GetId() string { return v.Id } + +// GetQuery returns CreateSmartClassQueryCreateSmartClassQuery.Query, and is useful for accessing the field via an interface. +func (v *CreateSmartClassQueryCreateSmartClassQuery) GetQuery() string { return v.Query } + +// GetSmartClassId returns CreateSmartClassQueryCreateSmartClassQuery.SmartClassId, and is useful for accessing the field via an interface. +func (v *CreateSmartClassQueryCreateSmartClassQuery) GetSmartClassId() string { return v.SmartClassId } + +// GetDescription returns CreateSmartClassQueryCreateSmartClassQuery.Description, and is useful for accessing the field via an interface. +func (v *CreateSmartClassQueryCreateSmartClassQuery) GetDescription() string { return v.Description } + +type CreateSmartClassQueryInput struct { + SmartClassId string `json:"smartClassId"` + Description string `json:"description"` + Query string `json:"query"` +} + +// GetSmartClassId returns CreateSmartClassQueryInput.SmartClassId, and is useful for accessing the field via an interface. +func (v *CreateSmartClassQueryInput) GetSmartClassId() string { return v.SmartClassId } + +// GetDescription returns CreateSmartClassQueryInput.Description, and is useful for accessing the field via an interface. +func (v *CreateSmartClassQueryInput) GetDescription() string { return v.Description } + +// GetQuery returns CreateSmartClassQueryInput.Query, and is useful for accessing the field via an interface. +func (v *CreateSmartClassQueryInput) GetQuery() string { return v.Query } + +// CreateSmartClassQueryResponse is returned by CreateSmartClassQuery on success. +type CreateSmartClassQueryResponse struct { + CreateSmartClassQuery CreateSmartClassQueryCreateSmartClassQuery `json:"createSmartClassQuery"` +} + +// GetCreateSmartClassQuery returns CreateSmartClassQueryResponse.CreateSmartClassQuery, and is useful for accessing the field via an interface. +func (v *CreateSmartClassQueryResponse) GetCreateSmartClassQuery() CreateSmartClassQueryCreateSmartClassQuery { + return v.CreateSmartClassQuery +} + +// CreateSmartClassResponse is returned by CreateSmartClass on success. +type CreateSmartClassResponse struct { + CreateSmartClass CreateSmartClassCreateSmartClass `json:"createSmartClass"` +} + +// GetCreateSmartClass returns CreateSmartClassResponse.CreateSmartClass, and is useful for accessing the field via an interface. +func (v *CreateSmartClassResponse) GetCreateSmartClass() CreateSmartClassCreateSmartClass { + return v.CreateSmartClass +} + +// CreateSmartClassTagCreateSmartClassTag includes the requested fields of the GraphQL type SmartClassTag. +type CreateSmartClassTagCreateSmartClassTag struct { + Id string `json:"id"` + Name string `json:"name"` + Type SmartClassTagType `json:"type"` + Value string `json:"value"` +} + +// GetId returns CreateSmartClassTagCreateSmartClassTag.Id, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagCreateSmartClassTag) GetId() string { return v.Id } + +// GetName returns CreateSmartClassTagCreateSmartClassTag.Name, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagCreateSmartClassTag) GetName() string { return v.Name } + +// GetType returns CreateSmartClassTagCreateSmartClassTag.Type, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagCreateSmartClassTag) GetType() SmartClassTagType { return v.Type } + +// GetValue returns CreateSmartClassTagCreateSmartClassTag.Value, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagCreateSmartClassTag) GetValue() string { return v.Value } + +type CreateSmartClassTagInput struct { + SmartClassId string `json:"smartClassId"` + Name string `json:"name"` + Type SmartClassTagType `json:"type"` + Value string `json:"value"` +} + +// GetSmartClassId returns CreateSmartClassTagInput.SmartClassId, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagInput) GetSmartClassId() string { return v.SmartClassId } + +// GetName returns CreateSmartClassTagInput.Name, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagInput) GetName() string { return v.Name } + +// GetType returns CreateSmartClassTagInput.Type, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagInput) GetType() SmartClassTagType { return v.Type } + +// GetValue returns CreateSmartClassTagInput.Value, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagInput) GetValue() string { return v.Value } + +// CreateSmartClassTagResponse is returned by CreateSmartClassTag on success. +type CreateSmartClassTagResponse struct { + CreateSmartClassTag CreateSmartClassTagCreateSmartClassTag `json:"createSmartClassTag"` +} + +// GetCreateSmartClassTag returns CreateSmartClassTagResponse.CreateSmartClassTag, and is useful for accessing the field via an interface. +func (v *CreateSmartClassTagResponse) GetCreateSmartClassTag() CreateSmartClassTagCreateSmartClassTag { + return v.CreateSmartClassTag +} + // CreateUserGroupCreateIamGroupV1Group includes the requested fields of the GraphQL type V1Group. type CreateUserGroupCreateIamGroupV1Group struct { Id string `json:"id"` @@ -1531,6 +1662,62 @@ func (v *DeleteRuleInstanceResponse) GetDeleteRuleInstance() DeleteRuleInstanceD return v.DeleteRuleInstance } +// DeleteSmartClassDeleteSmartClassDeleteResponse includes the requested fields of the GraphQL type DeleteResponse. +type DeleteSmartClassDeleteSmartClassDeleteResponse struct { + Success bool `json:"success"` +} + +// GetSuccess returns DeleteSmartClassDeleteSmartClassDeleteResponse.Success, and is useful for accessing the field via an interface. +func (v *DeleteSmartClassDeleteSmartClassDeleteResponse) GetSuccess() bool { return v.Success } + +// DeleteSmartClassQueryDeleteSmartClassQueryDeleteResponse includes the requested fields of the GraphQL type DeleteResponse. +type DeleteSmartClassQueryDeleteSmartClassQueryDeleteResponse struct { + Success bool `json:"success"` +} + +// GetSuccess returns DeleteSmartClassQueryDeleteSmartClassQueryDeleteResponse.Success, and is useful for accessing the field via an interface. +func (v *DeleteSmartClassQueryDeleteSmartClassQueryDeleteResponse) GetSuccess() bool { + return v.Success +} + +// DeleteSmartClassQueryResponse is returned by DeleteSmartClassQuery on success. +type DeleteSmartClassQueryResponse struct { + DeleteSmartClassQuery DeleteSmartClassQueryDeleteSmartClassQueryDeleteResponse `json:"deleteSmartClassQuery"` +} + +// GetDeleteSmartClassQuery returns DeleteSmartClassQueryResponse.DeleteSmartClassQuery, and is useful for accessing the field via an interface. +func (v *DeleteSmartClassQueryResponse) GetDeleteSmartClassQuery() DeleteSmartClassQueryDeleteSmartClassQueryDeleteResponse { + return v.DeleteSmartClassQuery +} + +// DeleteSmartClassResponse is returned by DeleteSmartClass on success. +type DeleteSmartClassResponse struct { + DeleteSmartClass DeleteSmartClassDeleteSmartClassDeleteResponse `json:"deleteSmartClass"` +} + +// GetDeleteSmartClass returns DeleteSmartClassResponse.DeleteSmartClass, and is useful for accessing the field via an interface. +func (v *DeleteSmartClassResponse) GetDeleteSmartClass() DeleteSmartClassDeleteSmartClassDeleteResponse { + return v.DeleteSmartClass +} + +// DeleteSmartClassTagDeleteSmartClassTagDeleteResponse includes the requested fields of the GraphQL type DeleteResponse. +type DeleteSmartClassTagDeleteSmartClassTagDeleteResponse struct { + Success bool `json:"success"` +} + +// GetSuccess returns DeleteSmartClassTagDeleteSmartClassTagDeleteResponse.Success, and is useful for accessing the field via an interface. +func (v *DeleteSmartClassTagDeleteSmartClassTagDeleteResponse) GetSuccess() bool { return v.Success } + +// DeleteSmartClassTagResponse is returned by DeleteSmartClassTag on success. +type DeleteSmartClassTagResponse struct { + DeleteSmartClassTag DeleteSmartClassTagDeleteSmartClassTagDeleteResponse `json:"deleteSmartClassTag"` +} + +// GetDeleteSmartClassTag returns DeleteSmartClassTagResponse.DeleteSmartClassTag, and is useful for accessing the field via an interface. +func (v *DeleteSmartClassTagResponse) GetDeleteSmartClassTag() DeleteSmartClassTagDeleteSmartClassTagDeleteResponse { + return v.DeleteSmartClassTag +} + // DeleteUserGroupDeleteIamGroupSuccessStatusResult includes the requested fields of the GraphQL type SuccessStatusResult. type DeleteUserGroupDeleteIamGroupSuccessStatusResult struct { Success bool `json:"success"` @@ -2488,6 +2675,84 @@ func (v *GetResourcePermissionsResponse) GetGetResourcePermissions() []GetResour return v.GetResourcePermissions } +// GetSmartClassQueryResponse is returned by GetSmartClassQuery on success. +type GetSmartClassQueryResponse struct { + SmartClassQuery GetSmartClassQuerySmartClassQuery `json:"smartClassQuery"` +} + +// GetSmartClassQuery returns GetSmartClassQueryResponse.SmartClassQuery, and is useful for accessing the field via an interface. +func (v *GetSmartClassQueryResponse) GetSmartClassQuery() GetSmartClassQuerySmartClassQuery { + return v.SmartClassQuery +} + +// GetSmartClassQuerySmartClassQuery includes the requested fields of the GraphQL type SmartClassQuery. +type GetSmartClassQuerySmartClassQuery struct { + Id string `json:"id"` + Query string `json:"query"` + SmartClassId string `json:"smartClassId"` + Description string `json:"description"` +} + +// GetId returns GetSmartClassQuerySmartClassQuery.Id, and is useful for accessing the field via an interface. +func (v *GetSmartClassQuerySmartClassQuery) GetId() string { return v.Id } + +// GetQuery returns GetSmartClassQuerySmartClassQuery.Query, and is useful for accessing the field via an interface. +func (v *GetSmartClassQuerySmartClassQuery) GetQuery() string { return v.Query } + +// GetSmartClassId returns GetSmartClassQuerySmartClassQuery.SmartClassId, and is useful for accessing the field via an interface. +func (v *GetSmartClassQuerySmartClassQuery) GetSmartClassId() string { return v.SmartClassId } + +// GetDescription returns GetSmartClassQuerySmartClassQuery.Description, and is useful for accessing the field via an interface. +func (v *GetSmartClassQuerySmartClassQuery) GetDescription() string { return v.Description } + +// GetSmartClassResponse is returned by GetSmartClass on success. +type GetSmartClassResponse struct { + SmartClass GetSmartClassSmartClass `json:"smartClass"` +} + +// GetSmartClass returns GetSmartClassResponse.SmartClass, and is useful for accessing the field via an interface. +func (v *GetSmartClassResponse) GetSmartClass() GetSmartClassSmartClass { return v.SmartClass } + +// GetSmartClassSmartClass includes the requested fields of the GraphQL type SmartClass. +type GetSmartClassSmartClass struct { + Id string `json:"id"` + TagName string `json:"tagName"` + Description string `json:"description"` + Tags []GetSmartClassSmartClassTagsSmartClassTag `json:"tags"` +} + +// GetId returns GetSmartClassSmartClass.Id, and is useful for accessing the field via an interface. +func (v *GetSmartClassSmartClass) GetId() string { return v.Id } + +// GetTagName returns GetSmartClassSmartClass.TagName, and is useful for accessing the field via an interface. +func (v *GetSmartClassSmartClass) GetTagName() string { return v.TagName } + +// GetDescription returns GetSmartClassSmartClass.Description, and is useful for accessing the field via an interface. +func (v *GetSmartClassSmartClass) GetDescription() string { return v.Description } + +// GetTags returns GetSmartClassSmartClass.Tags, and is useful for accessing the field via an interface. +func (v *GetSmartClassSmartClass) GetTags() []GetSmartClassSmartClassTagsSmartClassTag { return v.Tags } + +// GetSmartClassSmartClassTagsSmartClassTag includes the requested fields of the GraphQL type SmartClassTag. +type GetSmartClassSmartClassTagsSmartClassTag struct { + Id string `json:"id"` + Name string `json:"name"` + Type SmartClassTagType `json:"type"` + Value string `json:"value"` +} + +// GetId returns GetSmartClassSmartClassTagsSmartClassTag.Id, and is useful for accessing the field via an interface. +func (v *GetSmartClassSmartClassTagsSmartClassTag) GetId() string { return v.Id } + +// GetName returns GetSmartClassSmartClassTagsSmartClassTag.Name, and is useful for accessing the field via an interface. +func (v *GetSmartClassSmartClassTagsSmartClassTag) GetName() string { return v.Name } + +// GetType returns GetSmartClassSmartClassTagsSmartClassTag.Type, and is useful for accessing the field via an interface. +func (v *GetSmartClassSmartClassTagsSmartClassTag) GetType() SmartClassTagType { return v.Type } + +// GetValue returns GetSmartClassSmartClassTagsSmartClassTag.Value, and is useful for accessing the field via an interface. +func (v *GetSmartClassSmartClassTagsSmartClassTag) GetValue() string { return v.Value } + // GetUserGroupIamGetGroupIamGroup includes the requested fields of the GraphQL type IamGroup. type GetUserGroupIamGetGroupIamGroup struct { Id string `json:"id"` @@ -2890,6 +3155,51 @@ func (v *PatchInsightsDashboardInput) GetPublishedToGroupIds() []string { return // GetResourceGroupId returns PatchInsightsDashboardInput.ResourceGroupId, and is useful for accessing the field via an interface. func (v *PatchInsightsDashboardInput) GetResourceGroupId() string { return v.ResourceGroupId } +type PatchSmartClassInput struct { + Id string `json:"id"` + Description string `json:"description"` +} + +// GetId returns PatchSmartClassInput.Id, and is useful for accessing the field via an interface. +func (v *PatchSmartClassInput) GetId() string { return v.Id } + +// GetDescription returns PatchSmartClassInput.Description, and is useful for accessing the field via an interface. +func (v *PatchSmartClassInput) GetDescription() string { return v.Description } + +type PatchSmartClassQueryInput struct { + Id string `json:"id"` + Description string `json:"description"` + Query string `json:"query"` +} + +// GetId returns PatchSmartClassQueryInput.Id, and is useful for accessing the field via an interface. +func (v *PatchSmartClassQueryInput) GetId() string { return v.Id } + +// GetDescription returns PatchSmartClassQueryInput.Description, and is useful for accessing the field via an interface. +func (v *PatchSmartClassQueryInput) GetDescription() string { return v.Description } + +// GetQuery returns PatchSmartClassQueryInput.Query, and is useful for accessing the field via an interface. +func (v *PatchSmartClassQueryInput) GetQuery() string { return v.Query } + +type PatchSmartClassTagInput struct { + Id string `json:"id"` + Name string `json:"name"` + Type SmartClassTagType `json:"type"` + Value string `json:"value"` +} + +// GetId returns PatchSmartClassTagInput.Id, and is useful for accessing the field via an interface. +func (v *PatchSmartClassTagInput) GetId() string { return v.Id } + +// GetName returns PatchSmartClassTagInput.Name, and is useful for accessing the field via an interface. +func (v *PatchSmartClassTagInput) GetName() string { return v.Name } + +// GetType returns PatchSmartClassTagInput.Type, and is useful for accessing the field via an interface. +func (v *PatchSmartClassTagInput) GetType() SmartClassTagType { return v.Type } + +// GetValue returns PatchSmartClassTagInput.Value, and is useful for accessing the field via an interface. +func (v *PatchSmartClassTagInput) GetValue() string { return v.Value } + type QueryResultsAre string const ( @@ -3255,6 +3565,14 @@ func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetSub return v.SubjectType } +type SmartClassTagType string + +const ( + SmartClassTagTypeString SmartClassTagType = "string" + SmartClassTagTypeBoolean SmartClassTagType = "boolean" + SmartClassTagTypeNumber SmartClassTagType = "number" +) + type UpdateComplianceFrameworkFields struct { Name string `json:"name"` WebLink string `json:"webLink"` @@ -4013,6 +4331,88 @@ func (v *UpdateResourceGroupUpdateResourceGroupIamResourceGroup) __premarshalJSO return &retval, nil } +// UpdateSmartClassPatchSmartClass includes the requested fields of the GraphQL type SmartClass. +type UpdateSmartClassPatchSmartClass struct { + Id string `json:"id"` + Description string `json:"description"` +} + +// GetId returns UpdateSmartClassPatchSmartClass.Id, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassPatchSmartClass) GetId() string { return v.Id } + +// GetDescription returns UpdateSmartClassPatchSmartClass.Description, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassPatchSmartClass) GetDescription() string { return v.Description } + +// UpdateSmartClassQueryPatchSmartClassQuery includes the requested fields of the GraphQL type SmartClassQuery. +type UpdateSmartClassQueryPatchSmartClassQuery struct { + Id string `json:"id"` + Query string `json:"query"` + SmartClassId string `json:"smartClassId"` + Description string `json:"description"` +} + +// GetId returns UpdateSmartClassQueryPatchSmartClassQuery.Id, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassQueryPatchSmartClassQuery) GetId() string { return v.Id } + +// GetQuery returns UpdateSmartClassQueryPatchSmartClassQuery.Query, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassQueryPatchSmartClassQuery) GetQuery() string { return v.Query } + +// GetSmartClassId returns UpdateSmartClassQueryPatchSmartClassQuery.SmartClassId, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassQueryPatchSmartClassQuery) GetSmartClassId() string { return v.SmartClassId } + +// GetDescription returns UpdateSmartClassQueryPatchSmartClassQuery.Description, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassQueryPatchSmartClassQuery) GetDescription() string { return v.Description } + +// UpdateSmartClassQueryResponse is returned by UpdateSmartClassQuery on success. +type UpdateSmartClassQueryResponse struct { + PatchSmartClassQuery UpdateSmartClassQueryPatchSmartClassQuery `json:"patchSmartClassQuery"` +} + +// GetPatchSmartClassQuery returns UpdateSmartClassQueryResponse.PatchSmartClassQuery, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassQueryResponse) GetPatchSmartClassQuery() UpdateSmartClassQueryPatchSmartClassQuery { + return v.PatchSmartClassQuery +} + +// UpdateSmartClassResponse is returned by UpdateSmartClass on success. +type UpdateSmartClassResponse struct { + PatchSmartClass UpdateSmartClassPatchSmartClass `json:"patchSmartClass"` +} + +// GetPatchSmartClass returns UpdateSmartClassResponse.PatchSmartClass, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassResponse) GetPatchSmartClass() UpdateSmartClassPatchSmartClass { + return v.PatchSmartClass +} + +// UpdateSmartClassTagPatchSmartClassTag includes the requested fields of the GraphQL type SmartClassTag. +type UpdateSmartClassTagPatchSmartClassTag struct { + Id string `json:"id"` + Name string `json:"name"` + Type SmartClassTagType `json:"type"` + Value string `json:"value"` +} + +// GetId returns UpdateSmartClassTagPatchSmartClassTag.Id, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassTagPatchSmartClassTag) GetId() string { return v.Id } + +// GetName returns UpdateSmartClassTagPatchSmartClassTag.Name, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassTagPatchSmartClassTag) GetName() string { return v.Name } + +// GetType returns UpdateSmartClassTagPatchSmartClassTag.Type, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassTagPatchSmartClassTag) GetType() SmartClassTagType { return v.Type } + +// GetValue returns UpdateSmartClassTagPatchSmartClassTag.Value, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassTagPatchSmartClassTag) GetValue() string { return v.Value } + +// UpdateSmartClassTagResponse is returned by UpdateSmartClassTag on success. +type UpdateSmartClassTagResponse struct { + PatchSmartClassTag UpdateSmartClassTagPatchSmartClassTag `json:"patchSmartClassTag"` +} + +// GetPatchSmartClassTag returns UpdateSmartClassTagResponse.PatchSmartClassTag, and is useful for accessing the field via an interface. +func (v *UpdateSmartClassTagResponse) GetPatchSmartClassTag() UpdateSmartClassTagPatchSmartClassTag { + return v.PatchSmartClassTag +} + // UpdateUserGroupResponse is returned by UpdateUserGroup on success. type UpdateUserGroupResponse struct { UpdateIamGroup UpdateUserGroupUpdateIamGroupV1Group `json:"updateIamGroup"` @@ -4212,6 +4612,30 @@ type __CreateResourceGroupInput struct { // GetInput returns __CreateResourceGroupInput.Input, and is useful for accessing the field via an interface. func (v *__CreateResourceGroupInput) GetInput() CreateIamResourceGroupInput { return v.Input } +// __CreateSmartClassInput is used internally by genqlient +type __CreateSmartClassInput struct { + Input CreateSmartClassInput `json:"input"` +} + +// GetInput returns __CreateSmartClassInput.Input, and is useful for accessing the field via an interface. +func (v *__CreateSmartClassInput) GetInput() CreateSmartClassInput { return v.Input } + +// __CreateSmartClassQueryInput is used internally by genqlient +type __CreateSmartClassQueryInput struct { + Input CreateSmartClassQueryInput `json:"input"` +} + +// GetInput returns __CreateSmartClassQueryInput.Input, and is useful for accessing the field via an interface. +func (v *__CreateSmartClassQueryInput) GetInput() CreateSmartClassQueryInput { return v.Input } + +// __CreateSmartClassTagInput is used internally by genqlient +type __CreateSmartClassTagInput struct { + Input CreateSmartClassTagInput `json:"input"` +} + +// GetInput returns __CreateSmartClassTagInput.Input, and is useful for accessing the field via an interface. +func (v *__CreateSmartClassTagInput) GetInput() CreateSmartClassTagInput { return v.Input } + // __CreateUserGroupInput is used internally by genqlient type __CreateUserGroupInput struct { Name string `json:"name"` @@ -4340,6 +4764,30 @@ type __DeleteRuleInstanceInput struct { // GetId returns __DeleteRuleInstanceInput.Id, and is useful for accessing the field via an interface. func (v *__DeleteRuleInstanceInput) GetId() string { return v.Id } +// __DeleteSmartClassInput is used internally by genqlient +type __DeleteSmartClassInput struct { + SmartClassId string `json:"smartClassId"` +} + +// GetSmartClassId returns __DeleteSmartClassInput.SmartClassId, and is useful for accessing the field via an interface. +func (v *__DeleteSmartClassInput) GetSmartClassId() string { return v.SmartClassId } + +// __DeleteSmartClassQueryInput is used internally by genqlient +type __DeleteSmartClassQueryInput struct { + SmartClassQueryId string `json:"smartClassQueryId"` +} + +// GetSmartClassQueryId returns __DeleteSmartClassQueryInput.SmartClassQueryId, and is useful for accessing the field via an interface. +func (v *__DeleteSmartClassQueryInput) GetSmartClassQueryId() string { return v.SmartClassQueryId } + +// __DeleteSmartClassTagInput is used internally by genqlient +type __DeleteSmartClassTagInput struct { + SmartClassTagId string `json:"smartClassTagId"` +} + +// GetSmartClassTagId returns __DeleteSmartClassTagInput.SmartClassTagId, and is useful for accessing the field via an interface. +func (v *__DeleteSmartClassTagInput) GetSmartClassTagId() string { return v.SmartClassTagId } + // __DeleteUserGroupInput is used internally by genqlient type __DeleteUserGroupInput struct { Name string `json:"name"` @@ -4456,6 +4904,22 @@ func (v *__GetResourcePermissionsInput) GetCursor() string { return v.Cursor } // GetLimit returns __GetResourcePermissionsInput.Limit, and is useful for accessing the field via an interface. func (v *__GetResourcePermissionsInput) GetLimit() int { return v.Limit } +// __GetSmartClassInput is used internally by genqlient +type __GetSmartClassInput struct { + SmartClassId string `json:"smartClassId"` +} + +// GetSmartClassId returns __GetSmartClassInput.SmartClassId, and is useful for accessing the field via an interface. +func (v *__GetSmartClassInput) GetSmartClassId() string { return v.SmartClassId } + +// __GetSmartClassQueryInput is used internally by genqlient +type __GetSmartClassQueryInput struct { + SmartClassQueryId string `json:"smartClassQueryId"` +} + +// GetSmartClassQueryId returns __GetSmartClassQueryInput.SmartClassQueryId, and is useful for accessing the field via an interface. +func (v *__GetSmartClassQueryInput) GetSmartClassQueryId() string { return v.SmartClassQueryId } + // __GetUserGroupInput is used internally by genqlient type __GetUserGroupInput struct { Id string `json:"id"` @@ -4634,6 +5098,30 @@ type __UpdateResourceGroupInput struct { // GetInput returns __UpdateResourceGroupInput.Input, and is useful for accessing the field via an interface. func (v *__UpdateResourceGroupInput) GetInput() UpdateIamResourceGroupInput { return v.Input } +// __UpdateSmartClassInput is used internally by genqlient +type __UpdateSmartClassInput struct { + Input PatchSmartClassInput `json:"input"` +} + +// GetInput returns __UpdateSmartClassInput.Input, and is useful for accessing the field via an interface. +func (v *__UpdateSmartClassInput) GetInput() PatchSmartClassInput { return v.Input } + +// __UpdateSmartClassQueryInput is used internally by genqlient +type __UpdateSmartClassQueryInput struct { + Input PatchSmartClassQueryInput `json:"input"` +} + +// GetInput returns __UpdateSmartClassQueryInput.Input, and is useful for accessing the field via an interface. +func (v *__UpdateSmartClassQueryInput) GetInput() PatchSmartClassQueryInput { return v.Input } + +// __UpdateSmartClassTagInput is used internally by genqlient +type __UpdateSmartClassTagInput struct { + Input PatchSmartClassTagInput `json:"input"` +} + +// GetInput returns __UpdateSmartClassTagInput.Input, and is useful for accessing the field via an interface. +func (v *__UpdateSmartClassTagInput) GetInput() PatchSmartClassTagInput { return v.Input } + // __UpdateUserGroupInput is used internally by genqlient type __UpdateUserGroupInput struct { Id string `json:"id"` @@ -5081,6 +5569,110 @@ fragment ResourceGroup on IamResourceGroup { return &data, err } +func CreateSmartClass( + ctx context.Context, + client graphql.Client, + input CreateSmartClassInput, +) (*CreateSmartClassResponse, error) { + req := &graphql.Request{ + OpName: "CreateSmartClass", + Query: ` +mutation CreateSmartClass ($input: CreateSmartClassInput!) { + createSmartClass(input: $input) { + id + tagName + description + } +} +`, + Variables: &__CreateSmartClassInput{ + Input: input, + }, + } + var err error + + var data CreateSmartClassResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func CreateSmartClassQuery( + ctx context.Context, + client graphql.Client, + input CreateSmartClassQueryInput, +) (*CreateSmartClassQueryResponse, error) { + req := &graphql.Request{ + OpName: "CreateSmartClassQuery", + Query: ` +mutation CreateSmartClassQuery ($input: CreateSmartClassQueryInput!) { + createSmartClassQuery(input: $input) { + id + query + smartClassId + description + } +} +`, + Variables: &__CreateSmartClassQueryInput{ + Input: input, + }, + } + var err error + + var data CreateSmartClassQueryResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func CreateSmartClassTag( + ctx context.Context, + client graphql.Client, + input CreateSmartClassTagInput, +) (*CreateSmartClassTagResponse, error) { + req := &graphql.Request{ + OpName: "CreateSmartClassTag", + Query: ` +mutation CreateSmartClassTag ($input: CreateSmartClassTagInput!) { + createSmartClassTag(input: $input) { + id + name + type + value + } +} +`, + Variables: &__CreateSmartClassTagInput{ + Input: input, + }, + } + var err error + + var data CreateSmartClassTagResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + func CreateUserGroup( ctx context.Context, client graphql.Client, @@ -5546,6 +6138,102 @@ mutation DeleteRuleInstance ($id: ID!) { return &data, err } +func DeleteSmartClass( + ctx context.Context, + client graphql.Client, + smartClassId string, +) (*DeleteSmartClassResponse, error) { + req := &graphql.Request{ + OpName: "DeleteSmartClass", + Query: ` +mutation DeleteSmartClass ($smartClassId: ID!) { + deleteSmartClass(id: $smartClassId) { + success + } +} +`, + Variables: &__DeleteSmartClassInput{ + SmartClassId: smartClassId, + }, + } + var err error + + var data DeleteSmartClassResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func DeleteSmartClassQuery( + ctx context.Context, + client graphql.Client, + smartClassQueryId string, +) (*DeleteSmartClassQueryResponse, error) { + req := &graphql.Request{ + OpName: "DeleteSmartClassQuery", + Query: ` +mutation DeleteSmartClassQuery ($smartClassQueryId: ID!) { + deleteSmartClassQuery(id: $smartClassQueryId) { + success + } +} +`, + Variables: &__DeleteSmartClassQueryInput{ + SmartClassQueryId: smartClassQueryId, + }, + } + var err error + + var data DeleteSmartClassQueryResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func DeleteSmartClassTag( + ctx context.Context, + client graphql.Client, + smartClassTagId string, +) (*DeleteSmartClassTagResponse, error) { + req := &graphql.Request{ + OpName: "DeleteSmartClassTag", + Query: ` +mutation DeleteSmartClassTag ($smartClassTagId: ID!) { + deleteSmartClassTag(id: $smartClassTagId) { + success + } +} +`, + Variables: &__DeleteSmartClassTagInput{ + SmartClassTagId: smartClassTagId, + }, + } + var err error + + var data DeleteSmartClassTagResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + func DeleteUserGroup( ctx context.Context, client graphql.Client, @@ -6161,6 +6849,81 @@ query GetResourcePermissions ($filter: GetResourcePermissionsFilter!, $cursor: S return &data, err } +func GetSmartClass( + ctx context.Context, + client graphql.Client, + smartClassId string, +) (*GetSmartClassResponse, error) { + req := &graphql.Request{ + OpName: "GetSmartClass", + Query: ` +query GetSmartClass ($smartClassId: ID!) { + smartClass(id: $smartClassId) { + id + tagName + description + tags { + id + name + type + value + } + } +} +`, + Variables: &__GetSmartClassInput{ + SmartClassId: smartClassId, + }, + } + var err error + + var data GetSmartClassResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func GetSmartClassQuery( + ctx context.Context, + client graphql.Client, + smartClassQueryId string, +) (*GetSmartClassQueryResponse, error) { + req := &graphql.Request{ + OpName: "GetSmartClassQuery", + Query: ` +query GetSmartClassQuery ($smartClassQueryId: ID!) { + smartClassQuery(id: $smartClassQueryId) { + id + query + smartClassId + description + } +} +`, + Variables: &__GetSmartClassQueryInput{ + SmartClassQueryId: smartClassQueryId, + }, + } + var err error + + var data GetSmartClassQueryResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + func GetUserGroup( ctx context.Context, client graphql.Client, @@ -6826,6 +7589,109 @@ fragment ResourceGroup on IamResourceGroup { return &data, err } +func UpdateSmartClass( + ctx context.Context, + client graphql.Client, + input PatchSmartClassInput, +) (*UpdateSmartClassResponse, error) { + req := &graphql.Request{ + OpName: "UpdateSmartClass", + Query: ` +mutation UpdateSmartClass ($input: PatchSmartClassInput!) { + patchSmartClass(input: $input) { + id + description + } +} +`, + Variables: &__UpdateSmartClassInput{ + Input: input, + }, + } + var err error + + var data UpdateSmartClassResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func UpdateSmartClassQuery( + ctx context.Context, + client graphql.Client, + input PatchSmartClassQueryInput, +) (*UpdateSmartClassQueryResponse, error) { + req := &graphql.Request{ + OpName: "UpdateSmartClassQuery", + Query: ` +mutation UpdateSmartClassQuery ($input: PatchSmartClassQueryInput!) { + patchSmartClassQuery(input: $input) { + id + query + smartClassId + description + } +} +`, + Variables: &__UpdateSmartClassQueryInput{ + Input: input, + }, + } + var err error + + var data UpdateSmartClassQueryResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func UpdateSmartClassTag( + ctx context.Context, + client graphql.Client, + input PatchSmartClassTagInput, +) (*UpdateSmartClassTagResponse, error) { + req := &graphql.Request{ + OpName: "UpdateSmartClassTag", + Query: ` +mutation UpdateSmartClassTag ($input: PatchSmartClassTagInput!) { + patchSmartClassTag(input: $input) { + id + name + type + value + } +} +`, + Variables: &__UpdateSmartClassTagInput{ + Input: input, + }, + } + var err error + + var data UpdateSmartClassTagResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + func UpdateUserGroup( ctx context.Context, client graphql.Client, diff --git a/jupiterone/internal/client/genqlient.yaml b/jupiterone/internal/client/genqlient.yaml index e604eb1e..5cc11638 100644 --- a/jupiterone/internal/client/genqlient.yaml +++ b/jupiterone/internal/client/genqlient.yaml @@ -13,6 +13,7 @@ operations: - integration.graphql - resourcePermissions.graphql - resourceGroups.graphql + - smartClasses.graphql generated: generated.go bindings: diff --git a/jupiterone/internal/client/smartClasses.graphql b/jupiterone/internal/client/smartClasses.graphql new file mode 100644 index 00000000..1ac03886 --- /dev/null +++ b/jupiterone/internal/client/smartClasses.graphql @@ -0,0 +1,91 @@ +query GetSmartClass($smartClassId: ID!) { + smartClass(id: $smartClassId) { + id + tagName + description + tags { + id + name + type + value + } + } +} + +mutation CreateSmartClass($input: CreateSmartClassInput!) { + createSmartClass(input: $input) { + id + tagName + description + } +} + +mutation DeleteSmartClass($smartClassId: ID!) { + deleteSmartClass(id: $smartClassId) { + success + } +} + +mutation UpdateSmartClass($input: PatchSmartClassInput!) { + patchSmartClass(input: $input) { + id + description + } +} + +query GetSmartClassQuery($smartClassQueryId: ID!) { + smartClassQuery(id: $smartClassQueryId) { + id + query + smartClassId + description + } +} + +mutation CreateSmartClassQuery($input: CreateSmartClassQueryInput!) { + createSmartClassQuery(input: $input) { + id + query + smartClassId + description + } +} + +mutation DeleteSmartClassQuery($smartClassQueryId: ID!) { + deleteSmartClassQuery(id: $smartClassQueryId) { + success + } +} + +mutation UpdateSmartClassQuery($input: PatchSmartClassQueryInput!) { + patchSmartClassQuery(input: $input) { + id + query + smartClassId + description + } +} + +mutation CreateSmartClassTag($input: CreateSmartClassTagInput!) { + createSmartClassTag(input: $input) { + id + name + type + value + } +} + +mutation DeleteSmartClassTag($smartClassTagId: ID!) { + deleteSmartClassTag(id: $smartClassTagId) { + success + } +} + +mutation UpdateSmartClassTag($input: PatchSmartClassTagInput!) { + patchSmartClassTag(input: $input) { + id + name + type + value + } +} \ No newline at end of file diff --git a/jupiterone/provider.go b/jupiterone/provider.go index 612cc807..9b23c1ab 100644 --- a/jupiterone/provider.go +++ b/jupiterone/provider.go @@ -146,6 +146,9 @@ func (*JupiterOneProvider) Resources(context.Context) []func() resource.Resource NewIntegrationResource, NewResourcePermissionResource, NewResourceGroupResource, + NewSmartClassResource, + NewSmartClassQueryResource, + NewSmartClassTagResource, } } diff --git a/jupiterone/resource_resource_group.go b/jupiterone/resource_resource_group.go index bc8de128..d437ecba 100644 --- a/jupiterone/resource_resource_group.go +++ b/jupiterone/resource_resource_group.go @@ -164,14 +164,10 @@ func (r *ResourceGroupResource) Read(ctx context.Context, req resource.ReadReque if strings.Contains(err.Error(), "Item not found") { resp.State.RemoveResource(ctx) } else { - resp.Diagnostics.AddError("failed to get user group", err.Error()) + resp.Diagnostics.AddError("failed to get resource group", err.Error()) } return } - if err != nil { - resp.Diagnostics.AddError("failed to get resource group", err.Error()) - return - } data.Name = types.StringValue(resourceGroup.ResourceGroup.Name) diff --git a/jupiterone/resource_smart_class.go b/jupiterone/resource_smart_class.go new file mode 100644 index 00000000..665a398f --- /dev/null +++ b/jupiterone/resource_smart_class.go @@ -0,0 +1,171 @@ +package jupiterone + +import ( + "context" + "fmt" + "strings" + + "github.com/Khan/genqlient/graphql" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/jupiterone/terraform-provider-jupiterone/jupiterone/internal/client" +) + +type SmartClassResource struct { + version string + qlient graphql.Client +} + +func NewSmartClassResource() resource.Resource { + return &SmartClassResource{} +} + +type SmartClassRule struct { + EvaluationStep types.String `json:"evaluation_step,omitempty" tfsdk:"evaluation_step"` + LastEvaluationEndOn types.Int64 `json:"last_evaluation_end_on,omitempty" tfsdk:"last_evaluation_end_on"` +} + +type SmartClass struct { + Id types.String `json:"id,omitempty" tfsdk:"id"` + Description types.String `json:"description,omitempty" tfsdk:"description"` + TagName types.String `json:"tag_name,omitempty" tfsdk:"tag_name"` +} + +func (r *SmartClassResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data SmartClass + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + mutationResult, err := client.CreateSmartClass(ctx, r.qlient, client.CreateSmartClassInput{ + TagName: data.TagName.ValueString(), + Description: data.Description.ValueString(), + }) + + if err != nil { + resp.Diagnostics.AddError("Failed to create smart class", err.Error()) + return + } + + data.Id = types.StringValue(mutationResult.CreateSmartClass.Id) + + tflog.Trace(ctx, "Created smart class", map[string]interface{}{"id": data.Id}) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SmartClassResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *SmartClass + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + smartClass, err := client.GetSmartClass(ctx, r.qlient, data.Id.ValueString()) + if err != nil { + if strings.Contains(err.Error(), "not found") { + resp.State.RemoveResource(ctx) + } else { + resp.Diagnostics.AddError("failed to get smart class", err.Error()) + } + return + } + + data.Id = types.StringValue(smartClass.SmartClass.Id) + data.TagName = types.StringValue(smartClass.SmartClass.TagName) + data.Description = types.StringValue(smartClass.SmartClass.Description) +} + +func (r *SmartClassResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *SmartClass + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + if _, err := client.UpdateSmartClass(ctx, r.qlient, client.PatchSmartClassInput{ + Id: data.Id.ValueString(), + Description: data.Description.ValueString(), + }); err != nil { + resp.Diagnostics.AddError("Failed to update smart class", err.Error()) + return + } + + tflog.Trace(ctx, "Updated smart class", map[string]interface{}{"id": data.Id}) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SmartClassResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *SmartClass + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + if _, err := client.DeleteSmartClass(ctx, r.qlient, data.Id.ValueString()); err != nil { + resp.Diagnostics.AddError("Failed to delete smart class", err.Error()) + } +} + +func (r *SmartClassResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func (r *SmartClassResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_smart_class" +} + +func (r *SmartClassResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + p, ok := req.ProviderData.(*JupiterOneProvider) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected JupiterOneProvider, got %T. Please report this issue to the provider developers.", req.ProviderData), + ) + } + + r.version = p.version + r.qlient = p.Qlient + +} + +func (r *SmartClassResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "JupiterOne Smart Class", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "tag_name": schema.StringAttribute{ + Required: true, + Description: "The tag name of the smart class.", + }, + "description": schema.StringAttribute{ + Optional: true, + Description: "The description of the smart class.", + }, + }, + } + +} diff --git a/jupiterone/resource_smart_class_query.go b/jupiterone/resource_smart_class_query.go new file mode 100644 index 00000000..c849bdfa --- /dev/null +++ b/jupiterone/resource_smart_class_query.go @@ -0,0 +1,177 @@ +package jupiterone + +import ( + "context" + "fmt" + "strings" + + "github.com/Khan/genqlient/graphql" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/jupiterone/terraform-provider-jupiterone/jupiterone/internal/client" +) + +type SmartClassQuery struct { + Id types.String `json:"id,omitempty" tfsdk:"id"` + Query types.String `json:"query,omitempty" tfsdk:"query"` + SmartClassId types.String `json:"smart_class_id,omitempty" tfsdk:"smart_class_id"` + Description types.String `json:"description,omitempty" tfsdk:"description"` +} + +func NewSmartClassQueryResource() resource.Resource { + return &SmartClassQueryResource{} +} + +type SmartClassQueryResource struct { + version string + qlient graphql.Client +} + +func (r *SmartClassQueryResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_smart_class_query" +} + +func (r *SmartClassQueryResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "query": schema.StringAttribute{ + Required: true, + Description: "The J1QL query to find entities for the smart class", + }, + "smart_class_id": schema.StringAttribute{ + Required: true, + Description: "The ID of the smart class to associate the query with", + }, + "description": schema.StringAttribute{ + Required: true, + Description: "A description of the smart class query", + }, + }, + } +} + +func (r *SmartClassQueryResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + p, ok := req.ProviderData.(*JupiterOneProvider) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected JupiterOneProvider, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.version = p.version + r.qlient = p.Qlient +} + +func (r *SmartClassQueryResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func (r *SmartClassQueryResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data SmartClassQuery + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + mutationResult, err := client.CreateSmartClassQuery(ctx, r.qlient, client.CreateSmartClassQueryInput{ + Query: data.Query.ValueString(), + SmartClassId: data.SmartClassId.ValueString(), + Description: data.Description.ValueString(), + }) + + if err != nil { + resp.Diagnostics.AddError("Failed to create smart class query", err.Error()) + return + } + + data.Id = types.StringValue(mutationResult.CreateSmartClassQuery.Id) + + tflog.Trace(ctx, "Created smart class query", map[string]interface{}{"id": data.Id}) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SmartClassQueryResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *SmartClassQuery + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + smartClassQuery, err := client.GetSmartClassQuery(ctx, r.qlient, data.Id.ValueString()) + if err != nil { + if strings.Contains(err.Error(), "not found") { + resp.State.RemoveResource(ctx) + } else { + resp.Diagnostics.AddError("Failed to get smart class query", err.Error()) + } + return + } + + data.Id = types.StringValue(smartClassQuery.SmartClassQuery.Id) + data.Query = types.StringValue(smartClassQuery.SmartClassQuery.Query) + data.SmartClassId = types.StringValue(smartClassQuery.SmartClassQuery.SmartClassId) + data.Description = types.StringValue(smartClassQuery.SmartClassQuery.Description) +} + +func (r *SmartClassQueryResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data SmartClassQuery + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := client.UpdateSmartClassQuery(ctx, r.qlient, client.PatchSmartClassQueryInput{ + Id: data.Id.ValueString(), + Query: data.Query.ValueString(), + Description: data.Description.ValueString(), + }) + + if err != nil { + resp.Diagnostics.AddError("Failed to update smart class query", err.Error()) + return + } + + tflog.Trace(ctx, "Updated smart class query", map[string]interface{}{"id": data.Id}) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SmartClassQueryResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *SmartClassQuery + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + if _, err := client.DeleteSmartClassQuery(ctx, r.qlient, data.Id.ValueString()); err != nil { + resp.Diagnostics.AddError("Failed to delete smart class query", err.Error()) + return + } + + resp.State.RemoveResource(ctx) +} diff --git a/jupiterone/resource_smart_class_tag.go b/jupiterone/resource_smart_class_tag.go new file mode 100644 index 00000000..f1ffa791 --- /dev/null +++ b/jupiterone/resource_smart_class_tag.go @@ -0,0 +1,198 @@ +package jupiterone + +import ( + "context" + "fmt" + "strings" + + "github.com/Khan/genqlient/graphql" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/jupiterone/terraform-provider-jupiterone/jupiterone/internal/client" +) + +type SmartClassTag struct { + Id types.String `json:"id,omitempty" tfsdk:"id"` + SmartClassId types.String `json:"smart_class_id,omitempty" tfsdk:"smart_class_id"` + Name types.String `json:"name,omitempty" tfsdk:"name"` + Type types.String `json:"type,omitempty" tfsdk:"type"` + Value types.String `json:"value,omitempty" tfsdk:"value"` +} + +func NewSmartClassTagResource() resource.Resource { + return &SmartClassTagResource{} +} + +type SmartClassTagResource struct { + version string + qlient graphql.Client +} + +func (r *SmartClassTagResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_smart_class_tag" +} + +func (r *SmartClassTagResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "name": schema.StringAttribute{ + Required: true, + Description: "The name (key) of the tag", + }, + "type": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("string", "boolean", "number"), + }, + Description: "The type of the tag, one of 'string', 'boolean', or 'number'", + }, + "value": schema.StringAttribute{ + Required: true, + Description: "The value of the tag as a string", + }, + }, + } +} + +func (r *SmartClassTagResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + p, ok := req.ProviderData.(*JupiterOneProvider) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected JupiterOneProvider, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.version = p.version + r.qlient = p.Qlient +} + +func (r *SmartClassTagResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func (r *SmartClassTagResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data SmartClassTag + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + mutationResult, err := client.CreateSmartClassTag(ctx, r.qlient, client.CreateSmartClassTagInput{ + SmartClassId: data.SmartClassId.ValueString(), + Type: client.SmartClassTagType(data.Type.ValueString()), + Name: data.Name.ValueString(), + Value: data.Value.ValueString(), + }) + + if err != nil { + resp.Diagnostics.AddError("Failed to create smart class Tag", err.Error()) + return + } + + data.Id = types.StringValue(mutationResult.CreateSmartClassTag.Id) + + tflog.Trace(ctx, "Created smart class Tag", map[string]interface{}{"id": data.Id}) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SmartClassTagResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *SmartClassTag + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + smartClass, err := client.GetSmartClass(ctx, r.qlient, data.SmartClassId.ValueString()) + + if err != nil { + resp.Diagnostics.AddError("Failed to read smart class Tag", err.Error()) + return + } + + var smartClassTag client.GetSmartClassSmartClassTagsSmartClassTag + found := false + for _, tag := range smartClass.SmartClass.Tags { + if strings.EqualFold(tag.Id, data.Id.ValueString()) { + smartClassTag = tag + found = true + break + } + } + + if !found { + resp.Diagnostics.AddError("Failed to read smart class Tag", "Tag not found on smart class") + return + } + + data.Id = types.StringValue(smartClassTag.Id) + data.Type = types.StringValue(string(smartClassTag.Type)) + data.Name = types.StringValue(smartClassTag.Name) + data.Value = types.StringValue(smartClassTag.Value) + data.SmartClassId = types.StringValue(data.SmartClassId.ValueString()) +} + +func (r *SmartClassTagResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data SmartClassTag + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := client.UpdateSmartClassTag(ctx, r.qlient, client.PatchSmartClassTagInput{ + Id: data.Id.ValueString(), + Type: client.SmartClassTagType(data.Type.ValueString()), + Name: data.Name.ValueString(), + Value: data.Value.ValueString(), + }) + + if err != nil { + resp.Diagnostics.AddError("Failed to update smart class Tag", err.Error()) + return + } + + tflog.Trace(ctx, "Updated smart class Tag", map[string]interface{}{"id": data.Id}) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SmartClassTagResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *SmartClassTag + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + if _, err := client.DeleteSmartClassTag(ctx, r.qlient, data.Id.ValueString()); err != nil { + resp.Diagnostics.AddError("Failed to delete smart class Tag", err.Error()) + return + } + + resp.State.RemoveResource(ctx) +} diff --git a/jupiterone/resource_smart_class_test.go b/jupiterone/resource_smart_class_test.go new file mode 100644 index 00000000..dc30bf07 --- /dev/null +++ b/jupiterone/resource_smart_class_test.go @@ -0,0 +1,174 @@ +package jupiterone + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + + "github.com/Khan/genqlient/graphql" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/jupiterone/terraform-provider-jupiterone/jupiterone/internal/client" +) + +func TestSmartClass_Basic(t *testing.T) { + ctx := context.TODO() + + recordingClient, directClient, cleanup := setupTestClients(ctx, t) + defer cleanup(t) + + resourceName := "jupiterone_smart_class.test" + smartClassTagName := "TfProviderTestSmartClass" + smartClassDescription := "description of " + smartClassTagName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(recordingClient), + CheckDestroy: testAccCheckSmartClassDestroy(ctx, directClient), + Steps: []resource.TestStep{ + { + Config: testSmartClassBasicConfig(smartClassTagName, smartClassDescription), + Check: resource.ComposeTestCheckFunc( + testAccCheckSmartClassExists(ctx, directClient), + resource.TestCheckResourceAttrSet(resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "tag_name", smartClassTagName), + resource.TestCheckResourceAttr(resourceName, "description", smartClassDescription), + ), + }, + }, + }) +} + +func TestSmartClass_BasicImport(t *testing.T) { + ctx := context.TODO() + + recordingClient, directClient, cleanup := setupTestClients(ctx, t) + defer cleanup(t) + + resourceName := "jupiterone_smart_class.test" + smartClassTagName := "TfProviderTestImport" + smartClassDescription := "description of " + smartClassTagName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(recordingClient), + Steps: []resource.TestStep{ + { + ImportState: true, + ResourceName: resourceName, + ImportStateId: createTestSmartClass(ctx, t, recordingClient, smartClassTagName, smartClassDescription), + Config: testSmartClassBasicConfig(smartClassTagName, smartClassDescription), + Check: resource.ComposeTestCheckFunc( + testAccCheckSmartClassExists(ctx, directClient), + resource.TestCheckResourceAttrSet(resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "tag_name", smartClassTagName), + resource.TestCheckResourceAttr(resourceName, "description", smartClassDescription), + ), + }, + }, + }) +} + +func createTestSmartClass(ctx context.Context, t *testing.T, qlient graphql.Client, tagName string, description string) string { + r, err := client.CreateSmartClass(ctx, qlient, client.CreateSmartClassInput{ + TagName: tagName, + Description: description, + }) + if err != nil { + t.Log("error creating smart class import test", err) + t.FailNow() + } + + return r.CreateSmartClass.Id +} + +func testAccCheckSmartClassExists(ctx context.Context, qlient graphql.Client) resource.TestCheckFunc { + return func(s *terraform.State) error { + if err := smartClassExistsHelper(ctx, s, qlient); err != nil { + return err + } + return nil + } +} + +func smartClassExistsHelper(ctx context.Context, s *terraform.State, qlient graphql.Client) error { + if qlient == nil { + return nil + } + + duration := 10 * time.Second + for _, r := range s.RootModule().Resources { + err := retry.RetryContext(ctx, duration, func() *retry.RetryError { + id := r.Primary.ID + _, err := client.GetSmartClass(ctx, qlient, id) + + if err == nil { + return nil + } + + if strings.Contains(err.Error(), "Smart class string does not exist") { + return retry.RetryableError(fmt.Errorf("Smart class does not exist (id=%q)", id)) + } + + return retry.NonRetryableError(err) + }) + + if err != nil { + return err + } + } + + return nil +} + +func testAccCheckSmartClassDestroy(ctx context.Context, qlient graphql.Client) func(*terraform.State) error { + return func(s *terraform.State) error { + if err := smartClassDestroyHelper(ctx, s, qlient); err != nil { + return err + } + return nil + } +} + +func smartClassDestroyHelper(ctx context.Context, s *terraform.State, qlient graphql.Client) error { + if qlient == nil { + return nil + } + + duration := 10 * time.Second + for _, r := range s.RootModule().Resources { + err := retry.RetryContext(ctx, duration, func() *retry.RetryError { + id := r.Primary.ID + _, err := client.GetSmartClass(ctx, qlient, id) + + if err == nil { + return retry.RetryableError(fmt.Errorf("Smart class still exists (id=%q)", id)) + } + + if strings.Contains(err.Error(), "does not exist") { + return nil + } + + return retry.NonRetryableError(err) + }) + + if err != nil { + return err + } + } + return nil +} + +func testSmartClassBasicConfig(tagName string, description string) string { + return fmt.Sprintf(` + provider "jupiterone" {} + + resource "jupiterone_smart_class" "test" { + tag_name = %q + description = %q + } + `, tagName, description) +} diff --git a/scripts/get_current_schema.bash b/scripts/get_current_schema.bash index fb9907a6..4aad0b88 100755 --- a/scripts/get_current_schema.bash +++ b/scripts/get_current_schema.bash @@ -20,7 +20,7 @@ if [ -f "introspection_result.json" ]; then echo "Using already downloaded results, delete introspection_result.json to force a fetch" else curl --fail --location --request POST "${JUPITERONE_URL}" \ - --header "LifeOmic-Account: ${JUPITERONE_ACCOUNT}" \ + --header "LifeOmic-Account: ${JUPITERONE_ACCOUNT_ID}" \ --header "Authorization: Bearer ${JUPITERONE_API_KEY}" \ --header 'Content-Type: application/json' \ --output introspection_result.json \