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

feat(api,controller): support files up to 1MiB on RpaasInstance extra files #121

Merged
merged 6 commits into from
Aug 4, 2022
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
18 changes: 18 additions & 0 deletions api/v1alpha1/rpaasinstance_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,19 @@ type RpaasInstanceSpec struct {
Service *nginxv1alpha1.NginxService `json:"service,omitempty"`

// ExtraFiles points to a ConfigMap where the files are stored.
//
// Deprecated: ExtraFiles stores all files in a single ConfigMap. In other
// words, they share the limit of 1MiB due to etcd limitations. In order to
// get around it, use the Field field.
//
// +optional
ExtraFiles *nginxv1alpha1.FilesRef `json:"extraFiles,omitempty"`

// Files is a list of regular files of general purpose to be mounted on
// Nginx pods. As ConfigMap stores the file content, a file cannot exceed 1MiB.
// +optional
Files []File `json:"files,omitempty"`

// The number of old Configs to retain to allow rollback.
// +optional
ConfigHistoryLimit *int `json:"configHistoryLimit,omitempty"`
Expand Down Expand Up @@ -195,6 +205,14 @@ type Value struct {
ValueFrom *ValueSource `json:"valueFrom,omitempty"`
}

type File struct {
// Name is the filaname of the file.
Name string `json:"name"`
// ConfigMap is a reference to ConfigMap in the namespace that contains the
// file content.
ConfigMap *corev1.ConfigMapKeySelector `json:"configMap,omitempty"`
}

const CertificateNameDefault = "default"

// RpaasInstanceAutoscaleSpec describes the behavior of HorizontalPodAutoscaler.
Expand Down
27 changes: 27 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

1,331 changes: 762 additions & 569 deletions config/crd/bases/extensions.tsuru.io_rpaasflavors.yaml

Large diffs are not rendered by default.

1,263 changes: 725 additions & 538 deletions config/crd/bases/extensions.tsuru.io_rpaasinstances.yaml

Large diffs are not rendered by default.

21 changes: 20 additions & 1 deletion controllers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,6 @@ func newNginx(instanceMergedWithFlavors *v1alpha1.RpaasInstance, plan *v1alpha1.
Resources: plan.Spec.Resources,
Service: instanceMergedWithFlavors.Spec.Service.DeepCopy(),
HealthcheckPath: "/_nginx_healthcheck",
ExtraFiles: instanceMergedWithFlavors.Spec.ExtraFiles,
TLS: instanceMergedWithFlavors.Spec.TLS,
Cache: cacheConfig,
PodTemplate: instanceMergedWithFlavors.Spec.PodTemplate,
Expand All @@ -1121,6 +1120,26 @@ func newNginx(instanceMergedWithFlavors *v1alpha1.RpaasInstance, plan *v1alpha1.
n.Spec.Service.Type = corev1.ServiceTypeLoadBalancer
}

for i, f := range instanceMergedWithFlavors.Spec.Files {
volumeName := fmt.Sprintf("extra-files-%d", i)

n.Spec.PodTemplate.Volumes = append(n.Spec.PodTemplate.Volumes, corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: f.ConfigMap.LocalObjectReference,
},
},
})

n.Spec.PodTemplate.VolumeMounts = append(n.Spec.PodTemplate.VolumeMounts, corev1.VolumeMount{
Name: volumeName,
MountPath: fmt.Sprintf("/etc/nginx/extra_files/%s", f.Name),
SubPath: f.Name,
ReadOnly: true,
})
}

if isTLSSessionTicketEnabled(instanceMergedWithFlavors) {
n.Spec.PodTemplate.Volumes = append(n.Spec.PodTemplate.Volumes, corev1.Volume{
Name: sessionTicketsVolumeName,
Expand Down
133 changes: 133 additions & 0 deletions controllers/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,139 @@ import (
extensionsruntime "github.com/tsuru/rpaas-operator/pkg/runtime"
)

func Test_newNginx(t *testing.T) {
tests := map[string]struct {
instance func(i *v1alpha1.RpaasInstance) *v1alpha1.RpaasInstance
plan func(p *v1alpha1.RpaasPlan) *v1alpha1.RpaasPlan
cm func(c *corev1.ConfigMap) *corev1.ConfigMap
expected func(n *nginxv1alpha1.Nginx) *nginxv1alpha1.Nginx
}{
"w/ extra files": {
instance: func(i *v1alpha1.RpaasInstance) *v1alpha1.RpaasInstance {
i.Spec.Files = []v1alpha1.File{
{
Name: "waf.cfg",
ConfigMap: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{Name: "my-instance-extra-files-1"},
},
},
{
Name: "binary.exe",
ConfigMap: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{Name: "my-instance-extra-files-2"},
},
},
}
return i
},
expected: func(n *nginxv1alpha1.Nginx) *nginxv1alpha1.Nginx {
n.Spec.PodTemplate.Volumes = []corev1.Volume{
{
Name: "extra-files-0",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{Name: "my-instance-extra-files-1"},
},
},
},
{
Name: "extra-files-1",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{Name: "my-instance-extra-files-2"},
},
},
},
}
n.Spec.PodTemplate.VolumeMounts = []corev1.VolumeMount{
{
Name: "extra-files-0",
MountPath: "/etc/nginx/extra_files/waf.cfg",
SubPath: "waf.cfg",
ReadOnly: true,
},
{
Name: "extra-files-1",
MountPath: "/etc/nginx/extra_files/binary.exe",
SubPath: "binary.exe",
ReadOnly: true,
},
}
return n
},
},
}

