Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support structured config #575

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Reverting changes about Config; just ConfigRefs will be a complex config
  • Loading branch information
ljtfreitas committed Apr 24, 2024
commit d637e40207b454c884115b060d6ccaf9829aa626
4 changes: 2 additions & 2 deletions deploy/crds/pulumi.com_stacks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ spec:
type: string
config:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
type: string
description: (optional) Config is the configuration for this stack,
which can be optionally specified inline. If this is omitted, configuration
is assumed to be checked in and taken from the source repository.
Expand Down Expand Up @@ -992,7 +992,7 @@ spec:
type: string
config:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
type: string
description: (optional) Config is the configuration for this stack,
which can be optionally specified inline. If this is omitted, configuration
is assumed to be checked in and taken from the source repository.
Expand Down
4 changes: 2 additions & 2 deletions docs/stacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ StackSpec defines the desired state of Pulumi Stack being managed by this operat
<td>false</td>
</tr><tr>
<td><b>config</b></td>
<td>map[string]JSON</td>
<td>map[string]string</td>
<td>
(optional) Config is the configuration for this stack, which can be optionally specified inline. If this is omitted, configuration is assumed to be checked in and taken from the source repository.<br/>
</td>
Expand Down Expand Up @@ -2355,7 +2355,7 @@ StackSpec defines the desired state of Pulumi Stack being managed by this operat
<td>false</td>
</tr><tr>
<td><b>config</b></td>
<td>map[string]JSON</td>
<td>map[string]string</td>
<td>
(optional) Config is the configuration for this stack, which can be optionally specified inline. If this is omitted, configuration is assumed to be checked in and taken from the source repository.<br/>
</td>
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/pulumi/shared/stack_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type StackSpec struct {
Stack string `json:"stack"`
// (optional) Config is the configuration for this stack, which can be optionally specified inline. If this
// is omitted, configuration is assumed to be checked in and taken from the source repository.
Config map[string]apiextensionsv1.JSON `json:"config,omitempty"`
Config map[string]string `json:"config,omitempty"`
// (optional) ConfigRefs is the configuration for this stack, which can be specified through ConfigRef.
// is omitted, configuration is assumed to be checked in and taken from the source repository.
ConfigRefs map[string]ConfigRef `json:"configsRef,omitempty"`
Expand Down
24 changes: 2 additions & 22 deletions pkg/apis/pulumi/shared/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions pkg/controller/stack/stack_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)

type JsonConfig map[string]apiextensionsv1.JSON
type StructuredConfig map[string]apiextensionsv1.JSON

type ConfigKeyValue struct {
Key string
Value auto.ConfigValue
}

