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

[v2] Add transformer in renderer step. #6051

Merged
merged 1 commit into from
Jun 23, 2021
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
7 changes: 7 additions & 0 deletions hack/versions/pkg/schema/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ func RunSchemaCheckOnChangedFiles() error {
}
var changedConfigFiles []string
for _, file := range changedFiles {
if strings.Contains(file, "v3alpha") {
continue
}
if strings.Contains(file, "latest/v2") {
continue
}

if strings.Contains(file, "config.go") {
changedConfigFiles = append(changedConfigFiles, file)
}
Expand Down
20 changes: 18 additions & 2 deletions pkg/skaffold/render/renderer/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/manifest"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/render/generate"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/render/kptfile"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/render/transform"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/render/validate"
latestV2 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest/v2"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
Expand Down Expand Up @@ -74,12 +75,24 @@ func NewSkaffoldRenderer(config *latestV2.RenderConfig, workingDir string) (Rend
validator, _ = validate.NewValidator([]latestV2.Validator{})
}

return &SkaffoldRenderer{Generator: *generator, Validator: *validator, workingDir: workingDir, hydrationDir: hydrationDir}, nil
var transformer *transform.Transformer
if config.Transform != nil {
var err error
transformer, err = transform.NewTransformer(*config.Transform)
if err != nil {
return nil, err
}
} else {
transformer, _ = transform.NewTransformer([]latestV2.Transformer{})
}
return &SkaffoldRenderer{Generator: *generator, Validator: *validator, Transformer: *transformer,
workingDir: workingDir, hydrationDir: hydrationDir}, nil
}

type SkaffoldRenderer struct {
generate.Generator
validate.Validator
transform.Transformer
workingDir string
hydrationDir string
labels map[string]string
Expand Down Expand Up @@ -164,7 +177,10 @@ func (r *SkaffoldRenderer) Render(ctx context.Context, out io.Writer, builds []g
}

kfConfig.Pipeline.Validators = r.GetDeclarativeValidators()
// TODO: Update the Kptfile with the new mutators.
kfConfig.Pipeline.Mutators, err = r.GetDeclarativeTransformers()
if err != nil {
return err
}

configByte, err := yaml.Marshal(kfConfig)
if err != nil {
Expand Down
110 changes: 110 additions & 0 deletions pkg/skaffold/render/transform/transform.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
Copyright 2021 The Skaffold Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package transform

import (
"fmt"
"strings"

sErrors "github.com/GoogleContainerTools/skaffold/pkg/skaffold/errors"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/render/kptfile"
latestV2 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest/v2"
"github.com/GoogleContainerTools/skaffold/proto/v1"
)

var (
allowListedTransformer = []string{"set-label"}
transformerAllowlist = map[string]kptfile.Function{
"set-label": {
Image: "gcr.io/kpt-functions/set-namespace",
ConfigMap: map[string]string{},
},
}
)

// NewTransformer instantiates a Transformer object.
func NewTransformer(config []latestV2.Transformer) (*Transformer, error) {
newFuncs, err := validateTransformers(config)
if err != nil {
return nil, err
}
return &Transformer{kptFn: newFuncs, needRefresh: true, config: config}, nil
}

type Transformer struct {
needRefresh bool
kptFn []kptfile.Function
config []latestV2.Transformer
}

// GetDeclarativeValidators transforms and returns the skaffold validators defined in skaffold.yaml
func (v *Transformer) GetDeclarativeTransformers() ([]kptfile.Function, error) {
// TODO: guarantee the v.kptFn is updated once users changed skaffold.yaml file.
if v.needRefresh {
newFuncs, err := validateTransformers(v.config)
if err != nil {
return nil, err
}
v.kptFn = newFuncs
v.needRefresh = false
}
return v.kptFn, nil
}

func validateTransformers(config []latestV2.Transformer) ([]kptfile.Function, error) {
var newFuncs []kptfile.Function
for _, c := range config {
newFunc, ok := transformerAllowlist[c.Name]
if !ok {
// TODO: Add links to explain "skaffold-managed mode" and "kpt-managed mode".
return nil, sErrors.NewErrorWithStatusCode(
proto.ActionableErr{
Message: fmt.Sprintf("unsupported transformer %q", c.Name),
ErrCode: proto.StatusCode_CONFIG_UNKNOWN_TRANSFORMER,
Suggestions: []*proto.Suggestion{
{
SuggestionCode: proto.SuggestionCode_CONFIG_ALLOWLIST_transformers,
Action: fmt.Sprintf(
"please only use the following transformers in skaffold-managed mode: %v. "+
"to use custom transformers, please use kpt-managed mode.", allowListedTransformer),
},
},
})
}
if c.ConfigMapData != nil {
for _, stringifiedData := range c.ConfigMapData {
items := strings.Split(stringifiedData, "=")
if len(items) != 2 {
return nil, sErrors.NewErrorWithStatusCode(
proto.ActionableErr{
Message: fmt.Sprintf("unknown arguments for transformer %v", c.Name),
ErrCode: proto.StatusCode_CONFIG_UNKNOWN_TRANSFORMER,
Suggestions: []*proto.Suggestion{
{
SuggestionCode: proto.SuggestionCode_CONFIG_ALLOWLIST_transformers,
Action: fmt.Sprintf("please check if the .transformer field and " +
"make sure `configMapData` is a list of data in the form of `${KEY}=${VALUE}`"),
},
},
})
}
newFunc.ConfigMap[items[0]] = items[1]
}
}
newFuncs = append(newFuncs, newFunc)
}
return newFuncs, nil
}
56 changes: 56 additions & 0 deletions pkg/skaffold/render/transform/transform_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
Copyright 2021 The Skaffold Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package transform

import (
"testing"

latestV2 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest/v2"
"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestNewTransformer(t *testing.T) {
tests := []struct {
description string
config []latestV2.Transformer
}{
{
description: "no transform",
config: []latestV2.Transformer{},
},
{
description: "set-label",
config: []latestV2.Transformer{
{Name: "set-label"},
},
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
_, err := NewTransformer(test.config)
t.CheckNoError(err)
})
}
}

func TestNewValidator_Error(t *testing.T) {
testutil.Run(t, "", func(t *testutil.T) {
_, err := NewTransformer([]latestV2.Transformer{
{Name: "bad-transformer"},
})
t.CheckContains(`unsupported transformer "bad-transformer". please only use the`, err.Error())
})
}
4 changes: 2 additions & 2 deletions pkg/skaffold/render/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
)

