Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions config/app_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ func (a *AppConfiguration) Normalize(ctx context.Context, pc core.ObjectPathCont
return errs
}

func (a *AppConfiguration) ToBlock(orgName string, stackId int64) types.Block {
block := a.BlockConfiguration.ToBlock(orgName, stackId)
block.Framework = a.Framework
return block
func (a *AppConfiguration) toBlockDefinition(orgName string, stackId int64) BlockDefinition {
def := a.BlockConfiguration.toBlockDefinition(orgName, stackId)
def.Block.Framework = a.Framework
return def
}

func (a *AppConfiguration) ApplyChangesTo(ic core.IacContext, updater core.WorkspaceConfigUpdater) error {
Expand Down
31 changes: 16 additions & 15 deletions config/block_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ type BlockConfiguration struct {
ModuleConstraint string `json:"moduleConstraint"`
Variables VariableConfigurations `json:"vars"`
Connections ConnectionConfigurations `json:"connections"`
IsShared bool `json:"isShared"`
Metadata MetadataConfiguration `json:"metadata"`

// These fields are populated via Resolve()
Expand Down Expand Up @@ -97,7 +96,6 @@ func blockConfigFromYaml(name string, value yaml.BlockConfiguration, blockType B
ModuleConstraint: moduleConstraint,
Variables: convertVariables(value.Variables),
Connections: convertConnections(value.Connections),
IsShared: value.IsShared,
Metadata: convertMetadata(value.Metadata),
}
}
Expand Down Expand Up @@ -184,19 +182,22 @@ func (b *BlockConfiguration) Normalize(ctx context.Context, pc core.ObjectPathCo
return b.Connections.Normalize(ctx, pc, resolver)
}

func (b *BlockConfiguration) ToBlock(orgName string, stackId int64) types.Block {
block := types.Block{
Type: string(b.Type),
OrgName: orgName,
StackId: stackId,
Name: b.Name,
IsShared: b.IsShared,
DnsName: "",
ModuleSource: b.ModuleSource,
ModuleSourceVersion: b.ModuleConstraint,
Connections: b.Connections.DesiredTargets(),
}
return block
// toBlockDefinition flattens the configuration into an API block.
// Fields IaC does not govern (IsShared, Repo, Framework for non-apps, ...) stay zero so a
// consumer syncing blocks can tell "not declared" from a declared value.
func (b *BlockConfiguration) toBlockDefinition(orgName string, stackId int64) BlockDefinition {
return BlockDefinition{
Block: types.Block{
Type: string(b.Type),
OrgName: orgName,
StackId: stackId,
Name: b.Name,
DnsName: "",
ModuleSource: b.ModuleSource,
ModuleSourceVersion: b.ModuleConstraint,
Connections: b.Connections.DesiredTargets(),
},
}
}

func (b *BlockConfiguration) ApplyChangesTo(ic core.IacContext, updater core.WorkspaceConfigUpdater) error {
Expand Down
55 changes: 55 additions & 0 deletions config/block_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,58 @@ func TestBlockConfiguration_ApplyChangesTo_dataClassification(t *testing.T) {
assert.Equal(t, types.ClassificationLevel(""), wc.Metadata.DataClassification)
})
}

// Sharing is not governed by IaC, so a definition never carries it; a block sync must leave
// the stored flag alone.
func TestBlockConfiguration_toBlockDefinitionOmitsUngovernedFields(t *testing.T) {
bc := blockConfigFromYaml("db", yaml.BlockConfiguration{ModuleSource: "nullstone/aws-rds-postgres"}, BlockTypeDatastore, types.CategoryDatastore)
def := bc.toBlockDefinition("acme", 100)
assert.False(t, def.Block.IsShared)
assert.Empty(t, def.Block.DnsName)
assert.Empty(t, def.Block.Framework)
assert.Empty(t, def.Block.Repo)
assert.Equal(t, "latest", def.Block.ModuleSourceVersion, "omitted module_version resolves to latest")
}

func TestEnvConfiguration_ToBlockDefinitions(t *testing.T) {
ec := &EnvConfiguration{
Applications: map[string]*AppConfiguration{
"api": {
BlockConfiguration: BlockConfiguration{Type: BlockTypeApplication, Name: "api", ModuleSource: "nullstone/aws-fargate-service", ModuleConstraint: "latest"},
Framework: "go",
},
},
Datastores: map[string]*DatastoreConfiguration{
"db": {BlockConfiguration: BlockConfiguration{Type: BlockTypeDatastore, Name: "db", ModuleSource: "nullstone/aws-rds-postgres"}},
},
Subdomains: map[string]*SubdomainConfiguration{
"web": {
BlockConfiguration: BlockConfiguration{Type: BlockTypeSubdomain, Name: "web", ModuleSource: "nullstone/aws-subdomain"},
SubdomainNameTemplate: ptr("web.{{ NULLSTONE_ENV }}"),
},
},
Blocks: map[string]*BlockConfiguration{
"queue": {Type: BlockTypeBlock, Name: "queue", ModuleSource: "nullstone/aws-sqs-queue"},
},
}

defs := ec.ToBlockDefinitions("acme", 100)
byName := map[string]BlockDefinition{}
for _, def := range defs {
byName[def.Block.Name] = def
}
require.Len(t, byName, 4)

assert.Equal(t, string(BlockTypeApplication), byName["api"].Block.Type)
assert.Equal(t, "go", byName["api"].Block.Framework)

assert.Equal(t, string(BlockTypeDatastore), byName["db"].Block.Type)
assert.Empty(t, byName["db"].Block.Framework)

assert.Equal(t, "web.{{ NULLSTONE_ENV }}", byName["web"].Block.DnsName)

assert.Equal(t, string(BlockTypeBlock), byName["queue"].Block.Type)
assert.Empty(t, byName["queue"].Block.DnsName)

assert.Empty(t, (*EnvConfiguration)(nil).ToBlockDefinitions("acme", 100))
}
8 changes: 4 additions & 4 deletions config/domain_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ type DomainConfiguration struct {
DomainNameTemplate *string `json:"domainNameTemplate"`
}

func (d *DomainConfiguration) ToBlock(orgName string, stackId int64) types.Block {
block := d.BlockConfiguration.ToBlock(orgName, stackId)
func (d *DomainConfiguration) toBlockDefinition(orgName string, stackId int64) BlockDefinition {
def := d.BlockConfiguration.toBlockDefinition(orgName, stackId)
if d.DomainNameTemplate != nil {
block.DnsName = *d.DomainNameTemplate
def.Block.DnsName = *d.DomainNameTemplate
}
return block
return def
}

func (d *DomainConfiguration) ApplyChangesTo(ic core.IacContext, updater core.WorkspaceConfigUpdater) error {
Expand Down
35 changes: 22 additions & 13 deletions config/env_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,41 +246,50 @@ func (e *EnvConfiguration) Normalize(ctx context.Context, resolver core.Normaliz
return nil
}

func (e *EnvConfiguration) ToBlocks(orgName string, stackId int64) types.Blocks {
blocks := make([]types.Block, 0)
// BlockDefinition is a block as declared in config.yml. Block carries only the fields IaC
// governs; anything IaC does not declare is left at its zero value. It is a struct so that
// declared-only information which the flat types.Block cannot express can be added later.
type BlockDefinition struct {
Block types.Block
}

// ToBlockDefinitions flattens every block in the file into sync definitions.
// Callers that only need the API shape read Block off each definition.
func (e *EnvConfiguration) ToBlockDefinitions(orgName string, stackId int64) []BlockDefinition {
defs := make([]BlockDefinition, 0)
if e == nil {
return blocks
return defs
}

for _, app := range e.Applications {
blocks = append(blocks, app.ToBlock(orgName, stackId))
defs = append(defs, app.toBlockDefinition(orgName, stackId))
}
for _, ds := range e.Datastores {
blocks = append(blocks, ds.ToBlock(orgName, stackId))
defs = append(defs, ds.toBlockDefinition(orgName, stackId))
}
for _, sub := range e.Subdomains {
blocks = append(blocks, sub.ToBlock(orgName, stackId))
defs = append(defs, sub.toBlockDefinition(orgName, stackId))
}
for _, d := range e.Domains {
blocks = append(blocks, d.ToBlock(orgName, stackId))
defs = append(defs, d.toBlockDefinition(orgName, stackId))
}
for _, i := range e.Ingresses {
blocks = append(blocks, i.ToBlock(orgName, stackId))
defs = append(defs, i.toBlockDefinition(orgName, stackId))
}
for _, cn := range e.ClusterNamespaces {
blocks = append(blocks, cn.ToBlock(orgName, stackId))
defs = append(defs, cn.toBlockDefinition(orgName, stackId))
}
for _, c := range e.Clusters {
blocks = append(blocks, c.ToBlock(orgName, stackId))
defs = append(defs, c.toBlockDefinition(orgName, stackId))
}
for _, n := range e.Networks {
blocks = append(blocks, n.ToBlock(orgName, stackId))
defs = append(defs, n.toBlockDefinition(orgName, stackId))
}
for _, b := range e.Blocks {
blocks = append(blocks, b.ToBlock(orgName, stackId))
defs = append(defs, b.toBlockDefinition(orgName, stackId))
}

return blocks
return defs
}

func (e *EnvConfiguration) ApplyChangesTo(block types.Block, updater core.WorkspaceConfigUpdater) error {
Expand Down
6 changes: 3 additions & 3 deletions config/env_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,10 @@ func TestConvertConfiguration(t *testing.T) {

syncBlocks := func(base *EnvConfiguration, resolver *find.ResourceResolver) {
backfill := make([]types.Block, 0)
for _, block := range base.ToBlocks(defaults.OrgName, resolver.CurStackId) {
if _, err := resolver.FindBlock(context.TODO(), types.ConnectionTarget{BlockName: block.Name}); err != nil {
for _, def := range base.ToBlockDefinitions(defaults.OrgName, resolver.CurStackId) {
if _, err := resolver.FindBlock(context.TODO(), types.ConnectionTarget{BlockName: def.Block.Name}); err != nil {
if find.IsMissingResource(err) {
backfill = append(backfill, block)
backfill = append(backfill, def.Block)
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions config/subdomain_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ type SubdomainConfiguration struct {
Reservation *types.SubdomainReservation `json:"reservation,omitempty"`
}

func (s *SubdomainConfiguration) ToBlock(orgName string, stackId int64) types.Block {
block := s.BlockConfiguration.ToBlock(orgName, stackId)
func (s *SubdomainConfiguration) toBlockDefinition(orgName string, stackId int64) BlockDefinition {
def := s.BlockConfiguration.toBlockDefinition(orgName, stackId)
if s.SubdomainNameTemplate != nil {
block.DnsName = *s.SubdomainNameTemplate
def.Block.DnsName = *s.SubdomainNameTemplate
}
return block
return def
}

func (s *SubdomainConfiguration) Resolve(ctx context.Context, resolver core.ResolveResolver, finder core.IacFinder, ic core.IacContext, pc core.ObjectPathContext) core.ResolveErrors {
Expand Down
1 change: 0 additions & 1 deletion yaml/block_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ type BlockConfiguration struct {
ModuleConstraint *string `yaml:"module_version,omitempty" json:"moduleVersion"`
Variables map[string]any `yaml:"vars,omitempty" json:"vars"`
Connections ConnectionConstraints `yaml:"connections,omitempty" json:"connections"`
IsShared bool `yaml:"is_shared,omitempty" json:"isShared"`
// Metadata holds governance/descriptive metadata (e.g. data classification).
Metadata *MetadataConfiguration `yaml:"metadata,omitempty" json:"metadata,omitempty"`
}
Expand Down
8 changes: 8 additions & 0 deletions yaml/block_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,11 @@ func TestMetadataFromWorkspaceConfig(t *testing.T) {
assert.Equal(t, "restricted", *got.DataClassification)
})
}

// is_shared is not an IaC setting (sharing is chosen in the UI); a stray key parses without error
// and has no effect, matching the lenient decoder used for every other unknown key.
func TestBlockConfiguration_IgnoresIsShared(t *testing.T) {
var bc BlockConfiguration
require.NoError(t, goyaml.Unmarshal([]byte("module: nullstone/aws-rds-postgres\nis_shared: true\n"), &bc))
assert.Equal(t, "nullstone/aws-rds-postgres", bc.ModuleSource)
}
Loading