Skip to content

Commit

Permalink
ENG-12679: Add data source for sidecar instance API (#457)
Browse files Browse the repository at this point in the history
* Add sidecar instance data source

* Deprecate cyral_sidecar_instance_ids data source

* Update docs

* Add tests

* Update docs

* Update docs

* Rename structures
  • Loading branch information
VictorGFM committed Oct 2, 2023
1 parent d4be7c9 commit fbaf876
Show file tree
Hide file tree
Showing 9 changed files with 576 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ make docker-compose/docs
pre-commit run --show-diff-on-failure --color=always --all-files
```

> **_Note_** that due to a [limitation of the tfplugindocs tool](https://github.com/hashicorp/terraform-plugin-docs/issues/28), some descriptions might not be automatically generated for nested fields. In this case, its necessary to generate the documentation manually by editing the template file - in the `templates` folder - corresponding to the resource/data-source.
> `pre-commit` can sometimes fail because your user is not the owner of the files in the `/docs` directory.
> To solve this problem, run the following command and re-run the `pre-commit run...` tried in the previous step:
Expand Down
196 changes: 196 additions & 0 deletions cyral/data_source_cyral_sidecar_instance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package cyral

import (
"fmt"
"net/http"

"github.com/cyralinc/terraform-provider-cyral/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

const (
// Schema keys
SidecarInstanceListKey = "instance_list"
MetadataKey = "metadata"
MonitoringKey = "monitoring"
VersionKey = "version"
DynamicVersionKey = "dynamic_version"
CapabilitiesKey = "capabilities"
StartTimestampKey = "start_timestamp"
LastRegistrationKey = "last_registration"
RecyclingKey = "recycling"
RecyclableKey = "recyclable"
ServicesKey = "services"
MetricsPortKey = "metrics_port"
ComponentsKey = "components"
ErrorKey = "error"
)

func dataSourceSidecarInstance() *schema.Resource {
return &schema.Resource{
Description: "Retrieve sidecar instances.",
ReadContext: ReadResource(ResourceOperationConfig{
Name: "SidecarInstanceDataSourceRead",
HttpMethod: http.MethodGet,
CreateURL: func(d *schema.ResourceData, c *client.Client) string {
return fmt.Sprintf(
"https://%s/v2/sidecars/%s/instances",
c.ControlPlane, d.Get(SidecarIDKey),
)
},
NewResponseData: func(_ *schema.ResourceData) ResponseData {
return &SidecarInstances{}
},
}),
Schema: map[string]*schema.Schema{
SidecarIDKey: {
Description: "Sidecar identifier.",
Type: schema.TypeString,
Required: true,
},
IDKey: {
Description: "Data source identifier.",
Type: schema.TypeString,
Computed: true,
},
SidecarInstanceListKey: {
Description: "List of existing sidecar instances.",
Computed: true,
Type: schema.TypeList,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
IDKey: {
Description: "Instance identifier. Varies according to the computing platform that " +
"the sidecar is deployed to.",
Type: schema.TypeString,
Computed: true,
},
MetadataKey: {
Description: "Instance metadata.",
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
VersionKey: {
Description: "Sidecar version that the instance is using.",
Type: schema.TypeString,
Computed: true,
},
DynamicVersionKey: {
Description: "If true, indicates that the instance has dynamic versioning, " +
"that means that the version is not fixed at template level and it can be " +
"automatically upgraded.",
Type: schema.TypeBool,
Computed: true,
},
CapabilitiesKey: {
Description: "Set of capabilities that can be enabled or disabled. **Note**: This " +
"field is per-instance, not per-sidecar, because not all sidecar instances might be " +
"in sync at some point in time.",
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
RecyclableKey: {
Description: "Indicates if sidecar instance will be recycled (e.g., by an ASG) " +
"if it reports itself as unhealthy.",
Type: schema.TypeBool,
Computed: true,
},
},
},
},
StartTimestampKey: {
Description: "The time when the instance started.",
Type: schema.TypeString,
Computed: true,
},
LastRegistrationKey: {
Description: "The last time the instance reported to the Control Plane.",
Type: schema.TypeString,
Computed: true,
},
RecyclingKey: {
Description: "Indicates whether the Control Plane has asked the instance to mark " +
"itself unhealthy so that it is recycled by the infrastructure.",
Type: schema.TypeBool,
Computed: true,
},
},
},
},
MonitoringKey: {
Description: "Instance monitoring information, such as its overall health.",
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
StatusKey: {
Description: "Aggregated status of all the sidecar services.",
Type: schema.TypeString,
Computed: true,
},
ServicesKey: {
Description: "Sidecar instance services monitoring information.",
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeSet,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
StatusKey: {
Description: "Aggregated status of sidecar service.",
Type: schema.TypeString,
Computed: true,
},
MetricsPortKey: {
Description: "Metrics port for service monitoring.",
Type: schema.TypeInt,
Computed: true,
},
ComponentsKey: {
Description: "Map of name to monitoring component. A component is a " +
"monitored check on the service that has its own status.",
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeSet,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
StatusKey: {
Description: "Component status.",
Type: schema.TypeString,
Computed: true,
},
DescriptionKey: {
Description: "Describes what the type of check the component represents.",
Type: schema.TypeString,
Computed: true,
},
ErrorKey: {
Description: "Error that describes what caused the current status.",
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
HostKey: {
Description: "Service host on the deployment.",
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
},
},
},
},
},
},
},
}
}
6 changes: 4 additions & 2 deletions cyral/data_source_cyral_sidecar_instance_ids.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ import (
)

type SidecarDetails struct {
Instances []SidecarInstance `json:"instances,omitempty"`
Instances []DeprecatedSidecarInstances `json:"instances,omitempty"`
}

type SidecarInstance struct {
type DeprecatedSidecarInstances struct {
ASGInstanceID string `json:"asg_instance,omitempty"`
}

func dataSourceSidecarInstanceIDs() *schema.Resource {
return &schema.Resource{
DeprecationMessage: "This data source was deprecated. It will be removed in the next major version of " +
"the provider. Use the data source `cyral_sidecar_instance` instead",
Description: "Retrieves the IDs of all the current instances of a given sidecar.",
ReadContext: dataSourceSidecarInstanceIDsRead,
Schema: map[string]*schema.Schema{
Expand Down
88 changes: 88 additions & 0 deletions cyral/data_source_cyral_sidecar_instance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package cyral

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

const (
sidecarInstanceDataSourceFullNameFmt = "data.cyral_sidecar_instance.%s"
)

func TestAccSidecarInstanceDataSource(t *testing.T) {
dataSourceName := "instances"
testSteps := []resource.TestStep{
accTestStepSidecarInstanceDataSource_EmptySidecarID(dataSourceName),
accTestStepSidecarInstanceDataSource_NoSidecarFoundForGivenID(dataSourceName),
accTestStepSidecarInstanceDataSource_NoSidecarInstances(dataSourceName),
}
resource.ParallelTest(
t, resource.TestCase{
ProviderFactories: providerFactories,
Steps: testSteps,
},
)
}

func accTestStepSidecarInstanceDataSource_EmptySidecarID(dataSourceName string) resource.TestStep {
config := fmt.Sprintf(`
data "cyral_sidecar_instance" "%s" {
}
`, dataSourceName)
return resource.TestStep{
Config: config,
ExpectError: regexp.MustCompile(fmt.Sprintf(`The argument "%s" is required`, SidecarIDKey)),
}
}

func accTestStepSidecarInstanceDataSource_NoSidecarFoundForGivenID(dataSourceName string) resource.TestStep {
nonExistentSidecarID := "some-non-existent-sidecar-id"
config := fmt.Sprintf(`
data "cyral_sidecar_instance" "%s" {
sidecar_id = %q
}
`, dataSourceName, nonExistentSidecarID)
return resource.TestStep{
Config: config,
ExpectError: regexp.MustCompile(fmt.Sprintf("sidecar with id '%s' does not exist", nonExistentSidecarID)),
}
}

func accTestStepSidecarInstanceDataSource_NoSidecarInstances(dataSourceName string) resource.TestStep {
// Creates a sidecar that doesn't have any instances, since it was not
// deployed.
config := formatBasicSidecarIntoConfig(
basicSidecarResName,
accTestName("data-sidecar-instance", "sidecar"),
"cft-ec2",
"",
)
config += fmt.Sprintf(`
data "cyral_sidecar_instance" "%s" {
sidecar_id = %s
}
`, dataSourceName, basicSidecarID)
dataSourceFullName := fmt.Sprintf(sidecarInstanceDataSourceFullNameFmt, dataSourceName)
check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(
dataSourceFullName,
SidecarIDKey,
),
resource.TestCheckResourceAttrSet(
dataSourceFullName,
IDKey,
),
resource.TestCheckResourceAttr(
dataSourceFullName,
fmt.Sprintf("%s.#", SidecarInstanceListKey),
"0",
),
)
return resource.TestStep{
Config: config,
Check: check,
}
}
Loading

0 comments on commit fbaf876

Please sign in to comment.