// Copyright 2017 The Kubernetes Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package deployment import ( "log" "github.com/kubernetes/dashboard/src/app/backend/errors" "github.com/kubernetes/dashboard/src/app/backend/resource/common" apps "k8s.io/api/apps/v1" metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" client "k8s.io/client-go/kubernetes" ) // RollingUpdateStrategy is behavior of a rolling update. See RollingUpdateDeployment K8s object. type RollingUpdateStrategy struct { MaxSurge *intstr.IntOrString `json:"maxSurge"` MaxUnavailable *intstr.IntOrString `json:"maxUnavailable"` } type StatusInfo struct { // Total number of desired replicas on the deployment Replicas int32 `json:"replicas"` // Number of non-terminated pods that have the desired template spec Updated int32 `json:"updated"` // Number of available pods (ready for at least minReadySeconds) // targeted by this deployment Available int32 `json:"available"` // Total number of unavailable pods targeted by this deployment. Unavailable int32 `json:"unavailable"` } // DeploymentDetail is a presentation layer view of Kubernetes Deployment resource. type DeploymentDetail struct { // Extends list item structure. Deployment `json:",inline"` // Label selector of the service. Selector map[string]string `json:"selector"` // Status information on the deployment StatusInfo `json:"statusInfo"` // Conditions describe the state of a deployment at a certain point. Conditions []common.Condition `json:"conditions"` // The deployment strategy to use to replace existing pods with new ones. // Valid options: Recreate, RollingUpdate Strategy apps.DeploymentStrategyType `json:"strategy"` // Min ready seconds MinReadySeconds int32 `json:"minReadySeconds"` // Rolling update strategy containing maxSurge and maxUnavailable RollingUpdateStrategy *RollingUpdateStrategy `json:"rollingUpdateStrategy,omitempty"` // Optional field that specifies the number of old Replica Sets to retain to allow rollback. RevisionHistoryLimit *int32 `json:"revisionHistoryLimit"` // List of non-critical errors, that occurred during resource retrieval. Errors []error `json:"errors"` } // GetDeploymentDetail returns model object of deployment and error, if any. func GetDeploymentDetail(client client.Interface, namespace string, deploymentName string) (*DeploymentDetail, error) { log.Printf("Getting details of %s deployment in %s namespace", deploymentName, namespace) deployment, err := client.AppsV1().Deployments(namespace).Get(deploymentName, metaV1.GetOptions{}) if err != nil { return nil, err } selector, err := metaV1.LabelSelectorAsSelector(deployment.Spec.Selector) if err != nil { return nil, err } options := metaV1.ListOptions{LabelSelector: selector.String()} channels := &common.ResourceChannels{ ReplicaSetList: common.GetReplicaSetListChannelWithOptions(client, common.NewSameNamespaceQuery(namespace), options, 1), PodList: common.GetPodListChannelWithOptions(client, common.NewSameNamespaceQuery(namespace), options, 1), EventList: common.GetEventListChannelWithOptions(client, common.NewSameNamespaceQuery(namespace), options, 1), } rawRs := <-channels.ReplicaSetList.List err = <-channels.ReplicaSetList.Error nonCriticalErrors, criticalError := errors.HandleError(err) if criticalError != nil { return nil, criticalError } rawPods := <-channels.PodList.List err = <-channels.PodList.Error nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors) if criticalError != nil { return nil, criticalError } rawEvents := <-channels.EventList.List err = <-channels.EventList.Error nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors) if criticalError != nil { return nil, criticalError } // Extra Info var rollingUpdateStrategy *RollingUpdateStrategy if deployment.Spec.Strategy.RollingUpdate != nil { rollingUpdateStrategy = &RollingUpdateStrategy{ MaxSurge: deployment.Spec.Strategy.RollingUpdate.MaxSurge, MaxUnavailable: deployment.Spec.Strategy.RollingUpdate.MaxUnavailable, } } return &DeploymentDetail{ Deployment: toDeployment(deployment, rawRs.Items, rawPods.Items, rawEvents.Items), Selector: deployment.Spec.Selector.MatchLabels, StatusInfo: GetStatusInfo(&deployment.Status), Conditions: getConditions(deployment.Status.Conditions), Strategy: deployment.Spec.Strategy.Type, MinReadySeconds: deployment.Spec.MinReadySeconds, RollingUpdateStrategy: rollingUpdateStrategy, RevisionHistoryLimit: deployment.Spec.RevisionHistoryLimit, Errors: nonCriticalErrors, }, nil } func GetStatusInfo(deploymentStatus *apps.DeploymentStatus) StatusInfo { return StatusInfo{ Replicas: deploymentStatus.Replicas, Updated: deploymentStatus.UpdatedReplicas, Available: deploymentStatus.AvailableReplicas, Unavailable: deploymentStatus.UnavailableReplicas, } }