detail.go 8.3 KB
Newer Older
1
// Copyright 2017 The Kubernetes Dashboard Authors.
S
Sebastian Florek 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14
//
// 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.

15 16 17 18 19
package deployment

import (
	"log"

20
	"github.com/kubernetes/dashboard/src/app/backend/api"
21
	"github.com/kubernetes/dashboard/src/app/backend/errors"
22
	metricapi "github.com/kubernetes/dashboard/src/app/backend/integration/metric/api"
23
	"github.com/kubernetes/dashboard/src/app/backend/resource/common"
24
	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
25
	"github.com/kubernetes/dashboard/src/app/backend/resource/event"
26
	hpa "github.com/kubernetes/dashboard/src/app/backend/resource/horizontalpodautoscaler"
27
	"github.com/kubernetes/dashboard/src/app/backend/resource/pod"
S
Sebastian Florek 已提交
28
	"github.com/kubernetes/dashboard/src/app/backend/resource/replicaset"
29
	extensions "k8s.io/api/extensions/v1beta1"
M
Marcin Maciaszczyk 已提交
30
	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31
	"k8s.io/apimachinery/pkg/util/intstr"
S
Sebastian Florek 已提交
32
	client "k8s.io/client-go/kubernetes"
33 34
)

B
bryk 已提交
35
// RollingUpdateStrategy is behavior of a rolling update. See RollingUpdateDeployment K8s object.
36
type RollingUpdateStrategy struct {
37 38
	MaxSurge       *intstr.IntOrString `json:"maxSurge"`
	MaxUnavailable *intstr.IntOrString `json:"maxUnavailable"`
39 40
}

41 42
type StatusInfo struct {
	// Total number of desired replicas on the deployment
43
	Replicas int32 `json:"replicas"`
44 45

	// Number of non-terminated pods that have the desired template spec
46
	Updated int32 `json:"updated"`
47 48 49

	// Number of available pods (ready for at least minReadySeconds)
	// targeted by this deployment
50
	Available int32 `json:"available"`
51 52

	// Total number of unavailable pods targeted by this deployment.
53
	Unavailable int32 `json:"unavailable"`
54 55
}

B
bryk 已提交
56
// DeploymentDetail is a presentation layer view of Kubernetes Deployment resource.
57
type DeploymentDetail struct {
58 59
	ObjectMeta api.ObjectMeta `json:"objectMeta"`
	TypeMeta   api.TypeMeta   `json:"typeMeta"`
60

61 62 63
	// Detailed information about Pods belonging to this Deployment.
	PodList pod.PodList `json:"podList"`

64 65 66
	// Label selector of the service.
	Selector map[string]string `json:"selector"`

67
	// Status information on the deployment
68
	StatusInfo `json:"statusInfo"`
69

L
Luiz Felipe G. Pereira 已提交
70 71
	// The deployment strategy to use to replace existing pods with new ones.
	// Valid options: Recreate, RollingUpdate
72
	Strategy extensions.DeploymentStrategyType `json:"strategy"`
73 74

	// Min ready seconds
75
	MinReadySeconds int32 `json:"minReadySeconds"`
76

L
Luiz Felipe G. Pereira 已提交
77
	// Rolling update strategy containing maxSurge and maxUnavailable
78
	RollingUpdateStrategy *RollingUpdateStrategy `json:"rollingUpdateStrategy,omitempty"`
79

L
Luiz Felipe G. Pereira 已提交
80
	// RepliaSetList containing old replica sets from the deployment
M
Marcin Maciaszczyk 已提交
81
	OldReplicaSetList replicaset.ReplicaSetList `json:"oldReplicaSetList"`
82

83
	// New replica set used by this deployment
L
Luiz Felipe G. Pereira 已提交
84
	NewReplicaSet replicaset.ReplicaSet `json:"newReplicaSet"`
85

86 87 88
	// Optional field that specifies the number of old Replica Sets to retain to allow rollback.
	RevisionHistoryLimit *int32 `json:"revisionHistoryLimit"`

89 90
	// List of events related to this Deployment
	EventList common.EventList `json:"eventList"`
91 92

	// List of Horizontal Pod AutoScalers targeting this Deployment
93 94 95 96
	HorizontalPodAutoscalerList hpa.HorizontalPodAutoscalerList `json:"horizontalPodAutoscalerList"`

	// List of non-critical errors, that occurred during resource retrieval.
	Errors []error `json:"errors"`
97 98
}

