-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle multiple stack api versions #899
Handle multiple stack api versions #899
Conversation
Codecov Report
@@ Coverage Diff @@
## master #899 +/- ##
=========================================
Coverage ? 53.51%
=========================================
Files ? 266
Lines ? 16891
Branches ? 0
=========================================
Hits ? 9040
Misses ? 7248
Partials ? 603 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I think we can clean more code. There is quite a few code in the
kubernetes
api package that are dead code (in terms of client's code) — like all theClone
functions,Discovery
, etc.. - We should re-enable linters of
kubernetes
package(s) - I wonder what is bringing
golang-lru
and the other new vendoring code 🤔
|
||
fileName := path.Base(config.File) | ||
content, err := ioutil.ReadFile(config.File) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Do we want to group errors ?
- If a file can't read (but not the first one), a configMap will be created in k8s and not used (orphan) — and will probably cause errors next time we do the
docker stack deploy
, right ?
I think we should "read all", and if there is no error, "create all". Then, if one of the creation fails, what should we do with the previous one created ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I'll fix that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose to fix this in a follow-up, as we may remove all configmaps and secrets if any error occurs, even while deploying the stack.
|
||
fileName := path.Base(secret.File) | ||
content, err := ioutil.ReadFile(secret.File) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll fix that too.
stacks composev1beta2.StackInterface | ||
} | ||
|
||
func (c *KubeCli) newStackV1Beta2() (stackClient, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather have func newStackV1Beta2(config *rest.Config, namespace string) …
here (not tying it up with KubeCli
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, fixed
stacks composev1beta1.StackInterface | ||
} | ||
|
||
func (c *KubeCli) newStackV1Beta1() (stackClient, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather have func newStackV1Beta1(config *rest.Config, namespace string) …
here (not tying it up with KubeCli
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, fixed
kubernetes/README.md
Outdated
@@ -1,4 +0,0 @@ | |||
# Kubernetes client libraries |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we keep the README ? 👼
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure!
glog "github.com/golang/glog" | ||
discovery "k8s.io/client-go/discovery" | ||
rest "k8s.io/client-go/rest" | ||
flowcontrol "k8s.io/client-go/util/flowcontrol" | ||
) | ||
|
||
// Interface defines the methods a compose kube client should have | ||
// FIXME(vdemeester) is it required ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah 😅 I need to find the answer for it 😛
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please 😄
// Deprecated: Compose retrieves the default version of ComposeClient. | ||
// Please explicitly pick a version. | ||
// Compose retrieves the default version of ComposeClient. | ||
// deprecated: please explicitly pick a version. | ||
func (c *Clientset) Compose() composev1beta1.ComposeV1beta1Interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum even if it's deprecated, should we return ComposeV1beta2Client
here instead 👼
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or I may remove it...
38df84c
to
96b7779
Compare
96b7779
to
b26d649
Compare
looks like this needs a rebase |
b26d649
to
eb91268
Compare
Done @thaJeztah |
@silvin-lubecki @vdemeester what's the status on this one? I think there's some outstanding review comments, but perhaps I looked wrong 😅 |
eb91268
to
e89100b
Compare
I think I addressed all @vdemeester comments, but I'd be pleased to hear your comments @thaJeztah 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🐸
) | ||
|
||
// LoadStack loads a stack from a Compose config, with a given name. | ||
func LoadStack(name string, cfg composetypes.Config) (*apiv1beta1.Stack, error) { | ||
func loadStack(name string, cfg composetypes.Config) (stack, error) { | ||
res, err := yaml.Marshal(cfg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we only need to do that in v1beta1
case right ? We shouldn't even "try" to do it all the time.
@vdemeester PTAL |
@@ -100,6 +103,18 @@ func verify(services corev1.ServiceInterface, stackName string, service string) | |||
return nil | |||
} | |||
|
|||
func (s *stackV1Beta1) LoadStack(name string, cfg composetypes.Config) (stack, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: not sure if LoadStack
is the correct name for those too 👼
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PTAL
48bf2ad
to
92ba690
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🦁
@thaJeztah PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left some comments and questions
} | ||
|
||
func fromComposeServiceConfig(s composeTypes.ServiceConfig) v1beta2.ServiceConfig { | ||
var userID *int64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we use an int
elsewhere (uids are 32-bit max IIRC (https://serverfault.com/a/585435))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This userID is used in the compose controller as a Kubernetes SecurityContext.RunAsUser (https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/api/core/v1/types.go#L4889) which is an *int64. And by the way the user is declared as a string in the Compose ServiceConfig type.
numerical, err := strconv.Atoi(s.User) | ||
if err == nil { | ||
unixUserID := int64(numerical) | ||
userID = &unixUserID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a nice (clean) approach as well;
cli/cli/compose/convert/service.go
Lines 384 to 386 in 236a847
func uint32Ptr(value uint32) *uint32 { | |
return &value | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, fixed!
return c | ||
} | ||
|
||
func fromComposeHealthcheck(h *composeTypes.HealthCheckConfig) *v1beta2.HealthCheckConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was comparing these to their "swarm mode" counterparts, and wondering if we need validation/error-handling for these conversions (could be a follow-up), e.g. comparing to
cli/cli/compose/convert/service.go
Lines 401 to 437 in 236a847
func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container.HealthConfig, error) { | |
if healthcheck == nil { | |
return nil, nil | |
} | |
var ( | |
timeout, interval, startPeriod time.Duration | |
retries int | |
) | |
if healthcheck.Disable { | |
if len(healthcheck.Test) != 0 { | |
return nil, errors.Errorf("test and disable can't be set at the same time") | |
} | |
return &container.HealthConfig{ | |
Test: []string{"NONE"}, | |
}, nil | |
} | |
if healthcheck.Timeout != nil { | |
timeout = *healthcheck.Timeout | |
} | |
if healthcheck.Interval != nil { | |
interval = *healthcheck.Interval | |
} | |
if healthcheck.StartPeriod != nil { | |
startPeriod = *healthcheck.StartPeriod | |
} | |
if healthcheck.Retries != nil { | |
retries = int(*healthcheck.Retries) | |
} | |
return &container.HealthConfig{ | |
Test: healthcheck.Test, | |
Timeout: timeout, | |
Interval: interval, | |
Retries: retries, | |
StartPeriod: startPeriod, | |
}, nil | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I add it, as it is an error and not a warning (which are in the next PR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a second thought, the Disable flag is just not used on Kubernetes compose controller, see https://github.com/docker/cli/pull/899/files#diff-9f8dfaca00498f5f3543480c12fec02aR198 , so I don't know if we really need to error on this...
func (s *stack) createFileBasedSecrets(secrets corev1.SecretInterface) error { | ||
for name, secret := range s.spec.Secrets { | ||
if secret.File == "" { | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to print a warning in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps also if other options (permissions/ownership) is set?
(oh, just realise thats probably on the service, not on creation of the secret)
return err | ||
} | ||
|
||
if _, err := secrets.Create(toSecret(s.name, name, fileName, content)); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as for "config": what happens if a secret already exists?
Namespace(c.ns). | ||
Resource("stacks"). | ||
Name(stack.Name). | ||
Body(stack). | ||
Do(). | ||
Into(result) | ||
return | ||
return result, err | ||
} | ||
|
||
// UpdateStatus was generated because the type contains a Status member. | ||
// Add a +genclientstatus=false comment above the type to avoid generating UpdateStatus(). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like UpdateStatus()
isn't used? should we remove this? (same for the other API version)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same answer 😄
@@ -1,11 +1,10 @@ | |||
// Package v1beta1 holds the v1beta1 versions of our stack structures. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, why was the Package description move further down? The first line is what will be documented as package description
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't really know, I'll revert it.
@@ -0,0 +1 @@ | |||
package v1beta1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is here to get representable coverage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep exactly.
// backward compatibility by support multiple concurrent versions | ||
// of the same resource | ||
|
||
// Package v1beta2 is the second version of the stack, containing a structured spec |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question here for positioning of the Package description (should likely be the first line in this file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -83,3 +83,4 @@ k8s.io/client-go kubernetes-1.8.2 | |||
k8s.io/kubernetes v1.8.2 | |||
k8s.io/kube-openapi 61b46af70dfed79c6d24530cd23b41440a7f22a5 | |||
vbom.ml/util 928aaa586d7718c70f4090ddf83f2b34c16fdc8d | |||
github.com/hashicorp/golang-lru 0a025b7e63adc15a622f29b0b2c4c3848243bbf6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: please add a newline
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
92ba690
to
ece1de4
Compare
PTAL @thaJeztah |
LGTM ping @thaJeztah |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like there's a linting failure;
Successfully built 4fd3db512de8
Successfully tagged cli-linter:11601
kubernetes/compose/v1beta1/doc.go:7:1:warning: package comment should be of the form "Package v1beta1 ..." (golint)
Exited with code 1
but looks good otherwise
ece1de4
to
dc3d8d7
Compare
Linter should be happy now, thanks @thaJeztah ! |
…s and use it in kubernetes stack commands * Add kubernetes Stack API v1beta2 client * Upgrade v1beta1 client to remove generated code Signed-off-by: Silvin Lubecki <[email protected]>
dc3d8d7
to
f958c66
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
- What I did
I integrated the new version of the Stack API (v1beta2). The CLI can now communicates with both versions.
- How I did it
I added a common interface between v1beta1 and v1beta2 stack clients and one common object stack, so the code in the commands remains the same.
- How to verify it
Execute a
docker version
command against latestdocker for mac
, it should output at the end:- Description for the changelog
- A picture of a cute animal (not mandatory but encouraged)