var (
AllowlistedValidators = []string{"kubeval"}
allowListedValidators = []string{"kubeval"}
validatorAllowlist = map[string]kptfile.Function{
"kubeval": {Image: "gcr.io/kpt-fn/kubeval:v0.1"},
// TODO: Add conftest validator in kpt catalog.
Expand All @@ -48,7 +48,7 @@ func NewValidator(config []latestV2.Validator) (*Validator, error) {
SuggestionCode: proto.SuggestionCode_CONFIG_ALLOWLIST_VALIDATORS,
Action: fmt.Sprintf(
"please only use the following validators in skaffold-managed mode: %v. "+
"to use custom validators, please use kpt-managed mode.", AllowlistedValidators),
"to use custom validators, please use kpt-managed mode.", allowListedValidators),
},
},
})
Expand Down
7 changes: 6 additions & 1 deletion pkg/skaffold/schema/latest/v2/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util"
)

// This config version is not yet released, it is SAFE TO MODIFY the structs in this file.
const Version string = "skaffold/v3alpha2"

// NewSkaffoldConfig creates a SkaffoldConfig
Expand Down Expand Up @@ -106,12 +107,16 @@ type Generate struct {
type Transformer struct {
// Name is the transformer name. Can only accept skaffold whitelisted tools.
Name string `yaml:"name" yamltags:"required"`
// ConfigMapData allows users to provide additional config data to the kpt function.
ConfigMapData []string `yaml:"configMapData,omitempty"`
}

// Transformer describes the supported kpt transformers.
// Validator describes the supported kpt validators.
type Validator struct {
// Name is the Validator name. Can only accept skaffold whitelisted tools.
Name string `yaml:"name" yamltags:"required"`
// ConfigMapData allows users to provide additional config data to the kpt function.
ConfigMapData []string `yaml:"configMapData,omitempty"`
}

// DeployConfig contains all the configuration needed by the deploy steps.
Expand Down
6 changes: 5 additions & 1 deletion pkg/skaffold/schema/v3alpha1/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,16 @@ type Generate struct {
type Transformer struct {
// Name is the transformer name. Can only accept skaffold whitelisted tools.
Name string `yaml:"name" yamltags:"required"`
// ConfigMapData allows users to provide additional config data to the kpt function.
ConfigMapData []string `yaml:"configMapData,omitempty"`
}

// Transformer describes the supported kpt transformers.
// Validator describes the supported kpt validators.
type Validator struct {
// Name is the Validator name. Can only accept skaffold whitelisted tools.
Name string `yaml:"name" yamltags:"required"`
// ConfigMapData allows users to provide additional config data to the kpt function.
ConfigMapData []string `yaml:"configMapData,omitempty"`
}

// DeployConfig contains all the configuration needed by the deploy steps.
Expand Down