Merge pull request #1823 from simonferquel/refactor-kubernetes-extras

Regroup all kubernetes extra-fields under x-kubernetes
This commit is contained in:
Sebastiaan van Stijn 2019-04-14 22:59:41 +02:00 committed by GitHub
commit d043ab5993
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 65 deletions

View File

@ -15,6 +15,7 @@ import (
"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/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors" "github.com/pkg/errors"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
@ -22,12 +23,8 @@ import (
) )
const ( const (
// pullSecretExtraField is an extra field on ServiceConfigs usable to reference a pull secret // kubernatesExtraField is an extra field on ServiceConfigs containing kubernetes-specific extensions to compose format
pullSecretExtraField = "x-pull-secret" kubernatesExtraField = "x-kubernetes"
// pullPolicyExtraField is an extra field on ServiceConfigs usable to specify a pull policy
pullPolicyExtraField = "x-pull-policy"
// internalServiceTypeExtraField is an extra field on ServiceConfigs to explicitly specify the kind of service to setup for intra-stack networking
internalServiceTypeExtraField = "x-internal-service-type"
) )
// NewStackConverter returns a converter from types.Config (compose) to the specified // NewStackConverter returns a converter from types.Config (compose) to the specified
@ -249,10 +246,8 @@ func fromComposeConfigs(s map[string]composeTypes.ConfigObjConfig) map[string]la
func fromComposeServiceConfig(s composeTypes.ServiceConfig, capabilities composeCapabilities) (latest.ServiceConfig, error) { func fromComposeServiceConfig(s composeTypes.ServiceConfig, capabilities composeCapabilities) (latest.ServiceConfig, error) {
var ( var (
userID *int64 userID *int64
pullSecret string err error
pullPolicy string
err error
) )
if s.User != "" { if s.User != "" {
numerical, err := strconv.Atoi(s.User) numerical, err := strconv.Atoi(s.User)
@ -261,23 +256,18 @@ func fromComposeServiceConfig(s composeTypes.ServiceConfig, capabilities compose
userID = &unixUserID userID = &unixUserID
} }
} }
pullSecret, err = resolveServiceExtra(s, pullSecretExtraField) kubeExtra, err := resolveServiceExtra(s)
if err != nil { if err != nil {
return latest.ServiceConfig{}, err return latest.ServiceConfig{}, err
} }
pullPolicy, err = resolveServiceExtra(s, pullPolicyExtraField) if kubeExtra.PullSecret != "" && !capabilities.hasPullSecrets {
if err != nil { return latest.ServiceConfig{}, errors.Errorf(`stack API version %s does not support pull secrets (field "x-kubernetes.pull_secret"), please use version v1alpha3 or higher`, capabilities.apiVersion)
return latest.ServiceConfig{}, err }
if kubeExtra.PullPolicy != "" && !capabilities.hasPullPolicies {
return latest.ServiceConfig{}, errors.Errorf(`stack API version %s does not support pull policies (field "x-kubernetes.pull_policy"), please use version v1alpha3 or higher`, capabilities.apiVersion)
} }
if pullSecret != "" && !capabilities.hasPullSecrets { internalPorts, err := setupIntraStackNetworking(s, kubeExtra, capabilities)
return latest.ServiceConfig{}, errors.Errorf("stack API version %s does not support pull secrets (field %q), please use version v1alpha3 or higher", capabilities.apiVersion, pullSecretExtraField)
}
if pullPolicy != "" && !capabilities.hasPullPolicies {
return latest.ServiceConfig{}, errors.Errorf("stack API version %s does not support pull policies (field %q), please use version v1alpha3 or higher", capabilities.apiVersion, pullPolicyExtraField)
}
internalServiceType, internalPorts, err := setupIntraStackNetworking(s, capabilities)
if err != nil { if err != nil {
return latest.ServiceConfig{}, err return latest.ServiceConfig{}, err
} }
@ -317,48 +307,41 @@ func fromComposeServiceConfig(s composeTypes.ServiceConfig, capabilities compose
User: userID, User: userID,
Volumes: fromComposeServiceVolumeConfig(s.Volumes), Volumes: fromComposeServiceVolumeConfig(s.Volumes),
WorkingDir: s.WorkingDir, WorkingDir: s.WorkingDir,
PullSecret: pullSecret, PullSecret: kubeExtra.PullSecret,
PullPolicy: pullPolicy, PullPolicy: kubeExtra.PullPolicy,
InternalServiceType: internalServiceType, InternalServiceType: kubeExtra.InternalServiceType,
InternalPorts: internalPorts, InternalPorts: internalPorts,
}, nil }, nil
} }
func setupIntraStackNetworking(s composeTypes.ServiceConfig, capabilities composeCapabilities) (latest.InternalServiceType, []latest.InternalPort, error) { func setupIntraStackNetworking(s composeTypes.ServiceConfig, kubeExtra kubernetesExtra, capabilities composeCapabilities) ([]latest.InternalPort, error) {
internalServiceTypeRaw, err := resolveServiceExtra(s, internalServiceTypeExtraField) if kubeExtra.InternalServiceType != latest.InternalServiceTypeAuto && !capabilities.hasIntraStackLoadBalancing {
if err != nil { return nil,
return latest.InternalServiceTypeAuto, nil, err errors.Errorf(`stack API version %s does not support intra-stack load balancing (field "x-kubernetes.internal_service_type"), please use version v1alpha3 or higher`,
} capabilities.apiVersion)
if internalServiceTypeRaw != "" && !capabilities.hasIntraStackLoadBalancing {
return latest.InternalServiceTypeAuto, nil,
errors.Errorf("stack API version %s does not support intra-stack load balancing (field %q), please use version v1alpha3 or higher", capabilities.apiVersion, internalServiceTypeExtraField)
} }
if !capabilities.hasIntraStackLoadBalancing { if !capabilities.hasIntraStackLoadBalancing {
return latest.InternalServiceTypeAuto, nil, nil return nil, nil
} }
internalServiceType, err := validateInternalServiceType(internalServiceTypeRaw) if err := validateInternalServiceType(kubeExtra.InternalServiceType); err != nil {
if err != nil { return nil, err
return latest.InternalServiceTypeAuto, nil, err
} }
internalPorts, err := toInternalPorts(s.Expose) internalPorts, err := toInternalPorts(s.Expose)
if err != nil { if err != nil {
return latest.InternalServiceTypeAuto, nil, err return nil, err
} }
return internalServiceType, internalPorts, nil return internalPorts, nil
} }
func validateInternalServiceType(raw string) (latest.InternalServiceType, error) { func validateInternalServiceType(internalServiceType latest.InternalServiceType) error {
internalServiceType := latest.InternalServiceType(raw)
switch internalServiceType { switch internalServiceType {
case latest.InternalServiceTypeAuto, latest.InternalServiceTypeClusterIP, latest.InternalServiceTypeHeadless: case latest.InternalServiceTypeAuto, latest.InternalServiceTypeClusterIP, latest.InternalServiceTypeHeadless:
default: default:
return latest.InternalServiceTypeAuto, return errors.Errorf(`invalid value %q for field "x-kubernetes.internal_service_type", valid values are %q or %q`, internalServiceType,
errors.Errorf("invalid value %q for field %q, valid values are %q or %q", raw, latest.InternalServiceTypeClusterIP,
internalServiceTypeExtraField, latest.InternalServiceTypeHeadless)
latest.InternalServiceTypeClusterIP,
latest.InternalServiceTypeHeadless)
} }
return internalServiceType, nil return nil
} }
func toInternalPorts(expose []string) ([]latest.InternalPort, error) { func toInternalPorts(expose []string) ([]latest.InternalPort, error) {
@ -385,15 +368,15 @@ func toInternalPorts(expose []string) ([]latest.InternalPort, error) {
return internalPorts, nil return internalPorts, nil
} }
func resolveServiceExtra(s composeTypes.ServiceConfig, field string) (string, error) { func resolveServiceExtra(s composeTypes.ServiceConfig) (kubernetesExtra, error) {
if iface, ok := s.Extras[field]; ok { if iface, ok := s.Extras[kubernatesExtraField]; ok {
value, ok := iface.(string) var result kubernetesExtra
if !ok { if err := mapstructure.Decode(iface, &result); err != nil {
return "", errors.Errorf("field %q: value %v type is %T, should be a string", field, iface, iface) return kubernetesExtra{}, err
} }
return value, nil return result, nil
} }
return "", nil return kubernetesExtra{}, nil
} }
func fromComposePorts(ports []composeTypes.ServicePortConfig) []latest.ServicePortConfig { func fromComposePorts(ports []composeTypes.ServicePortConfig) []latest.ServicePortConfig {
@ -576,3 +559,9 @@ type composeCapabilities struct {
hasPullPolicies bool hasPullPolicies bool
hasIntraStackLoadBalancing bool hasIntraStackLoadBalancing bool
} }
type kubernetesExtra struct {
PullSecret string `mapstructure:"pull_secret"`
PullPolicy string `mapstructure:"pull_policy"`
InternalServiceType latest.InternalServiceType `mapstructure:"internal_service_type"`
}

View File

@ -13,7 +13,7 @@ import (
"github.com/docker/compose-on-kubernetes/api/compose/v1beta2" "github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
"gotest.tools/assert" "gotest.tools/assert"
is "gotest.tools/assert/cmp" is "gotest.tools/assert/cmp"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
@ -189,8 +189,8 @@ func TestHandlePullSecret(t *testing.T) {
version string version string
err string err string
}{ }{
{version: "v1beta1", err: `stack API version v1beta1 does not support pull secrets (field "x-pull-secret"), please use version v1alpha3 or higher`}, {version: "v1beta1", err: `stack API version v1beta1 does not support pull secrets (field "x-kubernetes.pull_secret"), please use version v1alpha3 or higher`},
{version: "v1beta2", err: `stack API version v1beta2 does not support pull secrets (field "x-pull-secret"), please use version v1alpha3 or higher`}, {version: "v1beta2", err: `stack API version v1beta2 does not support pull secrets (field "x-kubernetes.pull_secret"), please use version v1alpha3 or higher`},
{version: "v1alpha3"}, {version: "v1alpha3"},
} }
@ -216,8 +216,8 @@ func TestHandlePullPolicy(t *testing.T) {
version string version string
err string err string
}{ }{
{version: "v1beta1", err: `stack API version v1beta1 does not support pull policies (field "x-pull-policy"), please use version v1alpha3 or higher`}, {version: "v1beta1", err: `stack API version v1beta1 does not support pull policies (field "x-kubernetes.pull_policy"), please use version v1alpha3 or higher`},
{version: "v1beta2", err: `stack API version v1beta2 does not support pull policies (field "x-pull-policy"), please use version v1alpha3 or higher`}, {version: "v1beta2", err: `stack API version v1beta2 does not support pull policies (field "x-kubernetes.pull_policy"), please use version v1alpha3 or higher`},
{version: "v1alpha3"}, {version: "v1alpha3"},
} }
@ -249,13 +249,13 @@ func TestHandleInternalServiceType(t *testing.T) {
name: "v1beta1", name: "v1beta1",
value: "ClusterIP", value: "ClusterIP",
caps: v1beta1Capabilities, caps: v1beta1Capabilities,
err: `stack API version v1beta1 does not support intra-stack load balancing (field "x-internal-service-type"), please use version v1alpha3 or higher`, err: `stack API version v1beta1 does not support intra-stack load balancing (field "x-kubernetes.internal_service_type"), please use version v1alpha3 or higher`,
}, },
{ {
name: "v1beta2", name: "v1beta2",
value: "ClusterIP", value: "ClusterIP",
caps: v1beta2Capabilities, caps: v1beta2Capabilities,
err: `stack API version v1beta2 does not support intra-stack load balancing (field "x-internal-service-type"), please use version v1alpha3 or higher`, err: `stack API version v1beta2 does not support intra-stack load balancing (field "x-kubernetes.internal_service_type"), please use version v1alpha3 or higher`,
}, },
{ {
name: "v1alpha3", name: "v1alpha3",
@ -267,7 +267,7 @@ func TestHandleInternalServiceType(t *testing.T) {
name: "v1alpha3-invalid", name: "v1alpha3-invalid",
value: "invalid", value: "invalid",
caps: v1alpha3Capabilities, caps: v1alpha3Capabilities,
err: `invalid value "invalid" for field "x-internal-service-type", valid values are "ClusterIP" or "Headless"`, err: `invalid value "invalid" for field "x-kubernetes.internal_service_type", valid values are "ClusterIP" or "Headless"`,
}, },
} }
for _, c := range cases { for _, c := range cases {
@ -276,7 +276,9 @@ func TestHandleInternalServiceType(t *testing.T) {
Name: "test", Name: "test",
Image: "test", Image: "test",
Extras: map[string]interface{}{ Extras: map[string]interface{}{
internalServiceTypeExtraField: c.value, "x-kubernetes": map[string]interface{}{
"internal_service_type": c.value,
},
}, },
}, c.caps) }, c.caps)
if c.err == "" { if c.err == "" {

View File

@ -2,4 +2,5 @@ version: "3.7"
services: services:
test: test:
image: "some-image" image: "some-image"
x-pull-policy: "Never" x-kubernetes:
pull_policy: "Never"

View File

@ -2,4 +2,5 @@ version: "3.7"
services: services:
test: test:
image: "some-private-image" image: "some-private-image"
x-pull-secret: "some-secret" x-kubernetes:
pull_secret: "some-secret"