Merge pull request #1615 from simonferquel/handle-v1alpha3

Handle v1alpha3 of Compose on Kubernetes API
This commit is contained in:
Sebastiaan van Stijn 2019-01-28 21:02:51 +01:00 committed by GitHub
commit cf6c238660
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 3188 additions and 136 deletions

View File

@ -103,7 +103,7 @@ func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) {
}
func (c *KubeCli) composeClient() (*Factory, error) {
return NewFactory(c.kubeNamespace, c.kubeConfig, c.clientSet)
return NewFactory(c.kubeNamespace, c.kubeConfig, c.clientSet, c.ClientInfo().HasExperimental)
}
func (c *KubeCli) checkHostsMatch() error {

View File

@ -1,7 +1,7 @@
package kubernetes
import (
kubernetes "github.com/docker/compose-on-kubernetes/api"
"github.com/docker/cli/kubernetes"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeclient "k8s.io/client-go/kubernetes"
@ -18,10 +18,11 @@ type Factory struct {
coreClientSet corev1.CoreV1Interface
appsClientSet appsv1beta2.AppsV1beta2Interface
clientSet *kubeclient.Clientset
experimental bool
}
// NewFactory creates a kubernetes client factory
func NewFactory(namespace string, config *restclient.Config, clientSet *kubeclient.Clientset) (*Factory, error) {
func NewFactory(namespace string, config *restclient.Config, clientSet *kubeclient.Clientset, experimental bool) (*Factory, error) {
coreClientSet, err := corev1.NewForConfig(config)
if err != nil {
return nil, err
@ -38,6 +39,7 @@ func NewFactory(namespace string, config *restclient.Config, clientSet *kubeclie
coreClientSet: coreClientSet,
appsClientSet: appsClientSet,
clientSet: clientSet,
experimental: experimental,
}, nil
}
@ -83,7 +85,7 @@ func (s *Factory) DaemonSets() typesappsv1beta2.DaemonSetInterface {
// Stacks returns a client for Docker's Stack on Kubernetes
func (s *Factory) Stacks(allNamespaces bool) (StackClient, error) {
version, err := kubernetes.GetStackAPIVersion(s.clientSet)
version, err := kubernetes.GetStackAPIVersion(s.clientSet.Discovery(), s.experimental)
if err != nil {
return nil, err
}
@ -97,7 +99,9 @@ func (s *Factory) Stacks(allNamespaces bool) (StackClient, error) {
return newStackV1Beta1(s.config, namespace)
case kubernetes.StackAPIV1Beta2:
return newStackV1Beta2(s.config, namespace)
case kubernetes.StackAPIV1Alpha3:
return newStackV1Alpha3(s.config, namespace)
default:
return nil, errors.Errorf("no supported Stack API version")
return nil, errors.Errorf("unsupported stack API version: %q", version)
}
}

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/cli/cli/compose/schema"
composeTypes "github.com/docker/cli/cli/compose/types"
composetypes "github.com/docker/cli/cli/compose/types"
latest "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta1"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
"github.com/pkg/errors"
@ -24,8 +25,8 @@ func NewStackConverter(version string) (StackConverter, error) {
switch version {
case "v1beta1":
return stackV1Beta1Converter{}, nil
case "v1beta2":
return stackV1Beta2Converter{}, nil
case "v1beta2", "v1alpha3":
return stackV1Beta2OrHigherConverter{}, nil
default:
return nil, errors.Errorf("stack version %s unsupported", version)
}
@ -61,9 +62,9 @@ func (s stackV1Beta1Converter) FromCompose(stderr io.Writer, name string, cfg *c
return st, nil
}
type stackV1Beta2Converter struct{}
type stackV1Beta2OrHigherConverter struct{}
func (s stackV1Beta2Converter) FromCompose(stderr io.Writer, name string, cfg *composetypes.Config) (Stack, error) {
func (s stackV1Beta2OrHigherConverter) FromCompose(stderr io.Writer, name string, cfg *composetypes.Config) (Stack, error) {
return fromCompose(stderr, name, cfg)
}
@ -113,7 +114,38 @@ func stackToV1beta1(s Stack) *v1beta1.Stack {
}
}
func stackFromV1beta2(in *v1beta2.Stack) Stack {
func stackFromV1beta2(in *v1beta2.Stack) (Stack, error) {
var spec *latest.StackSpec
if in.Spec != nil {
spec = &latest.StackSpec{}
if err := latest.Convert_v1beta2_StackSpec_To_v1alpha3_StackSpec(in.Spec, spec, nil); err != nil {
return Stack{}, err
}
}
return Stack{
Name: in.ObjectMeta.Name,
Namespace: in.ObjectMeta.Namespace,
Spec: spec,
}, nil
}
func stackToV1beta2(s Stack) (*v1beta2.Stack, error) {
var spec *v1beta2.StackSpec
if s.Spec != nil {
spec = &v1beta2.StackSpec{}
if err := latest.Convert_v1alpha3_StackSpec_To_v1beta2_StackSpec(s.Spec, spec, nil); err != nil {
return nil, err
}
}
return &v1beta2.Stack{
ObjectMeta: metav1.ObjectMeta{
Name: s.Name,
},
Spec: spec,
}, nil
}
func stackFromV1alpha3(in *latest.Stack) Stack {
return Stack{
Name: in.ObjectMeta.Name,
Namespace: in.ObjectMeta.Namespace,
@ -121,8 +153,8 @@ func stackFromV1beta2(in *v1beta2.Stack) Stack {
}
}
func stackToV1beta2(s Stack) *v1beta2.Stack {
return &v1beta2.Stack{
func stackToV1alpha3(s Stack) *latest.Stack {
return &latest.Stack{
ObjectMeta: metav1.ObjectMeta{
Name: s.Name,
},
@ -130,32 +162,32 @@ func stackToV1beta2(s Stack) *v1beta2.Stack {
}
}
func fromComposeConfig(stderr io.Writer, c *composeTypes.Config) *v1beta2.StackSpec {
func fromComposeConfig(stderr io.Writer, c *composeTypes.Config) *latest.StackSpec {
if c == nil {
return nil
}
warnUnsupportedFeatures(stderr, c)
serviceConfigs := make([]v1beta2.ServiceConfig, len(c.Services))
serviceConfigs := make([]latest.ServiceConfig, len(c.Services))
for i, s := range c.Services {
serviceConfigs[i] = fromComposeServiceConfig(s)
}
return &v1beta2.StackSpec{
return &latest.StackSpec{
Services: serviceConfigs,
Secrets: fromComposeSecrets(c.Secrets),
Configs: fromComposeConfigs(c.Configs),
}
}
func fromComposeSecrets(s map[string]composeTypes.SecretConfig) map[string]v1beta2.SecretConfig {
func fromComposeSecrets(s map[string]composeTypes.SecretConfig) map[string]latest.SecretConfig {
if s == nil {
return nil
}
m := map[string]v1beta2.SecretConfig{}
m := map[string]latest.SecretConfig{}
for key, value := range s {
m[key] = v1beta2.SecretConfig{
m[key] = latest.SecretConfig{
Name: value.Name,
File: value.File,
External: v1beta2.External{
External: latest.External{
Name: value.External.Name,
External: value.External.External,
},
@ -165,16 +197,16 @@ func fromComposeSecrets(s map[string]composeTypes.SecretConfig) map[string]v1bet
return m
}
func fromComposeConfigs(s map[string]composeTypes.ConfigObjConfig) map[string]v1beta2.ConfigObjConfig {
func fromComposeConfigs(s map[string]composeTypes.ConfigObjConfig) map[string]latest.ConfigObjConfig {
if s == nil {
return nil
}
m := map[string]v1beta2.ConfigObjConfig{}
m := map[string]latest.ConfigObjConfig{}
for key, value := range s {
m[key] = v1beta2.ConfigObjConfig{
m[key] = latest.ConfigObjConfig{
Name: value.Name,
File: value.File,
External: v1beta2.External{
External: latest.External{
Name: value.External.Name,
External: value.External.External,
},
@ -184,7 +216,7 @@ func fromComposeConfigs(s map[string]composeTypes.ConfigObjConfig) map[string]v1
return m
}
func fromComposeServiceConfig(s composeTypes.ServiceConfig) v1beta2.ServiceConfig {
func fromComposeServiceConfig(s composeTypes.ServiceConfig) latest.ServiceConfig {
var userID *int64
if s.User != "" {
numerical, err := strconv.Atoi(s.User)
@ -193,13 +225,13 @@ func fromComposeServiceConfig(s composeTypes.ServiceConfig) v1beta2.ServiceConfi
userID = &unixUserID
}
}
return v1beta2.ServiceConfig{
return latest.ServiceConfig{
Name: s.Name,
CapAdd: s.CapAdd,
CapDrop: s.CapDrop,
Command: s.Command,
Configs: fromComposeServiceConfigs(s.Configs),
Deploy: v1beta2.DeployConfig{
Deploy: latest.DeployConfig{
Mode: s.Deploy.Mode,
Replicas: s.Deploy.Replicas,
Labels: s.Deploy.Labels,
@ -231,13 +263,13 @@ func fromComposeServiceConfig(s composeTypes.ServiceConfig) v1beta2.ServiceConfi
}
}
func fromComposePorts(ports []composeTypes.ServicePortConfig) []v1beta2.ServicePortConfig {
func fromComposePorts(ports []composeTypes.ServicePortConfig) []latest.ServicePortConfig {
if ports == nil {
return nil
}
p := make([]v1beta2.ServicePortConfig, len(ports))
p := make([]latest.ServicePortConfig, len(ports))
for i, port := range ports {
p[i] = v1beta2.ServicePortConfig{
p[i] = latest.ServicePortConfig{
Mode: port.Mode,
Target: port.Target,
Published: port.Published,
@ -247,13 +279,13 @@ func fromComposePorts(ports []composeTypes.ServicePortConfig) []v1beta2.ServiceP
return p
}
func fromComposeServiceSecrets(secrets []composeTypes.ServiceSecretConfig) []v1beta2.ServiceSecretConfig {
func fromComposeServiceSecrets(secrets []composeTypes.ServiceSecretConfig) []latest.ServiceSecretConfig {
if secrets == nil {
return nil
}
c := make([]v1beta2.ServiceSecretConfig, len(secrets))
c := make([]latest.ServiceSecretConfig, len(secrets))
for i, secret := range secrets {
c[i] = v1beta2.ServiceSecretConfig{
c[i] = latest.ServiceSecretConfig{
Source: secret.Source,
Target: secret.Target,
UID: secret.UID,
@ -263,13 +295,13 @@ func fromComposeServiceSecrets(secrets []composeTypes.ServiceSecretConfig) []v1b
return c
}
func fromComposeServiceConfigs(configs []composeTypes.ServiceConfigObjConfig) []v1beta2.ServiceConfigObjConfig {
func fromComposeServiceConfigs(configs []composeTypes.ServiceConfigObjConfig) []latest.ServiceConfigObjConfig {
if configs == nil {
return nil
}
c := make([]v1beta2.ServiceConfigObjConfig, len(configs))
c := make([]latest.ServiceConfigObjConfig, len(configs))
for i, config := range configs {
c[i] = v1beta2.ServiceConfigObjConfig{
c[i] = latest.ServiceConfigObjConfig{
Source: config.Source,
Target: config.Target,
UID: config.UID,
@ -279,11 +311,11 @@ func fromComposeServiceConfigs(configs []composeTypes.ServiceConfigObjConfig) []
return c
}
func fromComposeHealthcheck(h *composeTypes.HealthCheckConfig) *v1beta2.HealthCheckConfig {
func fromComposeHealthcheck(h *composeTypes.HealthCheckConfig) *latest.HealthCheckConfig {
if h == nil {
return nil
}
return &v1beta2.HealthCheckConfig{
return &latest.HealthCheckConfig{
Test: h.Test,
Timeout: composetypes.ConvertDurationPtr(h.Timeout),
Interval: composetypes.ConvertDurationPtr(h.Interval),
@ -291,8 +323,8 @@ func fromComposeHealthcheck(h *composeTypes.HealthCheckConfig) *v1beta2.HealthCh
}
}
func fromComposePlacement(p composeTypes.Placement) v1beta2.Placement {
return v1beta2.Placement{
func fromComposePlacement(p composeTypes.Placement) latest.Placement {
return latest.Placement{
Constraints: fromComposeConstraints(p.Constraints),
}
}
@ -306,18 +338,18 @@ const (
swarmLabelPrefix = "node.labels."
)
func fromComposeConstraints(s []string) *v1beta2.Constraints {
func fromComposeConstraints(s []string) *latest.Constraints {
if len(s) == 0 {
return nil
}
constraints := &v1beta2.Constraints{}
constraints := &latest.Constraints{}
for _, constraint := range s {
matches := constraintEquals.FindStringSubmatch(constraint)
if len(matches) == 4 {
key := matches[1]
operator := matches[2]
value := matches[3]
constraint := &v1beta2.Constraint{
constraint := &latest.Constraint{
Operator: operator,
Value: value,
}
@ -330,7 +362,7 @@ func fromComposeConstraints(s []string) *v1beta2.Constraints {
constraints.Hostname = constraint
case strings.HasPrefix(key, swarmLabelPrefix):
if constraints.MatchLabels == nil {
constraints.MatchLabels = map[string]v1beta2.Constraint{}
constraints.MatchLabels = map[string]latest.Constraint{}
}
constraints.MatchLabels[strings.TrimPrefix(key, swarmLabelPrefix)] = *constraint
}
@ -339,48 +371,48 @@ func fromComposeConstraints(s []string) *v1beta2.Constraints {
return constraints
}
func fromComposeResources(r composeTypes.Resources) v1beta2.Resources {
return v1beta2.Resources{
func fromComposeResources(r composeTypes.Resources) latest.Resources {
return latest.Resources{
Limits: fromComposeResourcesResource(r.Limits),
Reservations: fromComposeResourcesResource(r.Reservations),
}
}
func fromComposeResourcesResource(r *composeTypes.Resource) *v1beta2.Resource {
func fromComposeResourcesResource(r *composeTypes.Resource) *latest.Resource {
if r == nil {
return nil
}
return &v1beta2.Resource{
return &latest.Resource{
MemoryBytes: int64(r.MemoryBytes),
NanoCPUs: r.NanoCPUs,
}
}
func fromComposeUpdateConfig(u *composeTypes.UpdateConfig) *v1beta2.UpdateConfig {
func fromComposeUpdateConfig(u *composeTypes.UpdateConfig) *latest.UpdateConfig {
if u == nil {
return nil
}
return &v1beta2.UpdateConfig{
return &latest.UpdateConfig{
Parallelism: u.Parallelism,
}
}
func fromComposeRestartPolicy(r *composeTypes.RestartPolicy) *v1beta2.RestartPolicy {
func fromComposeRestartPolicy(r *composeTypes.RestartPolicy) *latest.RestartPolicy {
if r == nil {
return nil
}
return &v1beta2.RestartPolicy{
return &latest.RestartPolicy{
Condition: r.Condition,
}
}
func fromComposeServiceVolumeConfig(vs []composeTypes.ServiceVolumeConfig) []v1beta2.ServiceVolumeConfig {
func fromComposeServiceVolumeConfig(vs []composeTypes.ServiceVolumeConfig) []latest.ServiceVolumeConfig {
if vs == nil {
return nil
}
volumes := []v1beta2.ServiceVolumeConfig{}
volumes := []latest.ServiceVolumeConfig{}
for _, v := range vs {
volumes = append(volumes, v1beta2.ServiceVolumeConfig{
volumes = append(volumes, latest.ServiceVolumeConfig{
Type: v.Type,
Source: v.Source,
Target: v.Target,

View File

@ -1,10 +1,15 @@
package kubernetes
import (
"path/filepath"
"testing"
"github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta1"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestNewStackConverter(t *testing.T) {
@ -15,4 +20,144 @@ func TestNewStackConverter(t *testing.T) {
assert.NilError(t, err)
_, err = NewStackConverter("v1beta2")
assert.NilError(t, err)
_, err = NewStackConverter("v1alpha3")
assert.NilError(t, err)
}
func TestConvertFromToV1beta1(t *testing.T) {
composefile := `version: "3.3"
services:
test:
image: nginx
secrets:
test:
file: testdata/secret
configs:
test:
file: testdata/config
`
stackv1beta1 := &v1beta1.Stack{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.StackSpec{
ComposeFile: composefile,
},
}
result, err := stackFromV1beta1(stackv1beta1)
assert.NilError(t, err)
expected := Stack{
Name: "test",
ComposeFile: composefile,
Spec: &v1alpha3.StackSpec{
Services: []v1alpha3.ServiceConfig{
{
Name: "test",
Image: "nginx",
Environment: make(map[string]*string),
},
},
Secrets: map[string]v1alpha3.SecretConfig{
"test": {File: filepath.FromSlash("testdata/secret")},
},
Configs: map[string]v1alpha3.ConfigObjConfig{
"test": {File: filepath.FromSlash("testdata/config")},
},
},
}
assert.DeepEqual(t, expected, result)
assert.DeepEqual(t, stackv1beta1, stackToV1beta1(result))
}
func TestConvertFromToV1beta2(t *testing.T) {
stackv1beta2 := &v1beta2.Stack{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: &v1beta2.StackSpec{
Services: []v1beta2.ServiceConfig{
{
Name: "test",
Image: "nginx",
Environment: make(map[string]*string),
},
},
Secrets: map[string]v1beta2.SecretConfig{
"test": {File: filepath.FromSlash("testdata/secret")},
},
Configs: map[string]v1beta2.ConfigObjConfig{
"test": {File: filepath.FromSlash("testdata/config")},
},
},
}
expected := Stack{
Name: "test",
Spec: &v1alpha3.StackSpec{
Services: []v1alpha3.ServiceConfig{
{
Name: "test",
Image: "nginx",
Environment: make(map[string]*string),
},
},
Secrets: map[string]v1alpha3.SecretConfig{
"test": {File: filepath.FromSlash("testdata/secret")},
},
Configs: map[string]v1alpha3.ConfigObjConfig{
"test": {File: filepath.FromSlash("testdata/config")},
},
},
}
result, err := stackFromV1beta2(stackv1beta2)
assert.NilError(t, err)
assert.DeepEqual(t, expected, result)
gotBack, err := stackToV1beta2(result)
assert.NilError(t, err)
assert.DeepEqual(t, stackv1beta2, gotBack)
}
func TestConvertFromToV1alpha3(t *testing.T) {
stackv1alpha3 := &v1alpha3.Stack{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: &v1alpha3.StackSpec{
Services: []v1alpha3.ServiceConfig{
{
Name: "test",
Image: "nginx",
Environment: make(map[string]*string),
},
},
Secrets: map[string]v1alpha3.SecretConfig{
"test": {File: filepath.FromSlash("testdata/secret")},
},
Configs: map[string]v1alpha3.ConfigObjConfig{
"test": {File: filepath.FromSlash("testdata/config")},
},
},
}
expected := Stack{
Name: "test",
Spec: &v1alpha3.StackSpec{
Services: []v1alpha3.ServiceConfig{
{
Name: "test",
Image: "nginx",
Environment: make(map[string]*string),
},
},
Secrets: map[string]v1alpha3.SecretConfig{
"test": {File: filepath.FromSlash("testdata/secret")},
},
Configs: map[string]v1alpha3.ConfigObjConfig{
"test": {File: filepath.FromSlash("testdata/config")},
},
},
}
result := stackFromV1alpha3(stackv1alpha3)
assert.DeepEqual(t, expected, result)
gotBack := stackToV1alpha3(result)
assert.DeepEqual(t, stackv1alpha3, gotBack)
}

View File

@ -4,8 +4,10 @@ import (
"errors"
"testing"
composev1alpha3 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1alpha3"
composev1beta1 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1beta1"
composev1beta2 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1beta2"
"github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta1"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
"gotest.tools/assert"
@ -31,11 +33,11 @@ configs:
test:
file: testdata/config
`,
Spec: &v1beta2.StackSpec{
Configs: map[string]v1beta2.ConfigObjConfig{
Spec: &v1alpha3.StackSpec{
Configs: map[string]v1alpha3.ConfigObjConfig{
"test": {Name: "test", File: "testdata/config"},
},
Secrets: map[string]v1beta2.SecretConfig{
Secrets: map[string]v1alpha3.SecretConfig{
"test": {Name: "test", File: "testdata/secret"},
},
},
@ -86,6 +88,24 @@ func TestCreateChildResourcesV1Beta2(t *testing.T) {
checkOwnerReferences(t, s.ObjectMeta, "test", v1beta2.SchemeGroupVersion.String())
}
func TestCreateChildResourcesV1Alpha3(t *testing.T) {
k8sclientSet := fake.NewSimpleClientset()
stack := testStack()
configs := k8sclientSet.CoreV1().ConfigMaps("test")
secrets := k8sclientSet.CoreV1().Secrets("test")
assert.NilError(t, createResources(
stack,
&stackV1Alpha3{stacks: &fakeV1alpha3Client{}},
configs,
secrets))
c, err := configs.Get("test", metav1.GetOptions{})
assert.NilError(t, err)
checkOwnerReferences(t, c.ObjectMeta, "test", v1alpha3.SchemeGroupVersion.String())
s, err := secrets.Get("test", metav1.GetOptions{})
assert.NilError(t, err)
checkOwnerReferences(t, s.ObjectMeta, "test", v1alpha3.SchemeGroupVersion.String())
}
func TestCreateChildResourcesWithStackCreationErrorV1Beta1(t *testing.T) {
k8sclientSet := fake.NewSimpleClientset()
stack := testStack()
@ -120,6 +140,23 @@ func TestCreateChildResourcesWithStackCreationErrorV1Beta2(t *testing.T) {
assert.Check(t, kerrors.IsNotFound(err))
}
func TestCreateChildResourcesWithStackCreationErrorV1Alpha3(t *testing.T) {
k8sclientSet := fake.NewSimpleClientset()
stack := testStack()
configs := k8sclientSet.CoreV1().ConfigMaps("test")
secrets := k8sclientSet.CoreV1().Secrets("test")
err := createResources(
stack,
&stackV1Alpha3{stacks: &fakeV1alpha3Client{errorOnCreate: true}},
configs,
secrets)
assert.Error(t, err, "some error")
_, err = configs.Get("test", metav1.GetOptions{})
assert.Check(t, kerrors.IsNotFound(err))
_, err = secrets.Get("test", metav1.GetOptions{})
assert.Check(t, kerrors.IsNotFound(err))
}
type fakeV1beta1Client struct {
errorOnCreate bool
}
@ -213,3 +250,50 @@ func (c *fakeV1beta2Client) Patch(name string, pt types.PatchType, data []byte,
func (c *fakeV1beta2Client) WithSkipValidation() composev1beta2.StackInterface {
return c
}
type fakeV1alpha3Client struct {
errorOnCreate bool
}
func (c *fakeV1alpha3Client) Create(s *v1alpha3.Stack) (*v1alpha3.Stack, error) {
if c.errorOnCreate {
return nil, errors.New("some error")
}
return s, nil
}
func (c *fakeV1alpha3Client) Update(*v1alpha3.Stack) (*v1alpha3.Stack, error) {
return nil, nil
}
func (c *fakeV1alpha3Client) UpdateStatus(*v1alpha3.Stack) (*v1alpha3.Stack, error) {
return nil, nil
}
func (c *fakeV1alpha3Client) Delete(name string, options *metav1.DeleteOptions) error {
return nil
}
func (c *fakeV1alpha3Client) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
return nil
}
func (c *fakeV1alpha3Client) Get(name string, options metav1.GetOptions) (*v1alpha3.Stack, error) {
return nil, kerrors.NewNotFound(v1beta1.SchemeGroupVersion.WithResource("stacks").GroupResource(), name)
}
func (c *fakeV1alpha3Client) List(opts metav1.ListOptions) (*v1alpha3.StackList, error) {
return nil, nil
}
func (c *fakeV1alpha3Client) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return nil, nil
}
func (c *fakeV1alpha3Client) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v1alpha3.Stack, error) {
return nil, nil
}
func (c *fakeV1alpha3Client) WithSkipValidation() composev1alpha3.StackInterface {
return c
}

View File

@ -5,7 +5,7 @@ import (
"path/filepath"
"sort"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
latest "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"github.com/docker/compose-on-kubernetes/api/labels"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -17,7 +17,7 @@ type Stack struct {
Name string
Namespace string
ComposeFile string
Spec *v1beta2.StackSpec
Spec *latest.StackSpec
}
type childResource interface {

View File

@ -3,8 +3,10 @@ package kubernetes
import (
"fmt"
composev1alpha3 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1alpha3"
composev1beta1 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1beta1"
composev1beta2 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1beta2"
"github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta1"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
"github.com/docker/compose-on-kubernetes/api/labels"
@ -123,7 +125,7 @@ func verify(services corev1.ServiceInterface, stackName string, service string)
// stackV1Beta2 implements stackClient interface and talks to compose component v1beta2.
type stackV1Beta2 struct {
stackV1Beta2Converter
stackV1Beta2OrHigherConverter
stacks composev1beta2.StackInterface
}
@ -136,17 +138,21 @@ func newStackV1Beta2(config *rest.Config, namespace string) (*stackV1Beta2, erro
}
func (s *stackV1Beta2) CreateOrUpdate(internalStack Stack, childResources []childResource) error {
// If it already exists, update the stack
var (
stack *v1beta2.Stack
err error
)
resolved, err := stackToV1beta2(internalStack)
if err != nil {
deleteChildResources(childResources)
return err
}
if stack, err = s.stacks.Get(internalStack.Name, metav1.GetOptions{}); err == nil {
stack.Spec = internalStack.Spec
stack.Spec = resolved.Spec
stack, err = s.stacks.Update(stack)
} else {
// Or create it
stack, err = s.stacks.Create(stackToV1beta2(internalStack))
stack, err = s.stacks.Create(resolved)
}
if err != nil {
deleteChildResources(childResources)
@ -173,7 +179,7 @@ func (s *stackV1Beta2) Get(name string) (Stack, error) {
if err != nil {
return Stack{}, err
}
return stackFromV1beta2(stackBeta2), nil
return stackFromV1beta2(stackBeta2)
}
func (s *stackV1Beta2) List(opts metav1.ListOptions) ([]Stack, error) {
@ -183,7 +189,9 @@ func (s *stackV1Beta2) List(opts metav1.ListOptions) ([]Stack, error) {
}
stacks := make([]Stack, len(list.Items))
for i := range list.Items {
stacks[i] = stackFromV1beta2(&list.Items[i])
if stacks[i], err = stackFromV1beta2(&list.Items[i]); err != nil {
return nil, err
}
}
return stacks, nil
}
@ -192,3 +200,75 @@ func (s *stackV1Beta2) List(opts metav1.ListOptions) ([]Stack, error) {
func (s *stackV1Beta2) IsColliding(servicesClient corev1.ServiceInterface, st Stack) error {
return nil
}
// stackV1Beta2 implements stackClient interface and talks to compose component v1beta2.
type stackV1Alpha3 struct {
stackV1Beta2OrHigherConverter
stacks composev1alpha3.StackInterface
}
func newStackV1Alpha3(config *rest.Config, namespace string) (*stackV1Alpha3, error) {
client, err := composev1alpha3.NewForConfig(config)
if err != nil {
return nil, err
}
return &stackV1Alpha3{stacks: client.Stacks(namespace)}, nil
}
func (s *stackV1Alpha3) CreateOrUpdate(internalStack Stack, childResources []childResource) error {
var (
stack *v1alpha3.Stack
err error
)
resolved := stackToV1alpha3(internalStack)
if stack, err = s.stacks.Get(internalStack.Name, metav1.GetOptions{}); err == nil {
stack.Spec = resolved.Spec
stack, err = s.stacks.Update(stack)
} else {
// Or create it
stack, err = s.stacks.Create(resolved)
}
if err != nil {
deleteChildResources(childResources)
return err
}
blockOwnerDeletion := true
isController := true
return setChildResourcesOwner(childResources, metav1.OwnerReference{
APIVersion: v1alpha3.SchemeGroupVersion.String(),
Kind: "Stack",
Name: stack.Name,
UID: stack.UID,
BlockOwnerDeletion: &blockOwnerDeletion,
Controller: &isController,
})
}
func (s *stackV1Alpha3) Delete(name string) error {
return s.stacks.Delete(name, &metav1.DeleteOptions{})
}
func (s *stackV1Alpha3) Get(name string) (Stack, error) {
stackAlpha3, err := s.stacks.Get(name, metav1.GetOptions{})
if err != nil {
return Stack{}, err
}
return stackFromV1alpha3(stackAlpha3), nil
}
func (s *stackV1Alpha3) List(opts metav1.ListOptions) ([]Stack, error) {
list, err := s.stacks.List(opts)
if err != nil {
return nil, err
}
stacks := make([]Stack, len(list.Items))
for i := range list.Items {
stacks[i] = stackFromV1alpha3(&list.Items[i])
}
return stacks, nil
}
// IsColliding is handle server side with the compose api v1beta2, so nothing to do here
func (s *stackV1Alpha3) IsColliding(servicesClient corev1.ServiceInterface, st Stack) error {
return nil
}

View File

@ -12,8 +12,8 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
kubecontext "github.com/docker/cli/cli/context/kubernetes"
"github.com/docker/cli/kubernetes"
"github.com/docker/cli/templates"
kubernetes "github.com/docker/compose-on-kubernetes/api"
"github.com/docker/docker/api/types"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -260,13 +260,13 @@ func getKubernetesVersion(dockerCli command.Cli, kubeConfig string) *kubernetesV
logrus.Debugf("failed to get Kubernetes client: %s", err)
return &version
}
version.StackAPI = getStackVersion(kubeClient)
version.StackAPI = getStackVersion(kubeClient, dockerCli.ClientInfo().HasExperimental)
version.Kubernetes = getKubernetesServerVersion(kubeClient)
return &version
}
func getStackVersion(client *kubernetesClient.Clientset) string {
apiVersion, err := kubernetes.GetStackAPIVersion(client)
func getStackVersion(client *kubernetesClient.Clientset, experimental bool) string {
apiVersion, err := kubernetes.GetStackAPIVersion(client, experimental)
if err != nil {
logrus.Debugf("failed to get Stack API version: %s", err)
return "Unknown"

View File

@ -1,20 +1,60 @@
package kubernetes
import api "github.com/docker/compose-on-kubernetes/api"
import (
apiv1alpha3 "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
apiv1beta1 "github.com/docker/compose-on-kubernetes/api/compose/v1beta1"
apiv1beta2 "github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
"github.com/pkg/errors"
apimachinerymetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
)
// StackVersion represents the detected Compose Component on Kubernetes side.
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.StackVersion instead
type StackVersion = api.StackVersion
type StackVersion string
const (
// StackAPIV1Beta1 is returned if it's the most recent version available.
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.StackAPIV1Beta1 instead
StackAPIV1Beta1 = api.StackAPIV1Beta1
StackAPIV1Beta1 = StackVersion("v1beta1")
// StackAPIV1Beta2 is returned if it's the most recent version available.
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.StackAPIV1Beta2 instead
StackAPIV1Beta2 = api.StackAPIV1Beta2
StackAPIV1Beta2 = StackVersion("v1beta2")
// StackAPIV1Alpha3 is returned if it's the most recent version available, and experimental flag is on.
StackAPIV1Alpha3 = StackVersion("v1alpha3")
)
// GetStackAPIVersion returns the most recent stack API installed.
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.GetStackAPIVersion instead
var GetStackAPIVersion = api.GetStackAPIVersion
// GetStackAPIVersion returns the most appropriate stack API version installed.
func GetStackAPIVersion(serverGroups discovery.ServerGroupsInterface, experimental bool) (StackVersion, error) {
groups, err := serverGroups.ServerGroups()
if err != nil {
return "", err
}
return getAPIVersion(groups, experimental)
}
func getAPIVersion(groups *metav1.APIGroupList, experimental bool) (StackVersion, error) {
switch {
case experimental && findVersion(apiv1alpha3.SchemeGroupVersion, groups.Groups):
return StackAPIV1Alpha3, nil
case findVersion(apiv1beta2.SchemeGroupVersion, groups.Groups):
return StackAPIV1Beta2, nil
case findVersion(apiv1beta1.SchemeGroupVersion, groups.Groups):
return StackAPIV1Beta1, nil
default:
return "", errors.New("failed to find a Stack API version")
}
}
func findVersion(stackAPI schema.GroupVersion, groups []apimachinerymetav1.APIGroup) bool {
for _, group := range groups {
if group.Name == stackAPI.Group {
for _, version := range group.Versions {
if version.Version == stackAPI.Version {
return true
}
}
}
}
return false
}

54
kubernetes/check_test.go Normal file
View File

@ -0,0 +1,54 @@
package kubernetes
import (
"testing"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestGetStackAPIVersion(t *testing.T) {
var tests = []struct {
description string
groups *metav1.APIGroupList
experimental bool
err bool
expectedStack StackVersion
}{
{"no stack api", makeGroups(), false, true, ""},
{"v1beta1", makeGroups(groupVersion{"compose.docker.com", []string{"v1beta1"}}), false, false, StackAPIV1Beta1},
{"v1beta2", makeGroups(groupVersion{"compose.docker.com", []string{"v1beta2"}}), false, false, StackAPIV1Beta2},
{"most recent has precedence", makeGroups(groupVersion{"compose.docker.com", []string{"v1beta1", "v1beta2"}}), false, false, StackAPIV1Beta2},
{"most recent has precedence", makeGroups(groupVersion{"compose.docker.com", []string{"v1beta1", "v1beta2", "v1alpha3"}}), false, false, StackAPIV1Beta2},
{"most recent has precedence", makeGroups(groupVersion{"compose.docker.com", []string{"v1beta1", "v1beta2", "v1alpha3"}}), true, false, StackAPIV1Alpha3},
}
for _, test := range tests {
version, err := getAPIVersion(test.groups, test.experimental)
if test.err {
assert.ErrorContains(t, err, "")
} else {
assert.NilError(t, err)
}
assert.Check(t, is.Equal(test.expectedStack, version))
}
}
type groupVersion struct {
name string
versions []string
}
func makeGroups(versions ...groupVersion) *metav1.APIGroupList {
groups := make([]metav1.APIGroup, len(versions))
for i := range versions {
groups[i].Name = versions[i].name
for _, v := range versions[i].versions {
groups[i].Versions = append(groups[i].Versions, metav1.GroupVersionForDiscovery{Version: v})
}
}
return &metav1.APIGroupList{
Groups: groups,
}
}

View File

@ -14,7 +14,7 @@ github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 # v1.1.0
github.com/dgrijalva/jwt-go a2c85815a77d0f951e33ba4db5ae93629a1530af
github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5
github.com/docker/docker f76d6a078d881f410c00e8d900dcdfc2e026c841
github.com/docker/compose-on-kubernetes a6086e2369e39c2058a003a7eb42e567ecfd1f03 # v0.4.17
github.com/docker/compose-on-kubernetes 1559927c6b456d56cc9c9b05438252ebb646640b # master w/ v1alpha3
github.com/docker/docker-credential-helpers 5241b46610f2491efdf9d1c85f1ddf5b02f6d962
# the docker/go package contains a customized version of canonical/json
# and is used by Notary. The package is periodically rebased on current Go versions.

View File

@ -185,3 +185,5 @@ See the [contributing](./CONTRIBUTING.md) and [debugging](./DEBUGGING.md) guides
# Deploying Compose on Kubernetes
- Guide for [Azure AKS](./docs/install-on-aks.md).
- Guide for [GKE](./docs/install-on-gke.md).
- Guide for [Minikube](./docs/install-on-minikube.md).

View File

@ -1,55 +0,0 @@
package apis
import (
apiv1beta1 "github.com/docker/compose-on-kubernetes/api/compose/v1beta1"
apiv1beta2 "github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
"github.com/pkg/errors"
apimachinerymetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
)
// StackVersion represents the detected Compose Component on Kubernetes side.
type StackVersion string
const (
// StackAPIV1Beta1 is returned if it's the most recent version available.
StackAPIV1Beta1 = StackVersion("v1beta1")
// StackAPIV1Beta2 is returned if it's the most recent version available.
StackAPIV1Beta2 = StackVersion("v1beta2")
)
// GetStackAPIVersion returns the most recent stack API installed.
func GetStackAPIVersion(clientSet *kubernetes.Clientset) (StackVersion, error) {
groups, err := clientSet.Discovery().ServerGroups()
if err != nil {
return "", err
}
return getAPIVersion(groups)
}
func getAPIVersion(groups *metav1.APIGroupList) (StackVersion, error) {
switch {
case findVersion(apiv1beta2.SchemeGroupVersion, groups.Groups):
return StackAPIV1Beta2, nil
case findVersion(apiv1beta1.SchemeGroupVersion, groups.Groups):
return StackAPIV1Beta1, nil
default:
return "", errors.Errorf("failed to find a Stack API version")
}
}
func findVersion(stackAPI schema.GroupVersion, groups []apimachinerymetav1.APIGroup) bool {
for _, group := range groups {
if group.Name == stackAPI.Group {
for _, version := range group.Versions {
if version.Version == stackAPI.Version {
return true
}
}
}
}
return false
}

View File

@ -1,6 +1,7 @@
package clientset
import (
composev1alpha3 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1alpha3"
composev1beta1 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1beta1"
composev1beta2 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1beta2"
glog "github.com/golang/glog"
@ -13,20 +14,36 @@ import (
// FIXME(vdemeester) is it required ?
type Interface interface {
Discovery() discovery.DiscoveryInterface
ComposeV1alpha3() composev1alpha3.ComposeV1alpha3Interface
ComposeV1beta2() composev1beta2.ComposeV1beta2Interface
ComposeV1beta1() composev1beta1.ComposeV1beta1Interface
// Deprecated: please explicitly pick a version if possible.
Compose() composev1beta1.ComposeV1beta1Interface
ComposeLatest() composev1alpha3.ComposeV1alpha3Interface
}
// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
*discovery.DiscoveryClient
*composev1alpha3.ComposeV1alpha3Client
*composev1beta2.ComposeV1beta2Client
*composev1beta1.ComposeV1beta1Client
}
// ComposeV1alpha3 retrieves the ComposeV1alpha3Client
func (c *Clientset) ComposeV1alpha3() composev1alpha3.ComposeV1alpha3Interface {
if c == nil {
return nil
}
return c.ComposeV1alpha3Client
}
// ComposeLatest retrieves the latest version of the client
func (c *Clientset) ComposeLatest() composev1alpha3.ComposeV1alpha3Interface {
return c.ComposeV1alpha3()
}
// ComposeV1beta2 retrieves the ComposeV1beta2Client
func (c *Clientset) ComposeV1beta2() composev1beta2.ComposeV1beta2Interface {
if c == nil {
@ -68,6 +85,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
}
var cs Clientset
var err error
cs.ComposeV1alpha3Client, err = composev1alpha3.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
}
cs.ComposeV1beta2Client, err = composev1beta2.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
@ -89,6 +110,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *Clientset {
var cs Clientset
cs.ComposeV1alpha3Client = composev1alpha3.NewForConfigOrDie(c)
cs.ComposeV1beta2Client = composev1beta2.NewForConfigOrDie(c)
cs.ComposeV1beta1Client = composev1beta1.NewForConfigOrDie(c)
@ -99,6 +121,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
// New creates a new Clientset for the given RESTClient.
func New(c rest.Interface) *Clientset {
var cs Clientset
cs.ComposeV1alpha3Client = composev1alpha3.New(c)
cs.ComposeV1beta2Client = composev1beta2.New(c)
cs.ComposeV1beta1Client = composev1beta1.New(c)

View File

@ -1,6 +1,7 @@
package scheme
import (
composev1alpha3 "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
composev1beta1 "github.com/docker/compose-on-kubernetes/api/compose/v1beta1"
composev1beta2 "github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -39,6 +40,7 @@ func init() {
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
// correctly.
func AddToScheme(scheme *runtime.Scheme) {
composev1alpha3.AddToScheme(scheme)
composev1beta2.AddToScheme(scheme)
composev1beta1.AddToScheme(scheme)

View File

@ -0,0 +1,74 @@
package v1alpha3
import (
"github.com/docker/compose-on-kubernetes/api/client/clientset/scheme"
v1alpha3 "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
rest "k8s.io/client-go/rest"
)
// ComposeV1alpha3Interface defines the methods a compose v1alpha3 client has
type ComposeV1alpha3Interface interface {
RESTClient() rest.Interface
StacksGetter
}
// ComposeV1alpha3Client is used to interact with features provided by the compose.docker.com group.
type ComposeV1alpha3Client struct {
restClient rest.Interface
}
// Stacks returns a stack client
func (c *ComposeV1alpha3Client) Stacks(namespace string) StackInterface {
return newStacks(c, namespace)
}
// NewForConfig creates a new ComposeV1alpha3Client for the given config.
func NewForConfig(c *rest.Config) (*ComposeV1alpha3Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &ComposeV1alpha3Client{client}, nil
}
// NewForConfigOrDie creates a new ComposeV1alpha3Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *ComposeV1alpha3Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new ComposeV1alpha3Client for the given RESTClient.
func New(c rest.Interface) *ComposeV1alpha3Client {
return &ComposeV1alpha3Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv := v1alpha3.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
return nil
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *ComposeV1alpha3Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}

View File

@ -0,0 +1,172 @@
package v1alpha3
import (
scheme "github.com/docker/compose-on-kubernetes/api/client/clientset/scheme"
v1alpha3 "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// StacksGetter has a method to return a StackInterface.
// A group's client should implement this interface.
type StacksGetter interface {
Stacks(namespace string) StackInterface
}
// StackInterface has methods to work with Stack resources.
type StackInterface interface {
Create(*v1alpha3.Stack) (*v1alpha3.Stack, error)
Update(*v1alpha3.Stack) (*v1alpha3.Stack, error)
UpdateStatus(*v1alpha3.Stack) (*v1alpha3.Stack, error)
Delete(name string, options *v1.DeleteOptions) error
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
Get(name string, options v1.GetOptions) (*v1alpha3.Stack, error)
List(opts v1.ListOptions) (*v1alpha3.StackList, error)
Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v1alpha3.Stack, error)
WithSkipValidation() StackInterface
}
// stacks implements StackInterface
type stacks struct {
skipValidation bool
client rest.Interface
ns string
}
// newStacks returns a Stacks
func newStacks(c *ComposeV1alpha3Client, namespace string) *stacks {
return &stacks{
client: c.RESTClient(),
ns: namespace,
}
}
func (c *stacks) handleSkipValidation(req *rest.Request) *rest.Request {
if !c.skipValidation {
return req
}
return req.Param("skip-validation", "1")
}
// Create takes the representation of a stack and creates it. Returns the server's representation of the stack, and an error, if there is any.
func (c *stacks) Create(stack *v1alpha3.Stack) (*v1alpha3.Stack, error) {
result := &v1alpha3.Stack{}
err := c.handleSkipValidation(c.client.Post().
Namespace(c.ns).
Resource("stacks").
Body(stack)).
Do().
Into(result)
return result, err
}
// Update takes the representation of a stack and updates it. Returns the server's representation of the stack, and an error, if there is any.
func (c *stacks) Update(stack *v1alpha3.Stack) (*v1alpha3.Stack, error) {
result := &v1alpha3.Stack{}
err := c.handleSkipValidation(c.client.Put().
Namespace(c.ns).
Resource("stacks").
Name(stack.Name).
Body(stack)).
Do().
Into(result)
return result, err
}
// UpdateStatus was generated because the type contains a Status member.
func (c *stacks) UpdateStatus(stack *v1alpha3.Stack) (*v1alpha3.Stack, error) {
result := &v1alpha3.Stack{}
err := c.handleSkipValidation(c.client.Put().
Namespace(c.ns).
Resource("stacks").
Name(stack.Name).
SubResource("status").
Body(stack)).
Do().
Into(result)
return result, err
}
// Delete takes name of the stack and deletes it. Returns an error if one occurs.
func (c *stacks) Delete(name string, options *v1.DeleteOptions) error {
return c.handleSkipValidation(c.client.Delete().
Namespace(c.ns).
Resource("stacks").
Name(name).
Body(options)).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *stacks) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
return c.handleSkipValidation(c.client.Delete().
Namespace(c.ns).
Resource("stacks").
VersionedParams(&listOptions, scheme.ParameterCodec).
Body(options)).
Do().
Error()
}
// Get takes name of the stack, and returns the corresponding stack object, and an error if there is any.
func (c *stacks) Get(name string, options v1.GetOptions) (*v1alpha3.Stack, error) {
result := &v1alpha3.Stack{}
err := c.client.Get().
Namespace(c.ns).
Resource("stacks").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return result, err
}
// List takes label and field selectors, and returns the list of Stacks that match those selectors.
func (c *stacks) List(opts v1.ListOptions) (*v1alpha3.StackList, error) {
result := &v1alpha3.StackList{}
err := c.client.Get().
Namespace(c.ns).
Resource("stacks").
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(result)
return result, err
}
// Watch returns a watch.Interface that watches the requested stacks.
func (c *stacks) Watch(opts v1.ListOptions) (watch.Interface, error) {
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("stacks").
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
// Patch applies the patch and returns the patched stack.
func (c *stacks) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v1alpha3.Stack, error) {
result := &v1alpha3.Stack{}
err := c.handleSkipValidation(c.client.Patch(pt).
Namespace(c.ns).
Resource("stacks").
SubResource(subresources...).
Name(name).
Body(data)).
Do().
Into(result)
return result, err
}
// WithSkipValidation creates a new Stack Client interface with validation disabled
func (c *stacks) WithSkipValidation() StackInterface {
return &stacks{
skipValidation: true,
client: c.client,
ns: c.ns,
}
}

View File

@ -1,6 +1,7 @@
package compose
import (
"github.com/docker/compose-on-kubernetes/api/client/informers/compose/v1alpha3"
"github.com/docker/compose-on-kubernetes/api/client/informers/compose/v1beta2"
"github.com/docker/compose-on-kubernetes/api/client/informers/internalinterfaces"
)
@ -8,6 +9,7 @@ import (
// Interface provides access to each of this group's versions.
type Interface interface {
V1beta2() v1beta2.Interface
V1alpha3() v1alpha3.Interface
}
type group struct {
@ -23,3 +25,8 @@ func New(f internalinterfaces.SharedInformerFactory) Interface {
func (g *group) V1beta2() v1beta2.Interface {
return v1beta2.New(g.SharedInformerFactory)
}
// V1alpha3 returns a new V1alpha3.Interface.
func (g *group) V1alpha3() v1alpha3.Interface {
return v1alpha3.New(g.SharedInformerFactory)
}

View File

@ -0,0 +1,25 @@
package v1alpha3
import (
"github.com/docker/compose-on-kubernetes/api/client/informers/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// Stacks returns a StackInformer.
Stacks() StackInformer
}
type version struct {
internalinterfaces.SharedInformerFactory
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory) Interface {
return &version{f}
}
// Stacks returns a StackInformer.
func (v *version) Stacks() StackInformer {
return &stackInformer{factory: v.SharedInformerFactory}
}

View File

@ -0,0 +1,51 @@
package v1alpha3
import (
"time"
"github.com/docker/compose-on-kubernetes/api/client/clientset"
"github.com/docker/compose-on-kubernetes/api/client/informers/internalinterfaces"
"github.com/docker/compose-on-kubernetes/api/client/listers/compose/v1alpha3"
compose_v1alpha3 "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/tools/cache"
)
// StackInformer provides access to a shared informer and lister for
// Stacks.
type StackInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1alpha3.StackLister
}
type stackInformer struct {
factory internalinterfaces.SharedInformerFactory
}
func newStackInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
sharedIndexInformer := cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
return client.ComposeV1alpha3().Stacks(v1.NamespaceAll).List(options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
return client.ComposeV1alpha3().Stacks(v1.NamespaceAll).Watch(options)
},
},
&compose_v1alpha3.Stack{},
resyncPeriod,
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
)
return sharedIndexInformer
}
func (f *stackInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&compose_v1alpha3.Stack{}, newStackInformer)
}
func (f *stackInformer) Lister() v1alpha3.StackLister {
return v1alpha3.NewStackLister(f.Informer().GetIndexer())
}

View File

@ -3,6 +3,7 @@ package informers
import (
"fmt"
"github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/tools/cache"
@ -37,7 +38,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
// Group=Compose, Version=V1beta1
case v1beta2.SchemeGroupVersion.WithResource("stacks"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Compose().V1beta2().Stacks().Informer()}, nil
case v1alpha3.SchemeGroupVersion.WithResource("stacks"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Compose().V1alpha3().Stacks().Informer()}, nil
}
return nil, fmt.Errorf("no informer found for %v", resource)

View File

@ -0,0 +1,9 @@
package v1alpha3
// StackListerExpansion allows custom methods to be added to
// StackLister.
type StackListerExpansion interface{}
// StackNamespaceListerExpansion allows custom methods to be added to
// StackNamespaceLister.
type StackNamespaceListerExpansion interface{}

View File

@ -0,0 +1,78 @@
package v1alpha3
import (
"github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// StackLister helps list Stacks.
type StackLister interface {
// List lists all Stacks in the indexer.
List(selector labels.Selector) ([]*v1alpha3.Stack, error)
// Stacks returns an object that can list and get Stacks.
Stacks(namespace string) StackNamespaceLister
StackListerExpansion
}
// stackLister implements the StackLister interface.
type stackLister struct {
indexer cache.Indexer
}
// NewStackLister returns a new StackLister.
func NewStackLister(indexer cache.Indexer) StackLister {
return &stackLister{indexer: indexer}
}
// List lists all Stacks in the indexer.
func (s *stackLister) List(selector labels.Selector) ([]*v1alpha3.Stack, error) {
stacks := []*v1alpha3.Stack{}
err := cache.ListAll(s.indexer, selector, func(m interface{}) {
stacks = append(stacks, m.(*v1alpha3.Stack))
})
return stacks, err
}
// Stacks returns an object that can list and get Stacks.
func (s *stackLister) Stacks(namespace string) StackNamespaceLister {
return stackNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// StackNamespaceLister helps list and get Stacks.
type StackNamespaceLister interface {
// List lists all Stacks in the indexer for a given namespace.
List(selector labels.Selector) ([]*v1alpha3.Stack, error)
// Get retrieves the Stack from the indexer for a given namespace and name.
Get(name string) (*v1alpha3.Stack, error)
StackNamespaceListerExpansion
}
// stackNamespaceLister implements the StackNamespaceLister
// interface.
type stackNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all Stacks in the indexer for a given namespace.
func (s stackNamespaceLister) List(selector labels.Selector) ([]*v1alpha3.Stack, error) {
stacks := []*v1alpha3.Stack{}
err := cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
stacks = append(stacks, m.(*v1alpha3.Stack))
})
return stacks, err
}
// Get retrieves the Stack from the indexer for a given namespace and name.
func (s stackNamespaceLister) Get(name string) (*v1alpha3.Stack, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1alpha3.GroupResource("stack"), name)
}
return obj.(*v1alpha3.Stack), nil
}

View File

@ -0,0 +1,26 @@
package v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// ComposeFile is the content of a stack's compose file if any
type ComposeFile struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
ComposeFile string `json:"composeFile,omitempty"`
}
func (c *ComposeFile) clone() *ComposeFile {
if c == nil {
return nil
}
res := *c
return &res
}
// DeepCopyObject clones the ComposeFile
func (c *ComposeFile) DeepCopyObject() runtime.Object {
return c.clone()
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,660 @@
// +build !ignore_autogenerated
/*
Copyright The Kubernetes 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.
*/
// Code generated by C:\gohome\bin\deepcopy-gen.exe. DO NOT EDIT.
package v1alpha3
import (
time "time"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConfigObjConfig) DeepCopyInto(out *ConfigObjConfig) {
*out = *in
out.External = in.External
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigObjConfig.
func (in *ConfigObjConfig) DeepCopy() *ConfigObjConfig {
if in == nil {
return nil
}
out := new(ConfigObjConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Constraint) DeepCopyInto(out *Constraint) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Constraint.
func (in *Constraint) DeepCopy() *Constraint {
if in == nil {
return nil
}
out := new(Constraint)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Constraints) DeepCopyInto(out *Constraints) {
*out = *in
if in.OperatingSystem != nil {
in, out := &in.OperatingSystem, &out.OperatingSystem
if *in == nil {
*out = nil
} else {
*out = new(Constraint)
**out = **in
}
}
if in.Architecture != nil {
in, out := &in.Architecture, &out.Architecture
if *in == nil {
*out = nil
} else {
*out = new(Constraint)
**out = **in
}
}
if in.Hostname != nil {
in, out := &in.Hostname, &out.Hostname
if *in == nil {
*out = nil
} else {
*out = new(Constraint)
**out = **in
}
}
if in.MatchLabels != nil {
in, out := &in.MatchLabels, &out.MatchLabels
*out = make(map[string]Constraint, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Constraints.
func (in *Constraints) DeepCopy() *Constraints {
if in == nil {
return nil
}
out := new(Constraints)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeployConfig) DeepCopyInto(out *DeployConfig) {
*out = *in
if in.Replicas != nil {
in, out := &in.Replicas, &out.Replicas
if *in == nil {
*out = nil
} else {
*out = new(uint64)
**out = **in
}
}
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.UpdateConfig != nil {
in, out := &in.UpdateConfig, &out.UpdateConfig
if *in == nil {
*out = nil
} else {
*out = new(UpdateConfig)
(*in).DeepCopyInto(*out)
}
}
in.Resources.DeepCopyInto(&out.Resources)
if in.RestartPolicy != nil {
in, out := &in.RestartPolicy, &out.RestartPolicy
if *in == nil {
*out = nil
} else {
*out = new(RestartPolicy)
**out = **in
}
}
in.Placement.DeepCopyInto(&out.Placement)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeployConfig.
func (in *DeployConfig) DeepCopy() *DeployConfig {
if in == nil {
return nil
}
out := new(DeployConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *External) DeepCopyInto(out *External) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new External.
func (in *External) DeepCopy() *External {
if in == nil {
return nil
}
out := new(External)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FileObjectConfig) DeepCopyInto(out *FileObjectConfig) {
*out = *in
out.External = in.External
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileObjectConfig.
func (in *FileObjectConfig) DeepCopy() *FileObjectConfig {
if in == nil {
return nil
}
out := new(FileObjectConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FileReferenceConfig) DeepCopyInto(out *FileReferenceConfig) {
*out = *in
if in.Mode != nil {
in, out := &in.Mode, &out.Mode
if *in == nil {
*out = nil
} else {
*out = new(uint32)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileReferenceConfig.
func (in *FileReferenceConfig) DeepCopy() *FileReferenceConfig {
if in == nil {
return nil
}
out := new(FileReferenceConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HealthCheckConfig) DeepCopyInto(out *HealthCheckConfig) {
*out = *in
if in.Test != nil {
in, out := &in.Test, &out.Test
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
if *in == nil {
*out = nil
} else {
*out = new(time.Duration)
**out = **in
}
}
if in.Interval != nil {
in, out := &in.Interval, &out.Interval
if *in == nil {
*out = nil
} else {
*out = new(time.Duration)
**out = **in
}
}
if in.Retries != nil {
in, out := &in.Retries, &out.Retries
if *in == nil {
*out = nil
} else {
*out = new(uint64)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthCheckConfig.
func (in *HealthCheckConfig) DeepCopy() *HealthCheckConfig {
if in == nil {
return nil
}
out := new(HealthCheckConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Placement) DeepCopyInto(out *Placement) {
*out = *in
if in.Constraints != nil {
in, out := &in.Constraints, &out.Constraints
if *in == nil {
*out = nil
} else {
*out = new(Constraints)
(*in).DeepCopyInto(*out)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Placement.
func (in *Placement) DeepCopy() *Placement {
if in == nil {
return nil
}
out := new(Placement)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Resource) DeepCopyInto(out *Resource) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resource.
func (in *Resource) DeepCopy() *Resource {
if in == nil {
return nil
}
out := new(Resource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Resources) DeepCopyInto(out *Resources) {
*out = *in
if in.Limits != nil {
in, out := &in.Limits, &out.Limits
if *in == nil {
*out = nil
} else {
*out = new(Resource)
**out = **in
}
}
if in.Reservations != nil {
in, out := &in.Reservations, &out.Reservations
if *in == nil {
*out = nil
} else {
*out = new(Resource)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources.
func (in *Resources) DeepCopy() *Resources {
if in == nil {
return nil
}
out := new(Resources)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RestartPolicy) DeepCopyInto(out *RestartPolicy) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestartPolicy.
func (in *RestartPolicy) DeepCopy() *RestartPolicy {
if in == nil {
return nil
}
out := new(RestartPolicy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretConfig) DeepCopyInto(out *SecretConfig) {
*out = *in
out.External = in.External
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretConfig.
func (in *SecretConfig) DeepCopy() *SecretConfig {
if in == nil {
return nil
}
out := new(SecretConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceConfig) DeepCopyInto(out *ServiceConfig) {
*out = *in
if in.CapAdd != nil {
in, out := &in.CapAdd, &out.CapAdd
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.CapDrop != nil {
in, out := &in.CapDrop, &out.CapDrop
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Command != nil {
in, out := &in.Command, &out.Command
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Configs != nil {
in, out := &in.Configs, &out.Configs
*out = make([]ServiceConfigObjConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.Deploy.DeepCopyInto(&out.Deploy)
if in.Entrypoint != nil {
in, out := &in.Entrypoint, &out.Entrypoint
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Environment != nil {
in, out := &in.Environment, &out.Environment
*out = make(map[string]*string, len(*in))
for key, val := range *in {
if val == nil {
(*out)[key] = nil
} else {
outVal := *val
(*out)[key] = &outVal
}
}
}
if in.ExtraHosts != nil {
in, out := &in.ExtraHosts, &out.ExtraHosts
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.HealthCheck != nil {
in, out := &in.HealthCheck, &out.HealthCheck
if *in == nil {
*out = nil
} else {
*out = new(HealthCheckConfig)
(*in).DeepCopyInto(*out)
}
}
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Ports != nil {
in, out := &in.Ports, &out.Ports
*out = make([]ServicePortConfig, len(*in))
copy(*out, *in)
}
if in.Secrets != nil {
in, out := &in.Secrets, &out.Secrets
*out = make([]ServiceSecretConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.StopGracePeriod != nil {
in, out := &in.StopGracePeriod, &out.StopGracePeriod
if *in == nil {
*out = nil
} else {
*out = new(time.Duration)
**out = **in
}
}
if in.Tmpfs != nil {
in, out := &in.Tmpfs, &out.Tmpfs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.User != nil {
in, out := &in.User, &out.User
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.Volumes != nil {
in, out := &in.Volumes, &out.Volumes
*out = make([]ServiceVolumeConfig, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceConfig.
func (in *ServiceConfig) DeepCopy() *ServiceConfig {
if in == nil {
return nil
}
out := new(ServiceConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceConfigObjConfig) DeepCopyInto(out *ServiceConfigObjConfig) {
*out = *in
if in.Mode != nil {
in, out := &in.Mode, &out.Mode
if *in == nil {
*out = nil
} else {
*out = new(uint32)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceConfigObjConfig.
func (in *ServiceConfigObjConfig) DeepCopy() *ServiceConfigObjConfig {
if in == nil {
return nil
}
out := new(ServiceConfigObjConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServicePortConfig) DeepCopyInto(out *ServicePortConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePortConfig.
func (in *ServicePortConfig) DeepCopy() *ServicePortConfig {
if in == nil {
return nil
}
out := new(ServicePortConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceSecretConfig) DeepCopyInto(out *ServiceSecretConfig) {
*out = *in
if in.Mode != nil {
in, out := &in.Mode, &out.Mode
if *in == nil {
*out = nil
} else {
*out = new(uint32)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSecretConfig.
func (in *ServiceSecretConfig) DeepCopy() *ServiceSecretConfig {
if in == nil {
return nil
}
out := new(ServiceSecretConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceVolumeConfig) DeepCopyInto(out *ServiceVolumeConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceVolumeConfig.
func (in *ServiceVolumeConfig) DeepCopy() *ServiceVolumeConfig {
if in == nil {
return nil
}
out := new(ServiceVolumeConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StackSpec) DeepCopyInto(out *StackSpec) {
*out = *in
if in.Services != nil {
in, out := &in.Services, &out.Services
*out = make([]ServiceConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Secrets != nil {
in, out := &in.Secrets, &out.Secrets
*out = make(map[string]SecretConfig, len(*in))
for key, val := range *in {
newVal := new(SecretConfig)
val.DeepCopyInto(newVal)
(*out)[key] = *newVal
}
}
if in.Configs != nil {
in, out := &in.Configs, &out.Configs
*out = make(map[string]ConfigObjConfig, len(*in))
for key, val := range *in {
newVal := new(ConfigObjConfig)
val.DeepCopyInto(newVal)
(*out)[key] = *newVal
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StackSpec.
func (in *StackSpec) DeepCopy() *StackSpec {
if in == nil {
return nil
}
out := new(StackSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UpdateConfig) DeepCopyInto(out *UpdateConfig) {
*out = *in
if in.Parallelism != nil {
in, out := &in.Parallelism, &out.Parallelism
if *in == nil {
*out = nil
} else {
*out = new(uint64)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateConfig.
func (in *UpdateConfig) DeepCopy() *UpdateConfig {
if in == nil {
return nil
}
out := new(UpdateConfig)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,8 @@
// Api versions allow the api contract for a resource to be changed while keeping
// backward compatibility by support multiple concurrent versions
// of the same resource
// Package v1alpha3 is the current in dev version of the stack, containing evolution on top of v1beta2 structured spec
// +k8s:openapi-gen=true
// +k8s:conversion-gen=github.com/docker/compose-on-kubernetes/api/compose/v1beta2
package v1alpha3

View File

@ -0,0 +1,30 @@
package v1alpha3
import (
"github.com/docker/compose-on-kubernetes/api/compose/impersonation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// Owner describes the user who created the stack
type Owner struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Owner impersonation.Config `json:"owner,omitempty"`
}
func (o *Owner) clone() *Owner {
if o == nil {
return nil
}
result := new(Owner)
result.TypeMeta = o.TypeMeta
result.ObjectMeta = o.ObjectMeta
result.Owner = *result.Owner.Clone()
return result
}
// DeepCopyObject clones the owner
func (o *Owner) DeepCopyObject() runtime.Object {
return o.clone()
}

View File

@ -0,0 +1,42 @@
package v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the name of the compose group
const GroupName = "compose.docker.com"
var (
// SchemeGroupVersion is group version used to register these objects
SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha3"}
// SchemeBuilder is the scheme builder
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
// AddToScheme adds to scheme
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
localSchemeBuilder.Register(addKnownTypes)
}
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Stack{},
&StackList{},
&Owner{},
&ComposeFile{},
&Scale{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
// GroupResource takes an unqualified resource and returns a Group qualified GroupResource
func GroupResource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

View File

@ -0,0 +1,29 @@
package v1alpha3
import (
"github.com/docker/compose-on-kubernetes/api/compose/clone"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// Scale contains the current/desired replica count for services in a stack.
type Scale struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec map[string]int `json:"spec,omitempty"`
Status map[string]int `json:"status,omitempty"`
}
func (s *Scale) clone() *Scale {
return &Scale{
TypeMeta: s.TypeMeta,
ObjectMeta: s.ObjectMeta,
Spec: clone.MapOfStringToInt(s.Spec),
Status: clone.MapOfStringToInt(s.Status),
}
}
// DeepCopyObject clones the scale
func (s *Scale) DeepCopyObject() runtime.Object {
return s.clone()
}

View File

@ -0,0 +1,270 @@
package v1alpha3
import (
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// StackList is a list of stacks
type StackList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []Stack `json:"items" protobuf:"bytes,2,rep,name=items"`
}
// Stack is v1alpha3's representation of a Stack
type Stack struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec *StackSpec `json:"spec,omitempty"`
Status *StackStatus `json:"status,omitempty"`
}
// DeepCopyObject clones the stack
func (s *Stack) DeepCopyObject() runtime.Object {
return s.clone()
}
// DeepCopyObject clones the stack list
func (s *StackList) DeepCopyObject() runtime.Object {
if s == nil {
return nil
}
result := new(StackList)
result.TypeMeta = s.TypeMeta
result.ListMeta = s.ListMeta
if s.Items == nil {
return result
}
result.Items = make([]Stack, len(s.Items))
for ix, s := range s.Items {
result.Items[ix] = *s.clone()
}
return result
}
func (s *Stack) clone() *Stack {
if s == nil {
return nil
}
result := new(Stack)
result.TypeMeta = s.TypeMeta
result.ObjectMeta = s.ObjectMeta
result.Spec = s.Spec.DeepCopy()
result.Status = s.Status.clone()
return result
}
// StackSpec defines the desired state of Stack
// +k8s:deepcopy-gen=true
type StackSpec struct {
Services []ServiceConfig `json:"services,omitempty"`
Secrets map[string]SecretConfig `json:"secrets,omitempty"`
Configs map[string]ConfigObjConfig `json:"configs,omitempty"`
}
// ServiceConfig is the configuration of one service
// +k8s:deepcopy-gen=true
type ServiceConfig struct {
Name string `json:"name,omitempty"`
CapAdd []string `json:"cap_add,omitempty"`
CapDrop []string `json:"cap_drop,omitempty"`
Command []string `json:"command,omitempty"`
Configs []ServiceConfigObjConfig `json:"configs,omitempty"`
Deploy DeployConfig `json:"deploy,omitempty"`
Entrypoint []string `json:"entrypoint,omitempty"`
Environment map[string]*string `json:"environment,omitempty"`
ExtraHosts []string `json:"extra_hosts,omitempty"`
Hostname string `json:"hostname,omitempty"`
HealthCheck *HealthCheckConfig `json:"health_check,omitempty"`
Image string `json:"image,omitempty"`
Ipc string `json:"ipc,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Pid string `json:"pid,omitempty"`
Ports []ServicePortConfig `json:"ports,omitempty"`
Privileged bool `json:"privileged,omitempty"`
ReadOnly bool `json:"read_only,omitempty"`
Secrets []ServiceSecretConfig `json:"secrets,omitempty"`
StdinOpen bool `json:"stdin_open,omitempty"`
StopGracePeriod *time.Duration `json:"stop_grace_period,omitempty"`
Tmpfs []string `json:"tmpfs,omitempty"`
Tty bool `json:"tty,omitempty"`
User *int64 `json:"user,omitempty"`
Volumes []ServiceVolumeConfig `json:"volumes,omitempty"`
WorkingDir string `json:"working_dir,omitempty"`
}
// ServicePortConfig is the port configuration for a service
// +k8s:deepcopy-gen=true
type ServicePortConfig struct {
Mode string `json:"mode,omitempty"`
Target uint32 `json:"target,omitempty"`
Published uint32 `json:"published,omitempty"`
Protocol string `json:"protocol,omitempty"`
}
// FileObjectConfig is a config type for a file used by a service
// +k8s:deepcopy-gen=true
type FileObjectConfig struct {
Name string `json:"name,omitempty"`
File string `json:"file,omitempty"`
External External `json:"external,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
}
// SecretConfig for a secret
// +k8s:deepcopy-gen=true
type SecretConfig FileObjectConfig
// ConfigObjConfig is the config for the swarm "Config" object
// +k8s:deepcopy-gen=true
type ConfigObjConfig FileObjectConfig
// External identifies a Volume or Network as a reference to a resource that is
// not managed, and should already exist.
// External.name is deprecated and replaced by Volume.name
// +k8s:deepcopy-gen=true
type External struct {
Name string `json:"name,omitempty"`
External bool `json:"external,omitempty"`
}
// FileReferenceConfig for a reference to a swarm file object
// +k8s:deepcopy-gen=true
type FileReferenceConfig struct {
Source string `json:"source,omitempty"`
Target string `json:"target,omitempty"`
UID string `json:"uid,omitempty"`
GID string `json:"gid,omitempty"`
Mode *uint32 `json:"mode,omitempty"`
}
// ServiceConfigObjConfig is the config obj configuration for a service
// +k8s:deepcopy-gen=true
type ServiceConfigObjConfig FileReferenceConfig
// ServiceSecretConfig is the secret configuration for a service
// +k8s:deepcopy-gen=true
type ServiceSecretConfig FileReferenceConfig
// DeployConfig is the deployment configuration for a service
// +k8s:deepcopy-gen=true
type DeployConfig struct {
Mode string `json:"mode,omitempty"`
Replicas *uint64 `json:"replicas,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
UpdateConfig *UpdateConfig `json:"update_config,omitempty"`
Resources Resources `json:"resources,omitempty"`
RestartPolicy *RestartPolicy `json:"restart_policy,omitempty"`
Placement Placement `json:"placement,omitempty"`
}
// UpdateConfig is the service update configuration
// +k8s:deepcopy-gen=true
type UpdateConfig struct {
Parallelism *uint64 `json:"paralellism,omitempty"`
}
// Resources the resource limits and reservations
// +k8s:deepcopy-gen=true
type Resources struct {
Limits *Resource `json:"limits,omitempty"`
Reservations *Resource `json:"reservations,omitempty"`
}
// Resource is a resource to be limited or reserved
// +k8s:deepcopy-gen=true
type Resource struct {
NanoCPUs string `json:"cpus,omitempty"`
MemoryBytes int64 `json:"memory,omitempty"`
}
// RestartPolicy is the service restart policy
// +k8s:deepcopy-gen=true
type RestartPolicy struct {
Condition string `json:"condition,omitempty"`
}
// Placement constraints for the service
// +k8s:deepcopy-gen=true
type Placement struct {
Constraints *Constraints `json:"constraints,omitempty"`
}
// Constraints lists constraints that can be set on the service
// +k8s:deepcopy-gen=true
type Constraints struct {
OperatingSystem *Constraint
Architecture *Constraint
Hostname *Constraint
MatchLabels map[string]Constraint
}
// Constraint defines a constraint and it's operator (== or !=)
// +k8s:deepcopy-gen=true
type Constraint struct {
Value string
Operator string
}
// HealthCheckConfig the healthcheck configuration for a service
// +k8s:deepcopy-gen=true
type HealthCheckConfig struct {
Test []string `json:"test,omitempty"`
Timeout *time.Duration `json:"timeout,omitempty"`
Interval *time.Duration `json:"interval,omitempty"`
Retries *uint64 `json:"retries,omitempty"`
}
// ServiceVolumeConfig are references to a volume used by a service
// +k8s:deepcopy-gen=true
type ServiceVolumeConfig struct {
Type string `json:"type,omitempty"`
Source string `json:"source,omitempty"`
Target string `json:"target,omitempty"`
ReadOnly bool `json:"read_only,omitempty"`
}
// StackPhase is the deployment phase of a stack
type StackPhase string
// These are valid conditions of a stack.
const (
// StackAvailable means the stack is available.
StackAvailable StackPhase = "Available"
// StackProgressing means the deployment is progressing.
StackProgressing StackPhase = "Progressing"
// StackFailure is added in a stack when one of its members fails to be created
// or deleted.
StackFailure StackPhase = "Failure"
// StackReconciliationPending means the stack has not yet been reconciled
StackReconciliationPending StackPhase = "ReconciliationPending"
)
// StackStatus defines the observed state of Stack
type StackStatus struct {
// Current condition of the stack.
// +optional
Phase StackPhase `json:"phase,omitempty" protobuf:"bytes,1,opt,name=phase,casttype=StackPhase"`
// A human readable message indicating details about the stack.
// +optional
Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
}
func (s *StackStatus) clone() *StackStatus {
if s == nil {
return nil
}
result := *s
return &result
}
// Clone clones a Stack
func (s *Stack) Clone() *Stack {
return s.clone()
}