for name, tt := range tests {
t.Run(name, func(t *testing.T) {
instance := &v1alpha1.RpaasInstance{
ObjectMeta: metav1.ObjectMeta{
Name: "my-instance",
Namespace: "rpaasv2",
},
Spec: v1alpha1.RpaasInstanceSpec{
PlanName: "my-plan",
},
}
if tt.instance != nil {
instance = tt.instance(instance)
}

plan := &v1alpha1.RpaasPlan{
ObjectMeta: metav1.ObjectMeta{
Name: "my-plan",
Namespace: "rpaasv2",
},
}
if tt.plan != nil {
plan = tt.plan(plan)
}

cm := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "my-instance-nginx-conf",
Namespace: "rpaasv2",
},
}

nginx := &nginxv1alpha1.Nginx{
TypeMeta: metav1.TypeMeta{
APIVersion: "nginx.tsuru.io/v1alpha1",
Kind: "Nginx",
},
ObjectMeta: metav1.ObjectMeta{
Name: "my-instance",
Namespace: "rpaasv2",
Labels: map[string]string{
"rpaas.extensions.tsuru.io/instance-name": "my-instance",
"rpaas.extensions.tsuru.io/plan-name": "my-plan",
},
OwnerReferences: []metav1.OwnerReference{{
APIVersion: "extensions.tsuru.io/v1alpha1",
Kind: "RpaasInstance",
Name: "my-instance",
Controller: func(b bool) *bool { return &b }(true),
BlockOwnerDeletion: func(b bool) *bool { return &b }(true),
}},
},
Spec: nginxv1alpha1.NginxSpec{
Config: &nginxv1alpha1.ConfigRef{
Kind: nginxv1alpha1.ConfigKindConfigMap,
Name: "my-instance-nginx-conf",
},
HealthcheckPath: "/_nginx_healthcheck",
},
}
if tt.expected != nil {
nginx = tt.expected(nginx)
}

got := newNginx(instance, plan, cm)
assert.Equal(t, nginx, got)
})
}
}

func Test_mergePlans(t *testing.T) {
tests := []struct {
base v1alpha1.RpaasPlanSpec
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
github.com/uber/jaeger-client-go v2.25.0+incompatible
github.com/urfave/cli/v2 v2.3.0
github.com/willf/bitset v1.1.11
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
k8s.io/api v0.24.2
Expand Down Expand Up @@ -79,7 +80,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.8.0 h1:mtR24eN6rapCN+shds82qFEIWWmg64NPMuyCNT7/Ogc=
github.com/google/go-containerregistry v0.8.0/go.mod h1:wW5v71NHGnQyb4k+gSshjxidrC7lN33MdWEn+Mz9TsI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down Expand Up @@ -1207,6 +1208,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
Expand Down Expand Up @@ -1561,7 +1564,6 @@ golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
Expand Down
22 changes: 22 additions & 0 deletions internal/pkg/rpaas/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ var (
ErrNoPoolDefined = errors.New("No pool defined")
)

type NotModifiedError struct {
Msg string `json:"message"`
Internal error `json:"-"`
}

func (NotModifiedError) IsNotModified() bool {
return true
}

func (e NotModifiedError) Error() string {
return e.Msg
}

func (e NotModifiedError) Unwrap() error {
return e.Internal
}

type ValidationError struct {
Msg string `json:"message"`
Internal error `json:"-"`
Expand Down Expand Up @@ -65,6 +82,11 @@ func (e NotFoundError) Unwrap() error {
return e.Internal
}

func IsNotModifiedError(err error) bool {
_, ok := err.(interface{ IsNotModified() bool })
return ok
}

func IsValidationError(err error) bool {
if vErr, ok := err.(interface {
IsValidation() bool
Expand Down
Loading