/
strategy.go
144 lines (121 loc) · 4.38 KB
/
strategy.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
package route
import (
"fmt"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
"github.com/openshift/origin/pkg/route"
"github.com/openshift/origin/pkg/route/api"
"github.com/openshift/origin/pkg/route/api/validation"
)
// HostGeneratedAnnotationKey is the key for an annotation set to "true" if the route's host was generated
const HostGeneratedAnnotationKey = "openshift.io/host.generated"
type routeStrategy struct {
runtime.ObjectTyper
kapi.NameGenerator
route.RouteAllocator
}
// NewStrategy initializes the default logic that applies when creating and updating
// Route objects via the REST API.
func NewStrategy(allocator route.RouteAllocator) routeStrategy {
return routeStrategy{
kapi.Scheme,
kapi.SimpleNameGenerator,
allocator,
}
}
func (routeStrategy) NamespaceScoped() bool {
return true
}
func (s routeStrategy) PrepareForCreate(ctx kapi.Context, obj runtime.Object) {
route := obj.(*api.Route)
route.Status = api.RouteStatus{}
err := s.allocateHost(route)
if err != nil {
// TODO: this will be changed when moved to a controller
utilruntime.HandleError(errors.NewInternalError(fmt.Errorf("allocation error: %v for route: %#v", err, obj)))
}
}
func (s routeStrategy) PrepareForUpdate(ctx kapi.Context, obj, old runtime.Object) {
route := obj.(*api.Route)
oldRoute := old.(*api.Route)
route.Status = oldRoute.Status
// Ignore attempts to clear the spec Host
// Prevents "immutable field" errors when applying the same route definition used to create
if len(route.Spec.Host) == 0 {
route.Spec.Host = oldRoute.Spec.Host
}
}
// allocateHost allocates a host name ONLY if the route doesn't specify a subdomain wildcard policy and
// the host name on the route is empty and an allocator is configured.
// It must first allocate the shard and may return an error if shard allocation fails.
func (s routeStrategy) allocateHost(route *api.Route) error {
if route.Spec.WildcardPolicy == api.WildcardPolicySubdomain {
// Don't allocate a host if subdomain wildcard policy.
return nil
}
if len(route.Spec.Host) == 0 && s.RouteAllocator != nil {
// TODO: this does not belong here, and should be removed
shard, err := s.RouteAllocator.AllocateRouterShard(route)
if err != nil {
return errors.NewInternalError(fmt.Errorf("allocation error: %v for route: %#v", err, route))
}
route.Spec.Host = s.RouteAllocator.GenerateHostname(route, shard)
if route.Annotations == nil {
route.Annotations = map[string]string{}
}
route.Annotations[HostGeneratedAnnotationKey] = "true"
}
return nil
}
func (routeStrategy) Validate(ctx kapi.Context, obj runtime.Object) field.ErrorList {
route := obj.(*api.Route)
return validation.ValidateRoute(route)
}
func (routeStrategy) AllowCreateOnUpdate() bool {
return false
}
// Canonicalize normalizes the object after validation.
func (routeStrategy) Canonicalize(obj runtime.Object) {
}
func (routeStrategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) field.ErrorList {
oldRoute := old.(*api.Route)
objRoute := obj.(*api.Route)
return validation.ValidateRouteUpdate(objRoute, oldRoute)
}
func (routeStrategy) AllowUnconditionalUpdate() bool {
return false
}
type routeStatusStrategy struct {
routeStrategy
}
var StatusStrategy = routeStatusStrategy{NewStrategy(nil)}
func (routeStatusStrategy) PrepareForUpdate(ctx kapi.Context, obj, old runtime.Object) {
newRoute := obj.(*api.Route)
oldRoute := old.(*api.Route)
newRoute.Spec = oldRoute.Spec
}
func (routeStatusStrategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) field.ErrorList {
return validation.ValidateRouteStatusUpdate(obj.(*api.Route), old.(*api.Route))
}
// GetAttrs returns labels and fields of a given object for filtering purposes
func GetAttrs(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) {
route, ok := obj.(*api.Route)
if !ok {
return nil, nil, fmt.Errorf("not a route")
}
return labels.Set(route.Labels), api.RouteToSelectableFields(route), nil
}
// Matcher returns a matcher for a route
func Matcher(label labels.Selector, field fields.Selector) storage.SelectionPredicate {
return storage.SelectionPredicate{
Label: label,
Field: field,
GetAttrs: GetAttrs,
}
}