1/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package types
18
19import (
20	"fmt"
21
22	v1 "k8s.io/api/core/v1"
23	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24	"k8s.io/kubernetes/pkg/apis/scheduling"
25)
26
27// Annotation keys for annotations used in this package.
28const (
29	ConfigSourceAnnotationKey    = "kubernetes.io/config.source"
30	ConfigMirrorAnnotationKey    = v1.MirrorPodAnnotationKey
31	ConfigFirstSeenAnnotationKey = "kubernetes.io/config.seen"
32	ConfigHashAnnotationKey      = "kubernetes.io/config.hash"
33)
34
35// PodOperation defines what changes will be made on a pod configuration.
36type PodOperation int
37
38// These constants identify the PodOperations that can be made on a pod configuration.
39const (
40	// SET is the current pod configuration.
41	SET PodOperation = iota
42	// ADD signifies pods that are new to this source.
43	ADD
44	// DELETE signifies pods that are gracefully deleted from this source.
45	DELETE
46	// REMOVE signifies pods that have been removed from this source.
47	REMOVE
48	// UPDATE signifies pods have been updated in this source.
49	UPDATE
50	// RECONCILE signifies pods that have unexpected status in this source,
51	// kubelet should reconcile status with this source.
52	RECONCILE
53)
54
55// These constants identify the sources of pods.
56const (
57	// Filesource idenitified updates from a file.
58	FileSource = "file"
59	// HTTPSource identifies updates from querying a web page.
60	HTTPSource = "http"
61	// ApiserverSource identifies updates from Kubernetes API Server.
62	ApiserverSource = "api"
63	// AllSource identifies updates from all sources.
64	AllSource = "*"
65)
66
67// NamespaceDefault is a string representing the default namespace.
68const NamespaceDefault = metav1.NamespaceDefault
69
70// PodUpdate defines an operation sent on the channel. You can add or remove single services by
71// sending an array of size one and Op == ADD|REMOVE (with REMOVE, only the ID is required).
72// For setting the state of the system to a given state for this source configuration, set
73// Pods as desired and Op to SET, which will reset the system state to that specified in this
74// operation for this source channel. To remove all pods, set Pods to empty object and Op to SET.
75//
76// Additionally, Pods should never be nil - it should always point to an empty slice. While
77// functionally similar, this helps our unit tests properly check that the correct PodUpdates
78// are generated.
79type PodUpdate struct {
80	Pods   []*v1.Pod
81	Op     PodOperation
82	Source string
83}
84
85// GetValidatedSources gets all validated sources from the specified sources.
86func GetValidatedSources(sources []string) ([]string, error) {
87	validated := make([]string, 0, len(sources))
88	for _, source := range sources {
89		switch source {
90		case AllSource:
91			return []string{FileSource, HTTPSource, ApiserverSource}, nil
92		case FileSource, HTTPSource, ApiserverSource:
93			validated = append(validated, source)
94		case "":
95			// Skip
96		default:
97			return []string{}, fmt.Errorf("unknown pod source %q", source)
98		}
99	}
100	return validated, nil
101}
102
103// GetPodSource returns the source of the pod based on the annotation.
104func GetPodSource(pod *v1.Pod) (string, error) {
105	if pod.Annotations != nil {
106		if source, ok := pod.Annotations[ConfigSourceAnnotationKey]; ok {
107			return source, nil
108		}
109	}
110	return "", fmt.Errorf("cannot get source of pod %q", pod.UID)
111}
112
113// SyncPodType classifies pod updates, eg: create, update.
114type SyncPodType int
115
116const (
117	// SyncPodSync is when the pod is synced to ensure desired state
118	SyncPodSync SyncPodType = iota
119	// SyncPodUpdate is when the pod is updated from source
120	SyncPodUpdate
121	// SyncPodCreate is when the pod is created from source
122	SyncPodCreate
123	// SyncPodKill is when the pod should have no running containers. A pod stopped in this way could be
124	// restarted in the future due config changes.
125	SyncPodKill
126)
127
128func (sp SyncPodType) String() string {
129	switch sp {
130	case SyncPodCreate:
131		return "create"
132	case SyncPodUpdate:
133		return "update"
134	case SyncPodSync:
135		return "sync"
136	case SyncPodKill:
137		return "kill"
138	default:
139		return "unknown"
140	}
141}
142
143// IsMirrorPod returns true if the passed Pod is a Mirror Pod.
144func IsMirrorPod(pod *v1.Pod) bool {
145	_, ok := pod.Annotations[ConfigMirrorAnnotationKey]
146	return ok
147}
148
149// IsStaticPod returns true if the pod is a static pod.
150func IsStaticPod(pod *v1.Pod) bool {
151	source, err := GetPodSource(pod)
152	return err == nil && source != ApiserverSource
153}
154
155// IsCriticalPod returns true if pod's priority is greater than or equal to SystemCriticalPriority.
156func IsCriticalPod(pod *v1.Pod) bool {
157	if IsStaticPod(pod) {
158		return true
159	}
160	if IsMirrorPod(pod) {
161		return true
162	}
163	if pod.Spec.Priority != nil && IsCriticalPodBasedOnPriority(*pod.Spec.Priority) {
164		return true
165	}
166	return false
167}
168
169// Preemptable returns true if preemptor pod can preempt preemptee pod
170// if preemptee is not critical or if preemptor's priority is greater than preemptee's priority
171func Preemptable(preemptor, preemptee *v1.Pod) bool {
172	if IsCriticalPod(preemptor) && !IsCriticalPod(preemptee) {
173		return true
174	}
175	if (preemptor != nil && preemptor.Spec.Priority != nil) &&
176		(preemptee != nil && preemptee.Spec.Priority != nil) {
177		return *(preemptor.Spec.Priority) > *(preemptee.Spec.Priority)
178	}
179
180	return false
181}
182
183// IsCriticalPodBasedOnPriority checks if the given pod is a critical pod based on priority resolved from pod Spec.
184func IsCriticalPodBasedOnPriority(priority int32) bool {
185	return priority >= scheduling.SystemCriticalPriority
186}
187
188// IsNodeCriticalPod checks if the given pod is a system-node-critical
189func IsNodeCriticalPod(pod *v1.Pod) bool {
190	return IsCriticalPod(pod) && (pod.Spec.PriorityClassName == scheduling.SystemNodeCritical)
191}
192