B
bryk 已提交
99
// GetDeploymentDetail returns model object of deployment and error, if any.
100
func GetDeploymentDetail(client client.Interface, metricClient metricapi.MetricClient, namespace string,
101
	deploymentName string) (*DeploymentDetail, error) {
102

103
	log.Printf("Getting details of %s deployment in %s namespace", deploymentName, namespace)
104

105
	deployment, err := client.ExtensionsV1beta1().Deployments(namespace).Get(deploymentName, metaV1.GetOptions{})
106 107 108 109
	if err != nil {
		return nil, err
	}

S
Sebastian Florek 已提交
110
	selector, err := metaV1.LabelSelectorAsSelector(deployment.Spec.Selector)
111 112 113
	if err != nil {
		return nil, err
	}
S
Sebastian Florek 已提交
114
	options := metaV1.ListOptions{LabelSelector: selector.String()}
115

L
Luiz Felipe G. Pereira 已提交
116
	channels := &common.ResourceChannels{
117
		ReplicaSetList: common.GetReplicaSetListChannelWithOptions(client,
118 119 120
			common.NewSameNamespaceQuery(namespace), options, 1),
		PodList: common.GetPodListChannelWithOptions(client,
			common.NewSameNamespaceQuery(namespace), options, 1),
L
Luiz Felipe G. Pereira 已提交
121 122
	}

123
	rawRs := <-channels.ReplicaSetList.List
124 125 126 127
	err = <-channels.ReplicaSetList.Error
	nonCriticalErrors, criticalError := errors.HandleError(err)
	if criticalError != nil {
		return nil, criticalError
L
Luiz Felipe G. Pereira 已提交
128
	}
129

130
	rawPods := <-channels.PodList.List
131 132 133 134
	err = <-channels.PodList.Error
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return nil, criticalError
L
Luiz Felipe G. Pereira 已提交
135 136
	}

137
	podList, err := GetDeploymentPods(client, metricClient, dataselect.DefaultDataSelectWithMetrics, namespace, deploymentName)
138 139 140
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return nil, criticalError
141
	}
142

M
Marcin Maciaszczyk 已提交
143
	eventList, err := event.GetResourceEvents(client, dataselect.DefaultDataSelect, namespace, deploymentName)
144 145 146
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return nil, criticalError
L
Luiz Felipe G. Pereira 已提交
147
	}
148 149 150 151 152

	hpas, err := hpa.GetHorizontalPodAutoscalerListForResource(client, namespace, "Deployment", deploymentName)
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return nil, criticalError
153
	}
L
Luiz Felipe G. Pereira 已提交
154

155
	oldReplicaSetList, err := GetDeploymentOldReplicaSets(client, dataselect.DefaultDataSelect, namespace, deploymentName)
156 157 158
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return nil, criticalError
L
Luiz Felipe G. Pereira 已提交
159
	}
L
Luiz Felipe G. Pereira 已提交
160

R
Rob Franken 已提交
161 162 163 164
	rawRepSets := make([]*extensions.ReplicaSet, 0)
	for i := range rawRs.Items {
		rawRepSets = append(rawRepSets, &rawRs.Items[i])
	}
M
Marcin Maciaszczyk 已提交
165
	newRs, err := FindNewReplicaSet(deployment, rawRepSets)
166 167 168
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return nil, criticalError
169
	}
170

171 172
	var newReplicaSet replicaset.ReplicaSet
	if newRs != nil {
173
		matchingPods := common.FilterPodsByControllerRef(newRs, rawPods.Items)
174
		newRsPodInfo := common.GetPodInfo(newRs.Status.Replicas, newRs.Spec.Replicas, matchingPods)
175
		events, err := event.GetPodsEvents(client, namespace, matchingPods)
176 177 178
		nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
		if criticalError != nil {
			return nil, criticalError
179 180
		}

181
		newRsPodInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods)
182 183
		newReplicaSet = replicaset.ToReplicaSet(newRs, &newRsPodInfo)
	}
L
Luiz Felipe G. Pereira 已提交
184

185
	// Extra Info
186 187 188
	var rollingUpdateStrategy *RollingUpdateStrategy
	if deployment.Spec.Strategy.RollingUpdate != nil {
		rollingUpdateStrategy = &RollingUpdateStrategy{
189 190
			MaxSurge:       deployment.Spec.Strategy.RollingUpdate.MaxSurge,
			MaxUnavailable: deployment.Spec.Strategy.RollingUpdate.MaxUnavailable,
191 192 193 194
		}
	}

	return &DeploymentDetail{
195 196
		ObjectMeta:                  api.NewObjectMeta(deployment.ObjectMeta),
		TypeMeta:                    api.NewTypeMeta(api.ResourceKindDeployment),
197 198 199 200 201 202 203 204 205 206 207
		PodList:                     *podList,
		Selector:                    deployment.Spec.Selector.MatchLabels,
		StatusInfo:                  GetStatusInfo(&deployment.Status),
		Strategy:                    deployment.Spec.Strategy.Type,
		MinReadySeconds:             deployment.Spec.MinReadySeconds,
		RollingUpdateStrategy:       rollingUpdateStrategy,
		OldReplicaSetList:           *oldReplicaSetList,
		NewReplicaSet:               newReplicaSet,
		RevisionHistoryLimit:        deployment.Spec.RevisionHistoryLimit,
		EventList:                   *eventList,
		HorizontalPodAutoscalerList: *hpas,
208
		Errors: nonCriticalErrors,
209 210
	}, nil

L
Luiz Felipe G. Pereira 已提交
211 212
}

213 214 215 216 217 218 219 220
func GetStatusInfo(deploymentStatus *extensions.DeploymentStatus) StatusInfo {
	return StatusInfo{
		Replicas:    deploymentStatus.Replicas,
		Updated:     deploymentStatus.UpdatedReplicas,
		Available:   deploymentStatus.AvailableReplicas,
		Unavailable: deploymentStatus.UnavailableReplicas,
	}
}