Skip to content
This repository has been archived by the owner on Jun 2, 2024. It is now read-only.

Commit

Permalink
Merge pull request #59 from gessnerfl/feature/51_app_config_boundary_…
Browse files Browse the repository at this point in the history
…scope

closes #51: feature implemented, automated tests in place, q-metrics ok, manual test applied
  • Loading branch information
gessnerfl authored Aug 21, 2020
2 parents 8e6de4d + 3bce964 commit f5f994f
Show file tree
Hide file tree
Showing 7 changed files with 360 additions and 89 deletions.
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ to the application config label when active.
resource "instana_application_config" "example" {
label = "label"
scope = "INCLUDE_ALL_DOWNSTREAM" #Optional, default = INCLUDE_NO_DOWNSTREAM
boundary_scope = "INBOUND" #Optional, default = INBOUND
match_specification = "agent.tag.stage EQUALS 'test' OR aws.ec2.tag.stage EQUALS 'test' OR call.tag.stage EQUALS 'test'"
}
```
Expand All @@ -96,6 +97,12 @@ For **scope** the following three options are allowed:
- INCLUDE_NO_DOWNSTREAM
- INCLUDE_IMMEDIATE_DOWNSTREAM_DATABASE_AND_MESSAGING

For **boundary_scope** the following three options are allowed:

- INBOUND
- ALL
- DEFAULT

The **match_specification** defines which entities should be included into the application. It supports:

- logical AND and/or logical OR conjunctions whereas AND has higher precedence then OR
Expand All @@ -110,7 +117,7 @@ binary_operation := logical_and OR logical_or | logical_and
logical_and := primary_expression AND logical_and | primary_expression
primary_expression := comparison | unary_operator_expression
comparison := key comparison_operator value
comparison_operator := EQUALS | NOT_EQUAL | CONTAINS | NOT_CONTAIN
comparison_operator := EQUALS | NOT_EQUAL | CONTAINS | NOT_CONTAIN | STARTS_WITH | ENDS_WITH | NOT_STARTS_WITH | NOT_ENDS_WITH | GREATER_OR_EQUAL_THAN | LESS_OR_EQUAL_THAN | LESS_THAN | GREATER_THAN
unary_operator_expression := key unary_operator
unary_operator := IS_EMPTY | NOT_EMPTY | IS_BLANK | NOT_BLANK
key := [a-zA-Z][\.a-zA-Z0-9_\-]*
Expand Down Expand Up @@ -168,7 +175,7 @@ resource "instana_custom_event_spec_entity_verification_rule" "example" {
rule_severity = "warning"
rule_matching_entity_type = "process"
rule_matching_operator = "is"
rule_matching_operator = "is" #allowed values: is, contains, startsWith, starts_with, endsWith, ends_with
rule_matching_entity_label = "entity-label"
rule_offline_duration = 60000
}
Expand Down Expand Up @@ -198,9 +205,15 @@ resource "instana_custom_event_spec_threshold_rule" "example" {
rule_metric_name = "metric_name"
rule_window = 60000 #Optional
rule_rollup = 500 #Optional
rule_aggregation = "sum" #Optional depending on metric type
rule_condition_operator = "=="
rule_aggregation = "sum" #Optional depending on metric type, allowed values: sum, avg, min, max
rule_condition_operator = "==" #allowed values: ==, !=, <=, <, >, =>
rule_condition_value = 1.2
#For built-in dynamic metrics
rule_metric_pattern_prefix = "prefix" #Optional - required only for built in dynamic metrics
rule_metric_pattern_postfix = "postfix" #Optional
rule_metric_pattern_placeholder = "placeholder" #Optional
rule_metric_pattern_operator = "is" #Optional - required only for built in dynamic metrics; allowed values: is, contains, any, startsWith, endsWith
}
```