func (c JsonConfig) Unmarshal() ([]ConfigKeyValue, error) {
func (c StructuredConfig) Unmarshal() ([]ConfigKeyValue, error) {
flatten, err := flattenKeys(c)
if err != nil {
return nil, err
}

configValues := make([]ConfigKeyValue, 0)
configValues := make([]ConfigKeyValue, 0, len(flatten))
for key, value := range flatten {
configValues = append(configValues, ConfigKeyValue{
Key: key,
Expand All @@ -35,7 +35,7 @@ func (c JsonConfig) Unmarshal() ([]ConfigKeyValue, error) {
return configValues, nil
}

func flattenKeys(config JsonConfig) (map[string]any, error) {
func flattenKeys(config StructuredConfig) (map[string]any, error) {
output := make(map[string]any)

for k, jsonValue := range config {
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/stack/stack_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestFlattenStackConfigFromJson(t *testing.T) {
"an-integer-config": toJson(123456),
}

configValues, err := JsonConfig(sourceConfigMap).Unmarshal()
configValues, err := StructuredConfig(sourceConfigMap).Unmarshal()

if assert.Nil(t, err) {
expected := []ConfigKeyValue{
Expand Down
20 changes: 13 additions & 7 deletions pkg/controller/stack/stack_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,7 @@ func (sess *reconcileStackSession) resolveConfigRefs(ctx context.Context, refs m
structuredRef := ref.StructuredRef
if structuredRef != nil {
// StructuredRef handles value as json, flattening all keys to build a list of Pulumi key:value configs
jsonConfig := JsonConfig(map[string]apiextensionsv1.JSON{
jsonConfig := StructuredConfig(map[string]apiextensionsv1.JSON{
k: structuredRef.Value,
})
structuredConfig, err := jsonConfig.Unmarshal()
Expand Down Expand Up @@ -1628,12 +1628,18 @@ func (sess *reconcileStackSession) InstallProjectDependencies(ctx context.Contex
}

func (sess *reconcileStackSession) UpdateConfig(ctx context.Context) error {
var configValues []ConfigKeyValue

// Config values will be handled as a structured config
configValues, err := JsonConfig(sess.stack.Config).Unmarshal()
if err != nil {
return fmt.Errorf("Fail reading config values: %w", err)
// Initialize a single config value slice to all values;
// plain config will be handled with values from ConfigRefs
configValues := make([]ConfigKeyValue, 0, len(sess.stack.Config))

for k, v := range sess.stack.Config {
configValues = append(configValues, ConfigKeyValue{
Key: k,
Value: auto.ConfigValue{
Value: v,
Secret: false,
},
})
}

// appending ConfigRefs values
Expand Down
16 changes: 8 additions & 8 deletions test/stack_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ var _ = Describe("Stack Controller", func() {
pulumiAWSSecret.Name,
},
EnvRefs: defaultEnvRefs(),
Config: map[string]v1.JSON{
"aws:region": {Raw: []byte("us-east-2")},
Config: map[string]string{
"aws:region": "us-east-2",
},
GitSource: &shared.GitSource{
ProjectRepo: baseDir,
Expand All @@ -276,7 +276,7 @@ var _ = Describe("Stack Controller", func() {
}, stackExecTimeout, interval).Should(BeTrue())

By("changing the region config item to an invalid value")
original.Spec.Config["aws:region"] = v1.JSON{Raw: []byte("us-nonexistent-1")}
original.Spec.Config["aws:region"] = "us-nonexistent-1"
Expect(k8sClient.Update(ctx, original)).Should(Succeed(), "%+v", original)

// Check that the stack tried to update but failed
Expand All @@ -295,7 +295,7 @@ var _ = Describe("Stack Controller", func() {
}, stackExecTimeout, interval).Should(BeTrue(), "the stack reaches a failed state")

By("restoring a valid value for the region config item")
updated.Spec.Config["aws:region"] = v1.JSON{Raw: []byte("us-east-2")}
updated.Spec.Config["aws:region"] = "us-east-2"
Expect(k8sClient.Update(ctx, updated)).To(Succeed())

// Check that the stack update attempted and succeeded after the region fix
Expand Down Expand Up @@ -326,8 +326,8 @@ var _ = Describe("Stack Controller", func() {
"AWS_SECRET_ACCESS_KEY": shared.NewSecretResourceRef(namespace, pulumiAWSSecret.Name, "AWS_SECRET_ACCESS_KEY"),
"AWS_SESSION_TOKEN": shared.NewEnvResourceRef("AWS_SESSION_TOKEN"),
},
Config: map[string]v1.JSON{
"aws:region": {Raw: []byte("us-east-2")},
Config: map[string]string{
"aws:region": "us-east-2",
},
GitSource: &shared.GitSource{
ProjectRepo: baseDir,
Expand Down Expand Up @@ -402,8 +402,8 @@ var _ = Describe("Stack Controller", func() {
},
Backend: fmt.Sprintf(`s3://%s`, s3Backend),
SecretsProvider: fmt.Sprintf(`awskms:///%s?region=us-east-2`, kmsKey),
Config: map[string]v1.JSON{
"aws:region": {Raw: []byte("us-east-2")},
Config: map[string]string{
"aws:region": "us-east-2",
},
Refresh: true,
Stack: stackName,
Expand Down
37 changes: 18 additions & 19 deletions test/stale_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (

"github.com/pulumi/pulumi-kubernetes-operator/pkg/apis/pulumi/shared"
pulumiv1 "github.com/pulumi/pulumi-kubernetes-operator/pkg/apis/pulumi/v1"
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -99,20 +98,20 @@ var _ = When("a stack uses a provider with credentials kept in state", Ordered,

setupStack = createStack("run-rabbitmq", "setup")
setupStack.Spec.DestroyOnFinalize = true // tear down the container afterwards
setupStack.Spec.Config = map[string]v1.JSON{
"password": {Raw: []byte(randString())},
"port": {Raw: []byte(rabbitPort)},
"secretName": {Raw: []byte(credsSecretName)},
setupStack.Spec.Config = map[string]string{
"password": randString(),
"port": rabbitPort,
"secretName": credsSecretName,
} // changing this will force it to restart RabbitMQ with the new creds
Expect(k8sClient.Create(ctx, setupStack)).To(Succeed())
waitForStackSuccess(setupStack, "120s")

// running this the first time should succeed -- the program will run and get the
// credentials from the secret, which then go into the stack state.
useRabbitStack = createStack("use-rabbitmq", "use")
useRabbitStack.Spec.Config = map[string]v1.JSON{
"port": {Raw: []byte(rabbitPort)},
"secretName": {Raw: []byte(credsSecretName)},
useRabbitStack.Spec.Config = map[string]string{
"port": rabbitPort,
"secretName": credsSecretName,
}

Expect(k8sClient.Create(context.TODO(), useRabbitStack)).To(Succeed())
Expand All @@ -133,10 +132,10 @@ var _ = When("a stack uses a provider with credentials kept in state", Ordered,
// "rotate" the credentials by rerunning the setup stack in such a way as to recreate
// the passphrase
refetch(setupStack)
setupStack.Spec.Config = map[string]v1.JSON{
"password": {Raw: []byte(randString())},
"port": {Raw: []byte(rabbitPort)},
"secretName": {Raw: []byte(credsSecretName)},
setupStack.Spec.Config = map[string]string{
"password": randString(),
"port": rabbitPort,
"secretName": credsSecretName,
}
resetWaitForStack()
Expect(k8sClient.Update(ctx, setupStack)).To(Succeed())
Expand Down Expand Up @@ -176,9 +175,9 @@ var _ = When("a stack uses a provider with credentials kept in state", Ordered,
// refreshes the _same_ state because it uses the same backend stack name.
targetedStack = createStack("use-rabbitmq", "use")
targetedStack.Spec.Targets = []string{providerURN}
targetedStack.Spec.Config = map[string]v1.JSON{
"port": {Raw: []byte(rabbitPort)},
"secretName": {Raw: []byte(credsSecretName)},
targetedStack.Spec.Config = map[string]string{
"port": rabbitPort,
"secretName": credsSecretName,
}
Expect(k8sClient.Create(ctx, targetedStack)).To(Succeed())
DeferCleanup(func() {
Expand All @@ -202,10 +201,10 @@ var _ = When("a stack uses a provider with credentials kept in state", Ordered,
// "rotate" the credentials by rerunning the setup stack in such a way as to recreate
// the passphrase
refetch(setupStack)
setupStack.Spec.Config = map[string]v1.JSON{
"password": {Raw: []byte(randString())},
"port": {Raw: []byte(rabbitPort)},
"secretName": {Raw: []byte(credsSecretName)},
setupStack.Spec.Config = map[string]string{
"password": randString(),
"port": rabbitPort,
"secretName": credsSecretName,
}
resetWaitForStack()
Expect(k8sClient.Update(ctx, setupStack)).To(Succeed())
Expand Down
Loading