-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
revision_helpers.go
164 lines (135 loc) · 5.37 KB
/
revision_helpers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
Copyright 2020 The Knative 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 v1
import (
"time"
corev1 "k8s.io/api/core/v1"
net "knative.dev/networking/pkg/apis/networking"
"knative.dev/pkg/kmeta"
"knative.dev/serving/pkg/apis/serving"
)
const (
// DefaultUserPort is the system default port value exposed on the user-container.
DefaultUserPort = 8080
// UserPortName is the name that will be used for the Port on the
// Deployment and Pod created by a Revision. This name will be set regardless of if
// a user specifies a port or the default value is chosen.
UserPortName = "user-port"
// QueueAdminPortName specifies the port name for
// health check and lifecycle hooks for queue-proxy.
QueueAdminPortName = "http-queueadm"
// AutoscalingQueueMetricsPortName specifies the port name to use for metrics
// emitted by queue-proxy for autoscaler.
AutoscalingQueueMetricsPortName = "http-autometric"
// UserQueueMetricsPortName specifies the port name to use for metrics
// emitted by queue-proxy for end user.
UserQueueMetricsPortName = "http-usermetric"
)
// RoutingState represents states of a revision with regards to serving a route.
type RoutingState string
const (
// RoutingStateUnset is the empty value for routing state, this state is unexpected.
RoutingStateUnset RoutingState = ""
// RoutingStatePending is a state after a revision is created, but before
// its routing state has been determined. It is treated like active for the purposes
// of revision garbage collection.
RoutingStatePending RoutingState = "pending"
// RoutingStateActive is a state for a revision which is actively referenced by a Route.
RoutingStateActive RoutingState = "active"
// RoutingStateReserve is a state for a revision which is no longer referenced by a Route,
// and is scaled down, but may be rapidly pinned to a route to be made active again.
RoutingStateReserve RoutingState = "reserve"
)
// GetContainer returns a pointer to the relevant corev1.Container field.
// It is never nil and should be exactly the specified container if len(containers) == 1 or
// if there are multiple containers it returns the container which has Ports
// as guaranteed by validation.
// Note: If you change this function, also update GetSidecarContainers.
func (rs *RevisionSpec) GetContainer() *corev1.Container {
switch {
case len(rs.Containers) == 1:
return &rs.Containers[0]
case len(rs.Containers) > 1:
for i := range rs.Containers {
if len(rs.Containers[i].Ports) != 0 {
return &rs.Containers[i]
}
}
}
// Should be unreachable post-validation, but here to ease testing.
return &corev1.Container{}
}
// GetSidecarContainers returns a slice of pointers to all sidecar containers.
// If len(containers) == 1 OR only one container with a user-port exists, it will return an empty slice.
// It is the "rest" of GetContainer.
func (rs *RevisionSpec) GetSidecarContainers() []*corev1.Container {
sidecars := []*corev1.Container{}
if len(rs.Containers) == 1 {
return sidecars
}
for i, c := range rs.Containers {
if len(c.Ports) == 0 {
sidecars = append(sidecars, &rs.Containers[i])
}
}
return sidecars
}
// SetRoutingState sets the routingState label on this Revision and updates the
// routingStateModified annotation.
func (r *Revision) SetRoutingState(state RoutingState, tm time.Time) {
stateStr := string(state)
if t := r.Annotations[serving.RoutingStateModifiedAnnotationKey]; t != "" &&
r.Labels[serving.RoutingStateLabelKey] == stateStr {
return // Don't update timestamp if no change.
}
r.Labels = kmeta.UnionMaps(r.Labels,
map[string]string{serving.RoutingStateLabelKey: stateStr})
r.Annotations = kmeta.UnionMaps(r.Annotations,
map[string]string{
serving.RoutingStateModifiedAnnotationKey: RoutingStateModifiedString(tm),
},
)
}
// RoutingStateModifiedString gives a formatted now timestamp.
func RoutingStateModifiedString(t time.Time) string {
return t.UTC().Format(time.RFC3339)
}
// GetRoutingState retrieves the RoutingState label.
func (r *Revision) GetRoutingState() RoutingState {
return RoutingState(r.Labels[serving.RoutingStateLabelKey])
}
// GetRoutingStateModified retrieves the RoutingStateModified annotation.
func (r *Revision) GetRoutingStateModified() time.Time {
val := r.Annotations[serving.RoutingStateModifiedAnnotationKey]
if val == "" {
return time.Time{}
}
parsed, err := time.Parse(time.RFC3339, val)
if err != nil {
return time.Time{}
}
return parsed
}
// GetProtocol returns the app level network protocol.
func (r *Revision) GetProtocol() net.ProtocolType {
ports := r.Spec.GetContainer().Ports
if len(ports) > 0 && ports[0].Name == string(net.ProtocolH2C) {
return net.ProtocolH2C
}
return net.ProtocolHTTP1
}
// IsActivationRequired returns true if activation is required.
func (rs *RevisionStatus) IsActivationRequired() bool {
c := revisionCondSet.Manage(rs).GetCondition(RevisionConditionActive)
return c != nil && c.Status != corev1.ConditionTrue
}