forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rest.go
148 lines (126 loc) · 4.7 KB
/
rest.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
package route
import (
"fmt"
"code.google.com/p/go-uuid/uuid"
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
"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"
// REST is an implementation of RESTStorage for the api server.
type REST struct {
registry Registry
allocator route.RouteAllocator
}
// NewREST returns a RESTStorage object that will work against routes.
func NewREST(registry Registry, allocator route.RouteAllocator) *REST {
return &REST{
registry: registry,
allocator: allocator,
}
}
// New returns a new Route
func (rs *REST) New() runtime.Object {
return &api.Route{}
}
// NewList returns a new list of Routes
func (*REST) NewList() runtime.Object {
return &api.Route{}
}
// List obtains a list of Routes that match label.
func (rs *REST) List(ctx kapi.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) {
list, err := rs.registry.ListRoutes(ctx, label)
if err != nil {
return nil, err
}
return list, err
}
// Get obtains the route specified by its id.
func (rs *REST) Get(ctx kapi.Context, id string) (runtime.Object, error) {
route, err := rs.registry.GetRoute(ctx, id)
if err != nil {
return nil, err
}
return route, err
}
// Delete asynchronously deletes the Route specified by its id.
func (rs *REST) Delete(ctx kapi.Context, id string) (runtime.Object, error) {
_, err := rs.registry.GetRoute(ctx, id)
if err != nil {
return nil, err
}
return &kapi.Status{Status: kapi.StatusSuccess}, rs.registry.DeleteRoute(ctx, id)
}
// Create registers a given new Route instance to rs.registry.
func (rs *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
route, ok := obj.(*api.Route)
if !ok {
return nil, errors.NewBadRequest(fmt.Sprintf("not a route: %#v", obj))
}
if !kapi.ValidNamespace(ctx, &route.ObjectMeta) {
return nil, errors.NewConflict("route", route.Namespace, fmt.Errorf("Route.Namespace does not match the provided context"))
}
shard, err := rs.allocator.AllocateRouterShard(route)
if err != nil {
return nil, errors.NewInternalError(fmt.Errorf("allocation error: %s for route: %#v", err, obj))
}
if route.Annotations == nil {
route.Annotations = map[string]string{}
}
if len(route.Host) == 0 {
route.Host = rs.allocator.GenerateHostname(route, shard)
route.Annotations[HostGeneratedAnnotationKey] = "true"
} else {
route.Annotations[HostGeneratedAnnotationKey] = "false"
}
if errs := validation.ValidateRoute(route); len(errs) > 0 {
return nil, errors.NewInvalid("route", route.Name, errs)
}
if len(route.Name) == 0 {
route.Name = uuid.NewUUID().String()
}
kapi.FillObjectMetaSystemFields(ctx, &route.ObjectMeta)
err = rs.registry.CreateRoute(ctx, route)
if err != nil {
return nil, err
}
return rs.registry.GetRoute(ctx, route.Name)
}
// Update replaces a given Route instance with an existing instance in rs.registry.
func (rs *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
route, ok := obj.(*api.Route)
if !ok {
return nil, false, errors.NewBadRequest(fmt.Sprintf("not a route: %#v", obj))
}
if !kapi.ValidNamespace(ctx, &route.ObjectMeta) {
return nil, false, errors.NewConflict("route", route.Namespace, fmt.Errorf("Route.Namespace does not match the provided context"))
}
old, err := rs.Get(ctx, route.Name)
if err != nil {
return nil, false, err
}
if errs := validation.ValidateRouteUpdate(route, old.(*api.Route)); len(errs) > 0 {
return nil, false, errors.NewInvalid("route", route.Name, errs)
}
// TODO: Convert to generic etcd
// TODO: Call ValidateRouteUpdate->ValidateObjectMetaUpdate
// TODO: In the UpdateStrategy.PrepareForUpdate, set the HostGeneratedAnnotationKey annotation to "false" if the updated route object modifies the host
err = rs.registry.UpdateRoute(ctx, route)
if err != nil {
return nil, false, err
}
out, err := rs.registry.GetRoute(ctx, route.Name)
return out, false, err
}
// Watch returns Routes events via a watch.Interface.
// It implements apiserver.ResourceWatcher.
func (rs *REST) Watch(ctx kapi.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
return rs.registry.WatchRoutes(ctx, label, field, resourceVersion)
}