Expand Down Expand Up @@ -349,7 +362,7 @@ resource "instana_alerting_config" "example" {
alert_name = "name"
integration_ids = [ "alerting-channel-id1", "alerting-channel-id2" ] # Optional, you can also use references to existing alerting channel configurations
event_filter_query = "query" # Optional
event_filter_event_types = [ "incident", "critical" ] # Allowed values: incident, critical, warning, change, online, offline, none
event_filter_event_types = [ "incident", "critical" ] # Allowed values: incident, critical, warning, change, online, offline, agent_monitoring_issue, none
}
```

Expand Down
111 changes: 53 additions & 58 deletions instana/resource-application-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,68 @@ import (
//ResourceInstanaApplicationConfig the name of the terraform-provider-instana resource to manage application config
const ResourceInstanaApplicationConfig = "instana_application_config"

// matchSpecification := binaryOperation | tagMatcherExpression
// binaryOperation := matchSpecification conjunction matchSpecification
// conjunction := AND | OR
// tagMatcherExpreassion := key value operator
// operator := EQUALS | NOT_EQUAL | CONTAINS | NOT_CONTAIN | NOT_EMPTY

const (
//ApplicationConfigScopeIncludeNoDownstream constant for the scope INCLUDE_NO_DOWNSTREAM
ApplicationConfigScopeIncludeNoDownstream = "INCLUDE_NO_DOWNSTREAM"
//ApplicationConfigScopeIncludeImmediateDownstreamDatabaseAndMessaging constant for the scope INCLUDE_IMMEDIATE_DOWNSTREAM_DATABASE_AND_MESSAGING
ApplicationConfigScopeIncludeImmediateDownstreamDatabaseAndMessaging = "INCLUDE_IMMEDIATE_DOWNSTREAM_DATABASE_AND_MESSAGING"
//ApplicationConfigScopeIncludeAllDownstream constant for the scope INCLUDE_ALL_DOWNSTREAM
ApplicationConfigScopeIncludeAllDownstream = "INCLUDE_ALL_DOWNSTREAM"
)

const (
//ApplicationConfigFieldLabel const for the label field of the application config
ApplicationConfigFieldLabel = "label"
//ApplicationConfigFieldFullLabel const for the full label field of the application config. The field is computed and contains the label which is sent to instana. The computation depends on the configured default_name_prefix and default_name_suffix at provider level
ApplicationConfigFieldFullLabel = "full_label"
//ApplicationConfigFieldScope const for the scope field of the application config
ApplicationConfigFieldScope = "scope"
//ApplicationConfigFieldBoundaryScope const for the boundary_scope field of the application config
ApplicationConfigFieldBoundaryScope = "boundary_scope"
//ApplicationConfigFieldMatchSpecification const for the match_specification field of the application config
ApplicationConfigFieldMatchSpecification = "match_specification"
)

var (
//ApplicationConfigLabel schema for the application config field label
ApplicationConfigLabel = &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "The label of the application config",
}
//ApplicationConfigFullLabel schema for the application config field full_label
ApplicationConfigFullLabel = &schema.Schema{
Type: schema.TypeString,
Computed: true,
Description: "The the full label field of the application config. The field is computed and contains the label which is sent to instana. The computation depends on the configured default_name_prefix and default_name_suffix at provider level",
}
//ApplicationConfigScope schema for the application config field scope
ApplicationConfigScope = &schema.Schema{
Type: schema.TypeString,
Required: false,
Optional: true,
Default: string(restapi.ApplicationConfigScopeIncludeNoDownstream),
ValidateFunc: validation.StringInSlice(restapi.SupportedApplicationConfigScopes.ToStringSlice(), false),
Description: "The scope of the application config",
}
//ApplicationConfigBoundaryScope schema for the application config field boundary_scope
ApplicationConfigBoundaryScope = &schema.Schema{
Type: schema.TypeString,
Required: false,
Optional: true,
Default: string(restapi.BoundaryScopeDefault),
ValidateFunc: validation.StringInSlice(restapi.SupportedBoundaryScopes.ToStringSlice(), false),
Description: "The boundary scope of the application config",
}
//ApplicationConfigMatchSpecification schema for the application config field match_specification
ApplicationConfigMatchSpecification = &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "The match specification of the application config",
}
)

//NewApplicationConfigResourceHandle creates a new instance of the ResourceHandle for application configs
func NewApplicationConfigResourceHandle() *ResourceHandle {
return &ResourceHandle{
ResourceName: ResourceInstanaApplicationConfig,
Schema: map[string]*schema.Schema{
ApplicationConfigFieldLabel: {
Type: schema.TypeString,
Required: true,
Description: "The label of the application config",
},
ApplicationConfigFieldFullLabel: {
Type: schema.TypeString,
Computed: true,
Description: "The the full label field of the application config. The field is computed and contains the label which is sent to instana. The computation depends on the configured default_name_prefix and default_name_suffix at provider level",
},
ApplicationConfigFieldScope: {
Type: schema.TypeString,
Required: false,
Optional: true,
Default: ApplicationConfigScopeIncludeNoDownstream,
ValidateFunc: validation.StringInSlice([]string{ApplicationConfigScopeIncludeNoDownstream, ApplicationConfigScopeIncludeImmediateDownstreamDatabaseAndMessaging, ApplicationConfigScopeIncludeAllDownstream}, false),
Description: "The scope of the application config",
},
ApplicationConfigFieldMatchSpecification: {
Type: schema.TypeString,
Required: true,
Description: "The match specification of the application config",
},
ApplicationConfigFieldLabel: ApplicationConfigLabel,
ApplicationConfigFieldFullLabel: ApplicationConfigFullLabel,
ApplicationConfigFieldScope: ApplicationConfigScope,
ApplicationConfigFieldBoundaryScope: ApplicationConfigBoundaryScope,
ApplicationConfigFieldMatchSpecification: ApplicationConfigMatchSpecification,
},
SchemaVersion: 1,
StateUpgraders: []schema.StateUpgrader{
Expand All @@ -88,7 +96,8 @@ func updateStateForApplicationConfig(d *schema.ResourceData, obj restapi.Instana
}

d.Set(ApplicationConfigFieldFullLabel, applicationConfig.Label)
d.Set(ApplicationConfigFieldScope, applicationConfig.Scope)
d.Set(ApplicationConfigFieldScope, string(applicationConfig.Scope))
d.Set(ApplicationConfigFieldBoundaryScope, string(applicationConfig.BoundaryScope))
d.Set(ApplicationConfigFieldMatchSpecification, normalizedExpressionString)

d.SetId(applicationConfig.ID)
Expand All @@ -114,7 +123,8 @@ func mapStateToDataObjectForApplicationConfig(d *schema.ResourceData, formatter
return restapi.ApplicationConfig{
ID: d.Id(),
Label: label,
Scope: d.Get(ApplicationConfigFieldScope).(string),
Scope: restapi.ApplicationConfigScope(d.Get(ApplicationConfigFieldScope).(string)),
BoundaryScope: restapi.BoundaryScope(d.Get(ApplicationConfigFieldBoundaryScope).(string)),
MatchSpecification: matchSpecification,
}, nil
}
Expand All @@ -140,24 +150,9 @@ func computeFullApplicationConfigLabelString(d *schema.ResourceData, formatter u
func applicationConfigSchemaV0() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
ApplicationConfigFieldLabel: {
Type: schema.TypeString,
Required: true,
Description: "The label of the application config",
},
ApplicationConfigFieldScope: {
Type: schema.TypeString,
Required: false,
Optional: true,
Default: ApplicationConfigScopeIncludeNoDownstream,
ValidateFunc: validation.StringInSlice([]string{ApplicationConfigScopeIncludeNoDownstream, ApplicationConfigScopeIncludeImmediateDownstreamDatabaseAndMessaging, ApplicationConfigScopeIncludeAllDownstream}, false),
Description: "The scope of the application config",
},
ApplicationConfigFieldMatchSpecification: {
Type: schema.TypeString,
Required: true,
Description: "The match specification of the application config",
},
ApplicationConfigFieldLabel: ApplicationConfigLabel,
ApplicationConfigFieldScope: ApplicationConfigScope,
ApplicationConfigFieldMatchSpecification: ApplicationConfigMatchSpecification,
},
}
}
Expand Down
28 changes: 19 additions & 9 deletions instana/resource-application-config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ provider "instana" {
resource "instana_application_config" "example" {
label = "label {{ITERATOR}}"
scope = "INCLUDE_ALL_DOWNSTREAM"
boundary_scope = "ALL"
match_specification = "{{MATCH_SPECIFICATION}}"
}
`
Expand All @@ -41,6 +42,7 @@ const serverResponseTemplate = `
"id" : "{{id}}",
"label" : "prefix label suffix",
"scope" : "INCLUDE_ALL_DOWNSTREAM",
"boundaryScope" : "ALL",
"matchSpecification" : {
"type" : "BINARY_OP",
"left" : {
Expand Down Expand Up @@ -118,7 +120,8 @@ func TestCRUDOfApplicationConfigResourceWithMockServer(t *testing.T) {
resource.TestCheckResourceAttrSet(testApplicationConfigDefinition, "id"),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldLabel, "label 0"),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldFullLabel, "prefix label 0 suffix"),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldScope, "INCLUDE_ALL_DOWNSTREAM"),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldScope, string(restapi.ApplicationConfigScopeIncludeAllDownstream)),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldBoundaryScope, string(restapi.BoundaryScopeAll)),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldMatchSpecification, defaultMatchSpecification),
),
},
Expand All @@ -128,7 +131,8 @@ func TestCRUDOfApplicationConfigResourceWithMockServer(t *testing.T) {
resource.TestCheckResourceAttrSet(testApplicationConfigDefinition, "id"),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldLabel, "label 1"),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldFullLabel, "prefix label 1 suffix"),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldScope, "INCLUDE_ALL_DOWNSTREAM"),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldScope, string(restapi.ApplicationConfigScopeIncludeAllDownstream)),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldBoundaryScope, string(restapi.BoundaryScopeAll)),
resource.TestCheckResourceAttr(testApplicationConfigDefinition, ApplicationConfigFieldMatchSpecification, defaultMatchSpecification),
),
},
Expand All @@ -142,7 +146,8 @@ func TestApplicationConfigSchemaDefinitionIsValid(t *testing.T) {
schemaAssert := testutils.NewTerraformSchemaAssert(schema, t)
schemaAssert.AssertSchemaIsRequiredAndOfTypeString(ApplicationConfigFieldLabel)
schemaAssert.AssertSchemaIsComputedAndOfTypeString(ApplicationConfigFieldFullLabel)
schemaAssert.AssertSchemaIsOptionalAndOfTypeStringWithDefault(ApplicationConfigFieldScope, ApplicationConfigScopeIncludeNoDownstream)
schemaAssert.AssertSchemaIsOptionalAndOfTypeStringWithDefault(ApplicationConfigFieldScope, string(restapi.ApplicationConfigScopeIncludeNoDownstream))
schemaAssert.AssertSchemaIsOptionalAndOfTypeStringWithDefault(ApplicationConfigFieldBoundaryScope, string(restapi.BoundaryScopeDefault))
schemaAssert.AssertSchemaIsRequiredAndOfTypeString(ApplicationConfigFieldMatchSpecification)
}

Expand Down Expand Up @@ -191,7 +196,8 @@ func TestShouldUpdateApplicationConfigTerraformResourceStateFromModel(t *testing
ID: applicationConfigID,
Label: label,
MatchSpecification: defaultMatchSpecificationModel,
Scope: ApplicationConfigScopeIncludeNoDownstream,
Scope: restapi.ApplicationConfigScopeIncludeNoDownstream,
BoundaryScope: restapi.BoundaryScopeAll,
}

testHelper := NewTestHelper(t)
Expand All @@ -204,7 +210,8 @@ func TestShouldUpdateApplicationConfigTerraformResourceStateFromModel(t *testing
assert.Equal(t, applicationConfigID, resourceData.Id())
assert.Equal(t, label, resourceData.Get(ApplicationConfigFieldFullLabel))
assert.Equal(t, defaultMatchSpecification, resourceData.Get(ApplicationConfigFieldMatchSpecification))
assert.Equal(t, ApplicationConfigScopeIncludeNoDownstream, resourceData.Get(ApplicationConfigFieldScope))
assert.Equal(t, string(restapi.ApplicationConfigScopeIncludeNoDownstream), resourceData.Get(ApplicationConfigFieldScope))
assert.Equal(t, string(restapi.BoundaryScopeAll), resourceData.Get(ApplicationConfigFieldBoundaryScope))
}

func TestShouldFailToUpdateApplicationConfigTerraformResourceStateFromModelWhenMatchSpecificationIsNotalid(t *testing.T) {
Expand All @@ -214,7 +221,7 @@ func TestShouldFailToUpdateApplicationConfigTerraformResourceStateFromModelWhenM
ID: applicationConfigID,
Label: label,
MatchSpecification: comparision,
Scope: ApplicationConfigScopeIncludeNoDownstream,
Scope: restapi.ApplicationConfigScopeIncludeNoDownstream,
}

testHelper := NewTestHelper(t)
Expand All @@ -235,7 +242,8 @@ func TestShouldSuccessfullyConvertApplicationConfigStateToDataModel(t *testing.T
resourceData.SetId(applicationConfigID)
resourceData.Set(ApplicationConfigFieldFullLabel, label)
resourceData.Set(ApplicationConfigFieldMatchSpecification, defaultMatchSpecification)
resourceData.Set(ApplicationConfigFieldScope, ApplicationConfigScopeIncludeNoDownstream)
resourceData.Set(ApplicationConfigFieldScope, string(restapi.ApplicationConfigScopeIncludeNoDownstream))
resourceData.Set(ApplicationConfigFieldBoundaryScope, string(restapi.BoundaryScopeAll))

result, err := resourceHandle.MapStateToDataObject(resourceData, utils.NewResourceNameFormatter("prefix ", " suffix"))

Expand All @@ -244,7 +252,8 @@ func TestShouldSuccessfullyConvertApplicationConfigStateToDataModel(t *testing.T
assert.Equal(t, applicationConfigID, result.GetID())
assert.Equal(t, label, result.(restapi.ApplicationConfig).Label)
assert.Equal(t, defaultMatchSpecificationModel, result.(restapi.ApplicationConfig).MatchSpecification)
assert.Equal(t, ApplicationConfigScopeIncludeNoDownstream, result.(restapi.ApplicationConfig).Scope)
assert.Equal(t, restapi.ApplicationConfigScopeIncludeNoDownstream, result.(restapi.ApplicationConfig).Scope)
assert.Equal(t, restapi.BoundaryScopeAll, result.(restapi.ApplicationConfig).BoundaryScope)
}

func TestShouldFailToConvertApplicationConfigStateToDataModelWhenMatchSpecificationIsNotValid(t *testing.T) {
Expand All @@ -256,7 +265,8 @@ func TestShouldFailToConvertApplicationConfigStateToDataModelWhenMatchSpecificat
resourceData.SetId(applicationConfigID)
resourceData.Set(ApplicationConfigFieldFullLabel, label)
resourceData.Set(ApplicationConfigFieldMatchSpecification, "INVALID")
resourceData.Set(ApplicationConfigFieldScope, ApplicationConfigScopeIncludeNoDownstream)
resourceData.Set(ApplicationConfigFieldScope, string(restapi.ApplicationConfigScopeIncludeNoDownstream))
resourceData.Set(ApplicationConfigFieldBoundaryScope, string(restapi.BoundaryScopeAll))

_, err := resourceHandle.MapStateToDataObject(resourceData, utils.NewResourceNameFormatter("prefix ", " suffix"))

Expand Down
1 change: 1 addition & 0 deletions instana/restapi/application-config-unmarshaller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func (u *applicationConfigUnmarshaller) Unmarshal(data []byte) (InstanaDataObjec
Label: temp.Label,
MatchSpecification: matchSpecification,
Scope: temp.Scope,
BoundaryScope: temp.BoundaryScope,
}, nil
}

Expand Down
5 changes: 4 additions & 1 deletion instana/restapi/application-config-unmarshaller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func TestShouldSuccessfullyUnmarshalApplicationConfig(t *testing.T) {
Label: label,
MatchSpecification: NewBinaryOperator(NewComparisionExpression("key", EqualsOperator, "value"), LogicalAnd, NewUnaryOperationExpression("key", NotBlankOperator)),
Scope: "scope",
BoundaryScope: "boundaryScope",
}

serializedJSON, _ := json.Marshal(applicationConfig)
Expand Down Expand Up @@ -59,7 +60,8 @@ func TestShouldFailToUnmarashalApplicationConfigWhenExpressionTypeIsNotSupported
Key: "foo",
Operator: NotEmptyOperator,
},
Scope: "scope",
Scope: "scope",
BoundaryScope: "boundaryScope",
}
serializedJSON, _ := json.Marshal(applicationConfig)

Expand Down Expand Up @@ -92,6 +94,7 @@ func testShouldFailToUnmarashalApplicationConfigWhenOneSideOfBinaryExpressionIsN
Label: "label",
MatchSpecification: NewBinaryOperator(left, LogicalOr, right),
Scope: "scope",
BoundaryScope: "boundaryScope",
}
serializedJSON, _ := json.Marshal(applicationConfig)

Expand Down
Loading

0 comments on commit f5f994f

Please sign in to comment.