Skip to content
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

Fix Deployment await logic #646

Merged
merged 1 commit into from
Jul 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
(https://github.com/pulumi/pulumi-kubernetes/pull/637).
- Use `opts` instead of `__opts__` and `resource_name` instead of `__name__` in Python SDK
(https://github.com/pulumi/pulumi-kubernetes/pull/639).
- Properly detect failed Deployment on rollout. (https://github.com/pulumi/pulumi-kubernetes/pull/646).
- Use dry-run support if available when diffing the actual and desired state of a resource
(https://github.com/pulumi/pulumi-kubernetes/pull/649)

Expand Down
16 changes: 11 additions & 5 deletions pkg/await/apps_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,10 @@ func (dia *deploymentInitAwaiter) processDeploymentEvent(event watch.Event) {
}

// extensions/v1beta1 does not include the "Progressing" status for rollouts.
progressingStatusUnavailable := dia.deployment.GetAPIVersion() == "extensions/v1beta1"
// Note: We must use the input apiVersion rather than the Deployment watch Event we're processing here, because
// the Progressing status field will not be present if the Deployment was created with the `extensions/v1beta1` API,
// regardless of what the Event apiVersion says.
progressingStatusUnavailable := dia.config.createAwaitConfig.currentInputs.GetAPIVersion() == "extensions/v1beta1"

// Success occurs when the ReplicaSet of the `currentGeneration` is marked as available, and
// when the deployment is available.
Expand Down Expand Up @@ -527,7 +530,10 @@ func (dia *deploymentInitAwaiter) checkReplicaSetStatus() {
var readyReplicasExists bool
// extensions/v1beta1/ReplicaSet does not include the "readyReplicas" status for rollouts,
// so use the Deployment "readyReplicas" status instead.
statusUnavailable := dia.deployment.GetAPIVersion() == "extensions/v1beta1"
// Note: We must use the input apiVersion rather than the Deployment watch Event we're processing here, because
// the Progressing status field will not be present if the Deployment was created with the `extensions/v1beta1` API,
// regardless of what the Event apiVersion says.
statusUnavailable := dia.config.createAwaitConfig.currentInputs.GetAPIVersion() == "extensions/v1beta1"
if statusUnavailable {
rawReadyReplicas, readyReplicasExists = openapi.Pluck(dia.deployment.Object, "status", "readyReplicas")
readyReplicas, _ = rawReadyReplicas.(int64)
Expand All @@ -541,17 +547,17 @@ func (dia *deploymentInitAwaiter) checkReplicaSetStatus() {

if dia.changeTriggeredRollout() {
dia.updatedReplicaSetReady = lastGeneration != dia.currentGeneration && updatedReplicaSetCreated &&
readyReplicasExists && readyReplicas >= int64(specReplicas)
readyReplicasExists && readyReplicas >= specReplicas
} else {
dia.updatedReplicaSetReady = updatedReplicaSetCreated &&
readyReplicasExists && readyReplicas >= int64(specReplicas)
readyReplicasExists && readyReplicas >= specReplicas
}

if !dia.updatedReplicaSetReady {
dia.config.logStatus(
diag.Info,
fmt.Sprintf("[1/2] Waiting for app ReplicaSet be marked available (%d/%d Pods available)",
readyReplicas, int64(specReplicas)))
readyReplicas, specReplicas))
}
}

Expand Down
40 changes: 31 additions & 9 deletions pkg/clients/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"strings"

"github.com/pulumi/pulumi-kubernetes/pkg/kinds"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
Expand Down Expand Up @@ -116,22 +117,43 @@ func (dcs *DynamicClientSet) gvkForKind(kind kinds.Kind) (*schema.GroupVersionKi
}
}

var fallbackResourceList *v1.APIResourceList
for _, gvResources := range resources {
for _, resource := range gvResources.APIResources {
if resource.Kind == string(kind) {
var gv schema.GroupVersion
gv, err = schema.ParseGroupVersion(gvResources.GroupVersion)
if err != nil {
return nil, err
}
return &schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: resource.Kind}, nil
}
// For some reason, the server is returning the old "extensions/v1beta1" GV before "apps/v1", so manually
// skip it and fallback to it if the Kind is not found.
if gvResources.GroupVersion == "extensions/v1beta1" {
fallbackResourceList = gvResources
continue
lblackstone marked this conversation as resolved.
Show resolved Hide resolved
}
versionKind, err, done := dcs.searchKindInGVResources(gvResources, kind)
if done {
return versionKind, err
}
}

versionKind, err, done := dcs.searchKindInGVResources(fallbackResourceList, kind)
if done {
return versionKind, err
}

return nil, fmt.Errorf("failed to find gvk for Kind: %q", kind)
}

func (dcs *DynamicClientSet) searchKindInGVResources(gvResources *v1.APIResourceList, kind kinds.Kind,
) (*schema.GroupVersionKind, error, bool) {
for _, resource := range gvResources.APIResources {
if resource.Kind == string(kind) {
var gv schema.GroupVersion
gv, err := schema.ParseGroupVersion(gvResources.GroupVersion)
if err != nil {
return nil, err, true
}
return &schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: resource.Kind}, nil, true
}
}
return nil, nil, false
}

func (dcs *DynamicClientSet) IsNamespacedKind(gvk schema.GroupVersionKind) (bool, error) {
gv := gvk.GroupVersion().String()
if strings.Contains(gv, "core/v1") {
Expand Down