mirror of https://github.com/docker/cli.git
Handle version v1alpha3
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
This commit is contained in:
parent
c863dbabf7
commit
2e5981d613
|
@ -103,7 +103,7 @@ func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *KubeCli) composeClient() (*Factory, 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 {
|
func (c *KubeCli) checkHostsMatch() error {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package kubernetes
|
package kubernetes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
kubernetes "github.com/docker/compose-on-kubernetes/api"
|
"github.com/docker/cli/kubernetes"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
kubeclient "k8s.io/client-go/kubernetes"
|
kubeclient "k8s.io/client-go/kubernetes"
|
||||||
|
@ -18,10 +18,11 @@ type Factory struct {
|
||||||
coreClientSet corev1.CoreV1Interface
|
coreClientSet corev1.CoreV1Interface
|
||||||
appsClientSet appsv1beta2.AppsV1beta2Interface
|
appsClientSet appsv1beta2.AppsV1beta2Interface
|
||||||
clientSet *kubeclient.Clientset
|
clientSet *kubeclient.Clientset
|
||||||
|
experimental bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFactory creates a kubernetes client factory
|
// 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)
|
coreClientSet, err := corev1.NewForConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -38,6 +39,7 @@ func NewFactory(namespace string, config *restclient.Config, clientSet *kubeclie
|
||||||
coreClientSet: coreClientSet,
|
coreClientSet: coreClientSet,
|
||||||
appsClientSet: appsClientSet,
|
appsClientSet: appsClientSet,
|
||||||
clientSet: clientSet,
|
clientSet: clientSet,
|
||||||
|
experimental: experimental,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +85,7 @@ func (s *Factory) DaemonSets() typesappsv1beta2.DaemonSetInterface {
|
||||||
|
|
||||||
// Stacks returns a client for Docker's Stack on Kubernetes
|
// Stacks returns a client for Docker's Stack on Kubernetes
|
||||||
func (s *Factory) Stacks(allNamespaces bool) (StackClient, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -97,7 +99,9 @@ func (s *Factory) Stacks(allNamespaces bool) (StackClient, error) {
|
||||||
return newStackV1Beta1(s.config, namespace)
|
return newStackV1Beta1(s.config, namespace)
|
||||||
case kubernetes.StackAPIV1Beta2:
|
case kubernetes.StackAPIV1Beta2:
|
||||||
return newStackV1Beta2(s.config, namespace)
|
return newStackV1Beta2(s.config, namespace)
|
||||||
|
case kubernetes.StackAPIV1Alpha3:
|
||||||
|
return newStackV1Alpha3(s.config, namespace)
|
||||||
default:
|
default:
|
||||||
return nil, errors.Errorf("no supported Stack API version")
|
return nil, errors.Errorf("unsupported stack API version: %q", version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/docker/cli/cli/compose/schema"
|
"github.com/docker/cli/cli/compose/schema"
|
||||||
composeTypes "github.com/docker/cli/cli/compose/types"
|
composeTypes "github.com/docker/cli/cli/compose/types"
|
||||||
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/v1beta1"
|
||||||
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
|
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -24,8 +25,8 @@ func NewStackConverter(version string) (StackConverter, error) {
|
||||||
switch version {
|
switch version {
|
||||||
case "v1beta1":
|
case "v1beta1":
|
||||||
return stackV1Beta1Converter{}, nil
|
return stackV1Beta1Converter{}, nil
|
||||||
case "v1beta2":
|
case "v1beta2", "v1alpha3":
|
||||||
return stackV1Beta2Converter{}, nil
|
return stackV1Beta2OrHigherConverter{}, nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.Errorf("stack version %s unsupported", version)
|
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
|
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)
|
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{
|
return Stack{
|
||||||
Name: in.ObjectMeta.Name,
|
Name: in.ObjectMeta.Name,
|
||||||
Namespace: in.ObjectMeta.Namespace,
|
Namespace: in.ObjectMeta.Namespace,
|
||||||
|
@ -121,8 +153,8 @@ func stackFromV1beta2(in *v1beta2.Stack) Stack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func stackToV1beta2(s Stack) *v1beta2.Stack {
|
func stackToV1alpha3(s Stack) *latest.Stack {
|
||||||
return &v1beta2.Stack{
|
return &latest.Stack{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: s.Name,
|
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 {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
warnUnsupportedFeatures(stderr, c)
|
warnUnsupportedFeatures(stderr, c)
|
||||||
serviceConfigs := make([]v1beta2.ServiceConfig, len(c.Services))
|
serviceConfigs := make([]latest.ServiceConfig, len(c.Services))
|
||||||
for i, s := range c.Services {
|
for i, s := range c.Services {
|
||||||
serviceConfigs[i] = fromComposeServiceConfig(s)
|
serviceConfigs[i] = fromComposeServiceConfig(s)
|
||||||
}
|
}
|
||||||
return &v1beta2.StackSpec{
|
return &latest.StackSpec{
|
||||||
Services: serviceConfigs,
|
Services: serviceConfigs,
|
||||||
Secrets: fromComposeSecrets(c.Secrets),
|
Secrets: fromComposeSecrets(c.Secrets),
|
||||||
Configs: fromComposeConfigs(c.Configs),
|
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 {
|
if s == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
m := map[string]v1beta2.SecretConfig{}
|
m := map[string]latest.SecretConfig{}
|
||||||
for key, value := range s {
|
for key, value := range s {
|
||||||
m[key] = v1beta2.SecretConfig{
|
m[key] = latest.SecretConfig{
|
||||||
Name: value.Name,
|
Name: value.Name,
|
||||||
File: value.File,
|
File: value.File,
|
||||||
External: v1beta2.External{
|
External: latest.External{
|
||||||
Name: value.External.Name,
|
Name: value.External.Name,
|
||||||
External: value.External.External,
|
External: value.External.External,
|
||||||
},
|
},
|
||||||
|
@ -165,16 +197,16 @@ func fromComposeSecrets(s map[string]composeTypes.SecretConfig) map[string]v1bet
|
||||||
return m
|
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 {
|
if s == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
m := map[string]v1beta2.ConfigObjConfig{}
|
m := map[string]latest.ConfigObjConfig{}
|
||||||
for key, value := range s {
|
for key, value := range s {
|
||||||
m[key] = v1beta2.ConfigObjConfig{
|
m[key] = latest.ConfigObjConfig{
|
||||||
Name: value.Name,
|
Name: value.Name,
|
||||||
File: value.File,
|
File: value.File,
|
||||||
External: v1beta2.External{
|
External: latest.External{
|
||||||
Name: value.External.Name,
|
Name: value.External.Name,
|
||||||
External: value.External.External,
|
External: value.External.External,
|
||||||
},
|
},
|
||||||
|
@ -184,7 +216,7 @@ func fromComposeConfigs(s map[string]composeTypes.ConfigObjConfig) map[string]v1
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeServiceConfig(s composeTypes.ServiceConfig) v1beta2.ServiceConfig {
|
func fromComposeServiceConfig(s composeTypes.ServiceConfig) latest.ServiceConfig {
|
||||||
var userID *int64
|
var userID *int64
|
||||||
if s.User != "" {
|
if s.User != "" {
|
||||||
numerical, err := strconv.Atoi(s.User)
|
numerical, err := strconv.Atoi(s.User)
|
||||||
|
@ -193,13 +225,13 @@ func fromComposeServiceConfig(s composeTypes.ServiceConfig) v1beta2.ServiceConfi
|
||||||
userID = &unixUserID
|
userID = &unixUserID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return v1beta2.ServiceConfig{
|
return latest.ServiceConfig{
|
||||||
Name: s.Name,
|
Name: s.Name,
|
||||||
CapAdd: s.CapAdd,
|
CapAdd: s.CapAdd,
|
||||||
CapDrop: s.CapDrop,
|
CapDrop: s.CapDrop,
|
||||||
Command: s.Command,
|
Command: s.Command,
|
||||||
Configs: fromComposeServiceConfigs(s.Configs),
|
Configs: fromComposeServiceConfigs(s.Configs),
|
||||||
Deploy: v1beta2.DeployConfig{
|
Deploy: latest.DeployConfig{
|
||||||
Mode: s.Deploy.Mode,
|
Mode: s.Deploy.Mode,
|
||||||
Replicas: s.Deploy.Replicas,
|
Replicas: s.Deploy.Replicas,
|
||||||
Labels: s.Deploy.Labels,
|
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 {
|
if ports == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
p := make([]v1beta2.ServicePortConfig, len(ports))
|
p := make([]latest.ServicePortConfig, len(ports))
|
||||||
for i, port := range ports {
|
for i, port := range ports {
|
||||||
p[i] = v1beta2.ServicePortConfig{
|
p[i] = latest.ServicePortConfig{
|
||||||
Mode: port.Mode,
|
Mode: port.Mode,
|
||||||
Target: port.Target,
|
Target: port.Target,
|
||||||
Published: port.Published,
|
Published: port.Published,
|
||||||
|
@ -247,13 +279,13 @@ func fromComposePorts(ports []composeTypes.ServicePortConfig) []v1beta2.ServiceP
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeServiceSecrets(secrets []composeTypes.ServiceSecretConfig) []v1beta2.ServiceSecretConfig {
|
func fromComposeServiceSecrets(secrets []composeTypes.ServiceSecretConfig) []latest.ServiceSecretConfig {
|
||||||
if secrets == nil {
|
if secrets == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c := make([]v1beta2.ServiceSecretConfig, len(secrets))
|
c := make([]latest.ServiceSecretConfig, len(secrets))
|
||||||
for i, secret := range secrets {
|
for i, secret := range secrets {
|
||||||
c[i] = v1beta2.ServiceSecretConfig{
|
c[i] = latest.ServiceSecretConfig{
|
||||||
Source: secret.Source,
|
Source: secret.Source,
|
||||||
Target: secret.Target,
|
Target: secret.Target,
|
||||||
UID: secret.UID,
|
UID: secret.UID,
|
||||||
|
@ -263,13 +295,13 @@ func fromComposeServiceSecrets(secrets []composeTypes.ServiceSecretConfig) []v1b
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeServiceConfigs(configs []composeTypes.ServiceConfigObjConfig) []v1beta2.ServiceConfigObjConfig {
|
func fromComposeServiceConfigs(configs []composeTypes.ServiceConfigObjConfig) []latest.ServiceConfigObjConfig {
|
||||||
if configs == nil {
|
if configs == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c := make([]v1beta2.ServiceConfigObjConfig, len(configs))
|
c := make([]latest.ServiceConfigObjConfig, len(configs))
|
||||||
for i, config := range configs {
|
for i, config := range configs {
|
||||||
c[i] = v1beta2.ServiceConfigObjConfig{
|
c[i] = latest.ServiceConfigObjConfig{
|
||||||
Source: config.Source,
|
Source: config.Source,
|
||||||
Target: config.Target,
|
Target: config.Target,
|
||||||
UID: config.UID,
|
UID: config.UID,
|
||||||
|
@ -279,11 +311,11 @@ func fromComposeServiceConfigs(configs []composeTypes.ServiceConfigObjConfig) []
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeHealthcheck(h *composeTypes.HealthCheckConfig) *v1beta2.HealthCheckConfig {
|
func fromComposeHealthcheck(h *composeTypes.HealthCheckConfig) *latest.HealthCheckConfig {
|
||||||
if h == nil {
|
if h == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &v1beta2.HealthCheckConfig{
|
return &latest.HealthCheckConfig{
|
||||||
Test: h.Test,
|
Test: h.Test,
|
||||||
Timeout: composetypes.ConvertDurationPtr(h.Timeout),
|
Timeout: composetypes.ConvertDurationPtr(h.Timeout),
|
||||||
Interval: composetypes.ConvertDurationPtr(h.Interval),
|
Interval: composetypes.ConvertDurationPtr(h.Interval),
|
||||||
|
@ -291,8 +323,8 @@ func fromComposeHealthcheck(h *composeTypes.HealthCheckConfig) *v1beta2.HealthCh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposePlacement(p composeTypes.Placement) v1beta2.Placement {
|
func fromComposePlacement(p composeTypes.Placement) latest.Placement {
|
||||||
return v1beta2.Placement{
|
return latest.Placement{
|
||||||
Constraints: fromComposeConstraints(p.Constraints),
|
Constraints: fromComposeConstraints(p.Constraints),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,18 +338,18 @@ const (
|
||||||
swarmLabelPrefix = "node.labels."
|
swarmLabelPrefix = "node.labels."
|
||||||
)
|
)
|
||||||
|
|
||||||
func fromComposeConstraints(s []string) *v1beta2.Constraints {
|
func fromComposeConstraints(s []string) *latest.Constraints {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
constraints := &v1beta2.Constraints{}
|
constraints := &latest.Constraints{}
|
||||||
for _, constraint := range s {
|
for _, constraint := range s {
|
||||||
matches := constraintEquals.FindStringSubmatch(constraint)
|
matches := constraintEquals.FindStringSubmatch(constraint)
|
||||||
if len(matches) == 4 {
|
if len(matches) == 4 {
|
||||||
key := matches[1]
|
key := matches[1]
|
||||||
operator := matches[2]
|
operator := matches[2]
|
||||||
value := matches[3]
|
value := matches[3]
|
||||||
constraint := &v1beta2.Constraint{
|
constraint := &latest.Constraint{
|
||||||
Operator: operator,
|
Operator: operator,
|
||||||
Value: value,
|
Value: value,
|
||||||
}
|
}
|
||||||
|
@ -330,7 +362,7 @@ func fromComposeConstraints(s []string) *v1beta2.Constraints {
|
||||||
constraints.Hostname = constraint
|
constraints.Hostname = constraint
|
||||||
case strings.HasPrefix(key, swarmLabelPrefix):
|
case strings.HasPrefix(key, swarmLabelPrefix):
|
||||||
if constraints.MatchLabels == nil {
|
if constraints.MatchLabels == nil {
|
||||||
constraints.MatchLabels = map[string]v1beta2.Constraint{}
|
constraints.MatchLabels = map[string]latest.Constraint{}
|
||||||
}
|
}
|
||||||
constraints.MatchLabels[strings.TrimPrefix(key, swarmLabelPrefix)] = *constraint
|
constraints.MatchLabels[strings.TrimPrefix(key, swarmLabelPrefix)] = *constraint
|
||||||
}
|
}
|
||||||
|
@ -339,48 +371,48 @@ func fromComposeConstraints(s []string) *v1beta2.Constraints {
|
||||||
return constraints
|
return constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeResources(r composeTypes.Resources) v1beta2.Resources {
|
func fromComposeResources(r composeTypes.Resources) latest.Resources {
|
||||||
return v1beta2.Resources{
|
return latest.Resources{
|
||||||
Limits: fromComposeResourcesResource(r.Limits),
|
Limits: fromComposeResourcesResource(r.Limits),
|
||||||
Reservations: fromComposeResourcesResource(r.Reservations),
|
Reservations: fromComposeResourcesResource(r.Reservations),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeResourcesResource(r *composeTypes.Resource) *v1beta2.Resource {
|
func fromComposeResourcesResource(r *composeTypes.Resource) *latest.Resource {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &v1beta2.Resource{
|
return &latest.Resource{
|
||||||
MemoryBytes: int64(r.MemoryBytes),
|
MemoryBytes: int64(r.MemoryBytes),
|
||||||
NanoCPUs: r.NanoCPUs,
|
NanoCPUs: r.NanoCPUs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeUpdateConfig(u *composeTypes.UpdateConfig) *v1beta2.UpdateConfig {
|
func fromComposeUpdateConfig(u *composeTypes.UpdateConfig) *latest.UpdateConfig {
|
||||||
if u == nil {
|
if u == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &v1beta2.UpdateConfig{
|
return &latest.UpdateConfig{
|
||||||
Parallelism: u.Parallelism,
|
Parallelism: u.Parallelism,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeRestartPolicy(r *composeTypes.RestartPolicy) *v1beta2.RestartPolicy {
|
func fromComposeRestartPolicy(r *composeTypes.RestartPolicy) *latest.RestartPolicy {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &v1beta2.RestartPolicy{
|
return &latest.RestartPolicy{
|
||||||
Condition: r.Condition,
|
Condition: r.Condition,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromComposeServiceVolumeConfig(vs []composeTypes.ServiceVolumeConfig) []v1beta2.ServiceVolumeConfig {
|
func fromComposeServiceVolumeConfig(vs []composeTypes.ServiceVolumeConfig) []latest.ServiceVolumeConfig {
|
||||||
if vs == nil {
|
if vs == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
volumes := []v1beta2.ServiceVolumeConfig{}
|
volumes := []latest.ServiceVolumeConfig{}
|
||||||
for _, v := range vs {
|
for _, v := range vs {
|
||||||
volumes = append(volumes, v1beta2.ServiceVolumeConfig{
|
volumes = append(volumes, latest.ServiceVolumeConfig{
|
||||||
Type: v.Type,
|
Type: v.Type,
|
||||||
Source: v.Source,
|
Source: v.Source,
|
||||||
Target: v.Target,
|
Target: v.Target,
|
||||||
|
|
|
@ -15,4 +15,6 @@ func TestNewStackConverter(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
_, err = NewStackConverter("v1beta2")
|
_, err = NewStackConverter("v1beta2")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
_, err = NewStackConverter("v1alpha3")
|
||||||
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"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"
|
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"
|
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/v1beta1"
|
||||||
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
|
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
|
@ -31,11 +33,11 @@ configs:
|
||||||
test:
|
test:
|
||||||
file: testdata/config
|
file: testdata/config
|
||||||
`,
|
`,
|
||||||
Spec: &v1beta2.StackSpec{
|
Spec: &v1alpha3.StackSpec{
|
||||||
Configs: map[string]v1beta2.ConfigObjConfig{
|
Configs: map[string]v1alpha3.ConfigObjConfig{
|
||||||
"test": {Name: "test", File: "testdata/config"},
|
"test": {Name: "test", File: "testdata/config"},
|
||||||
},
|
},
|
||||||
Secrets: map[string]v1beta2.SecretConfig{
|
Secrets: map[string]v1alpha3.SecretConfig{
|
||||||
"test": {Name: "test", File: "testdata/secret"},
|
"test": {Name: "test", File: "testdata/secret"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -86,6 +88,24 @@ func TestCreateChildResourcesV1Beta2(t *testing.T) {
|
||||||
checkOwnerReferences(t, s.ObjectMeta, "test", v1beta2.SchemeGroupVersion.String())
|
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) {
|
func TestCreateChildResourcesWithStackCreationErrorV1Beta1(t *testing.T) {
|
||||||
k8sclientSet := fake.NewSimpleClientset()
|
k8sclientSet := fake.NewSimpleClientset()
|
||||||
stack := testStack()
|
stack := testStack()
|
||||||
|
@ -120,6 +140,23 @@ func TestCreateChildResourcesWithStackCreationErrorV1Beta2(t *testing.T) {
|
||||||
assert.Check(t, kerrors.IsNotFound(err))
|
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 {
|
type fakeV1beta1Client struct {
|
||||||
errorOnCreate bool
|
errorOnCreate bool
|
||||||
}
|
}
|
||||||
|
@ -213,3 +250,50 @@ func (c *fakeV1beta2Client) Patch(name string, pt types.PatchType, data []byte,
|
||||||
func (c *fakeV1beta2Client) WithSkipValidation() composev1beta2.StackInterface {
|
func (c *fakeV1beta2Client) WithSkipValidation() composev1beta2.StackInterface {
|
||||||
return c
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"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"
|
"github.com/docker/compose-on-kubernetes/api/labels"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -17,7 +17,7 @@ type Stack struct {
|
||||||
Name string
|
Name string
|
||||||
Namespace string
|
Namespace string
|
||||||
ComposeFile string
|
ComposeFile string
|
||||||
Spec *v1beta2.StackSpec
|
Spec *latest.StackSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
type childResource interface {
|
type childResource interface {
|
||||||
|
|
|
@ -3,8 +3,10 @@ package kubernetes
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"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"
|
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"
|
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/v1beta1"
|
||||||
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
|
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
|
||||||
"github.com/docker/compose-on-kubernetes/api/labels"
|
"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.
|
// stackV1Beta2 implements stackClient interface and talks to compose component v1beta2.
|
||||||
type stackV1Beta2 struct {
|
type stackV1Beta2 struct {
|
||||||
stackV1Beta2Converter
|
stackV1Beta2OrHigherConverter
|
||||||
stacks composev1beta2.StackInterface
|
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 {
|
func (s *stackV1Beta2) CreateOrUpdate(internalStack Stack, childResources []childResource) error {
|
||||||
// If it already exists, update the stack
|
|
||||||
var (
|
var (
|
||||||
stack *v1beta2.Stack
|
stack *v1beta2.Stack
|
||||||
err error
|
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 {
|
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)
|
stack, err = s.stacks.Update(stack)
|
||||||
} else {
|
} else {
|
||||||
// Or create it
|
// Or create it
|
||||||
stack, err = s.stacks.Create(stackToV1beta2(internalStack))
|
stack, err = s.stacks.Create(resolved)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deleteChildResources(childResources)
|
deleteChildResources(childResources)
|
||||||
|
@ -173,7 +179,7 @@ func (s *stackV1Beta2) Get(name string) (Stack, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Stack{}, err
|
return Stack{}, err
|
||||||
}
|
}
|
||||||
return stackFromV1beta2(stackBeta2), nil
|
return stackFromV1beta2(stackBeta2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stackV1Beta2) List(opts metav1.ListOptions) ([]Stack, error) {
|
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))
|
stacks := make([]Stack, len(list.Items))
|
||||||
for i := range 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
|
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 {
|
func (s *stackV1Beta2) IsColliding(servicesClient corev1.ServiceInterface, st Stack) error {
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ import (
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
kubecontext "github.com/docker/cli/cli/context/kubernetes"
|
kubecontext "github.com/docker/cli/cli/context/kubernetes"
|
||||||
|
"github.com/docker/cli/kubernetes"
|
||||||
"github.com/docker/cli/templates"
|
"github.com/docker/cli/templates"
|
||||||
kubernetes "github.com/docker/compose-on-kubernetes/api"
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"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)
|
logrus.Debugf("failed to get Kubernetes client: %s", err)
|
||||||
return &version
|
return &version
|
||||||
}
|
}
|
||||||
version.StackAPI = getStackVersion(kubeClient)
|
version.StackAPI = getStackVersion(kubeClient, dockerCli.ClientInfo().HasExperimental)
|
||||||
version.Kubernetes = getKubernetesServerVersion(kubeClient)
|
version.Kubernetes = getKubernetesServerVersion(kubeClient)
|
||||||
return &version
|
return &version
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStackVersion(client *kubernetesClient.Clientset) string {
|
func getStackVersion(client *kubernetesClient.Clientset, experimental bool) string {
|
||||||
apiVersion, err := kubernetes.GetStackAPIVersion(client)
|
apiVersion, err := kubernetes.GetStackAPIVersion(client, experimental)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("failed to get Stack API version: %s", err)
|
logrus.Debugf("failed to get Stack API version: %s", err)
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
|
|
|
@ -1,20 +1,60 @@
|
||||||
package kubernetes
|
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.
|
// StackVersion represents the detected Compose Component on Kubernetes side.
|
||||||
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.StackVersion instead
|
type StackVersion string
|
||||||
type StackVersion = api.StackVersion
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// StackAPIV1Beta1 is returned if it's the most recent version available.
|
// StackAPIV1Beta1 is returned if it's the most recent version available.
|
||||||
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.StackAPIV1Beta1 instead
|
StackAPIV1Beta1 = StackVersion("v1beta1")
|
||||||
StackAPIV1Beta1 = api.StackAPIV1Beta1
|
|
||||||
// StackAPIV1Beta2 is returned if it's the most recent version available.
|
// StackAPIV1Beta2 is returned if it's the most recent version available.
|
||||||
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.StackAPIV1Beta2 instead
|
StackAPIV1Beta2 = StackVersion("v1beta2")
|
||||||
StackAPIV1Beta2 = api.StackAPIV1Beta2
|
// 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.
|
// GetStackAPIVersion returns the most appropriate stack API version installed.
|
||||||
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.GetStackAPIVersion instead
|
func GetStackAPIVersion(serverGroups discovery.ServerGroupsInterface, experimental bool) (StackVersion, error) {
|
||||||
var GetStackAPIVersion = api.GetStackAPIVersion
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue