@@ -19,14 +19,23 @@ import (
1919 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020)
2121
22+ const (
23+ // pullSecretExtraField is an extra field on ServiceConfigs usable to reference a pull secret
24+ pullSecretExtraField = "x-pull-secret"
25+ // pullPolicyExtraField is an extra field on ServiceConfigs usable to specify a pull policy
26+ pullPolicyExtraField = "x-pull-policy"
27+ )
28+
2229// NewStackConverter returns a converter from types.Config (compose) to the specified
2330// stack version or error out if the version is not supported or existent.
2431func NewStackConverter (version string ) (StackConverter , error ) {
2532 switch version {
2633 case "v1beta1" :
2734 return stackV1Beta1Converter {}, nil
28- case "v1beta2" , "v1alpha3" :
29- return stackV1Beta2OrHigherConverter {}, nil
35+ case "v1beta2" :
36+ return stackV1Beta2Converter {}, nil
37+ case "v1alpha3" :
38+ return stackV1Alpha3Converter {}, nil
3039 default :
3140 return nil , errors .Errorf ("stack version %s unsupported" , version )
3241 }
@@ -41,7 +50,7 @@ type stackV1Beta1Converter struct{}
4150
4251func (s stackV1Beta1Converter ) FromCompose (stderr io.Writer , name string , cfg * composetypes.Config ) (Stack , error ) {
4352 cfg .Version = v1beta1 .MaxComposeVersion
44- st , err := fromCompose (stderr , name , cfg )
53+ st , err := fromCompose (stderr , name , cfg , v1beta1Capabilities )
4554 if err != nil {
4655 return Stack {}, err
4756 }
@@ -62,16 +71,26 @@ func (s stackV1Beta1Converter) FromCompose(stderr io.Writer, name string, cfg *c
6271 return st , nil
6372}
6473
65- type stackV1Beta2OrHigherConverter struct {}
74+ type stackV1Beta2Converter struct {}
6675
67- func (s stackV1Beta2OrHigherConverter ) FromCompose (stderr io.Writer , name string , cfg * composetypes.Config ) (Stack , error ) {
68- return fromCompose (stderr , name , cfg )
76+ func (s stackV1Beta2Converter ) FromCompose (stderr io.Writer , name string , cfg * composetypes.Config ) (Stack , error ) {
77+ return fromCompose (stderr , name , cfg , v1beta2Capabilities )
6978}
7079
71- func fromCompose (stderr io.Writer , name string , cfg * composetypes.Config ) (Stack , error ) {
80+ type stackV1Alpha3Converter struct {}
81+
82+ func (s stackV1Alpha3Converter ) FromCompose (stderr io.Writer , name string , cfg * composetypes.Config ) (Stack , error ) {
83+ return fromCompose (stderr , name , cfg , v1alpha3Capabilities )
84+ }
85+
86+ func fromCompose (stderr io.Writer , name string , cfg * composetypes.Config , capabilities composeCapabilities ) (Stack , error ) {
87+ spec , err := fromComposeConfig (stderr , cfg , capabilities )
88+ if err != nil {
89+ return Stack {}, err
90+ }
7291 return Stack {
7392 Name : name ,
74- Spec : fromComposeConfig ( stderr , cfg ) ,
93+ Spec : spec ,
7594 }, nil
7695}
7796
@@ -95,11 +114,15 @@ func stackFromV1beta1(in *v1beta1.Stack) (Stack, error) {
95114 if err != nil {
96115 return Stack {}, err
97116 }
117+ spec , err := fromComposeConfig (ioutil .Discard , cfg , v1beta1Capabilities )
118+ if err != nil {
119+ return Stack {}, err
120+ }
98121 return Stack {
99122 Name : in .ObjectMeta .Name ,
100123 Namespace : in .ObjectMeta .Namespace ,
101124 ComposeFile : in .Spec .ComposeFile ,
102- Spec : fromComposeConfig ( ioutil . Discard , cfg ) ,
125+ Spec : spec ,
103126 }, nil
104127}
105128
@@ -162,20 +185,24 @@ func stackToV1alpha3(s Stack) *latest.Stack {
162185 }
163186}
164187
165- func fromComposeConfig (stderr io.Writer , c * composeTypes.Config ) * latest.StackSpec {
188+ func fromComposeConfig (stderr io.Writer , c * composeTypes.Config , capabilities composeCapabilities ) ( * latest.StackSpec , error ) {
166189 if c == nil {
167- return nil
190+ return nil , nil
168191 }
169192 warnUnsupportedFeatures (stderr , c )
170193 serviceConfigs := make ([]latest.ServiceConfig , len (c .Services ))
171194 for i , s := range c .Services {
172- serviceConfigs [i ] = fromComposeServiceConfig (s )
195+ svc , err := fromComposeServiceConfig (s , capabilities )
196+ if err != nil {
197+ return nil , err
198+ }
199+ serviceConfigs [i ] = svc
173200 }
174201 return & latest.StackSpec {
175202 Services : serviceConfigs ,
176203 Secrets : fromComposeSecrets (c .Secrets ),
177204 Configs : fromComposeConfigs (c .Configs ),
178- }
205+ }, nil
179206}
180207
181208func fromComposeSecrets (s map [string ]composeTypes.SecretConfig ) map [string ]latest.SecretConfig {
@@ -216,15 +243,34 @@ func fromComposeConfigs(s map[string]composeTypes.ConfigObjConfig) map[string]la
216243 return m
217244}
218245
219- func fromComposeServiceConfig (s composeTypes.ServiceConfig ) latest.ServiceConfig {
220- var userID * int64
246+ func fromComposeServiceConfig (s composeTypes.ServiceConfig , capabilities composeCapabilities ) (latest.ServiceConfig , error ) {
247+ var (
248+ userID * int64
249+ pullSecret string
250+ pullPolicy string
251+ err error
252+ )
221253 if s .User != "" {
222254 numerical , err := strconv .Atoi (s .User )
223255 if err == nil {
224256 unixUserID := int64 (numerical )
225257 userID = & unixUserID
226258 }
227259 }
260+ pullSecret , err = resolveServiceExtra (s , pullSecretExtraField )
261+ if err != nil {
262+ return latest.ServiceConfig {}, err
263+ }
264+ pullPolicy , err = resolveServiceExtra (s , pullPolicyExtraField )
265+ if err != nil {
266+ return latest.ServiceConfig {}, err
267+ }
268+ if pullSecret != "" && ! capabilities .hasPullSecrets {
269+ 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 )
270+ }
271+ if pullPolicy != "" && ! capabilities .hasPullPolicies {
272+ 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 )
273+ }
228274 return latest.ServiceConfig {
229275 Name : s .Name ,
230276 CapAdd : s .CapAdd ,
@@ -260,7 +306,20 @@ func fromComposeServiceConfig(s composeTypes.ServiceConfig) latest.ServiceConfig
260306 User : userID ,
261307 Volumes : fromComposeServiceVolumeConfig (s .Volumes ),
262308 WorkingDir : s .WorkingDir ,
309+ PullSecret : pullSecret ,
310+ PullPolicy : pullPolicy ,
311+ }, nil
312+ }
313+
314+ func resolveServiceExtra (s composeTypes.ServiceConfig , field string ) (string , error ) {
315+ if iface , ok := s .Extras [field ]; ok {
316+ value , ok := iface .(string )
317+ if ! ok {
318+ return "" , errors .Errorf ("field %q: value %v type is %T, should be a string" , field , iface , iface )
319+ }
320+ return value , nil
263321 }
322+ return "" , nil
264323}
265324
266325func fromComposePorts (ports []composeTypes.ServicePortConfig ) []latest.ServicePortConfig {
@@ -421,3 +480,23 @@ func fromComposeServiceVolumeConfig(vs []composeTypes.ServiceVolumeConfig) []lat
421480 }
422481 return volumes
423482}
483+
484+ var (
485+ v1beta1Capabilities = composeCapabilities {
486+ apiVersion : "v1beta1" ,
487+ }
488+ v1beta2Capabilities = composeCapabilities {
489+ apiVersion : "v1beta2" ,
490+ }
491+ v1alpha3Capabilities = composeCapabilities {
492+ apiVersion : "v1alpha3" ,
493+ hasPullSecrets : true ,
494+ hasPullPolicies : true ,
495+ }
496+ )
497+
498+ type composeCapabilities struct {
499+ apiVersion string
500+ hasPullSecrets bool
501+ hasPullPolicies bool
502+ }
0 commit comments