forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrest.go
145 lines (130 loc) · 5.19 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
package buildlog
import (
"fmt"
"time"
"github.com/golang/glog"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/client/unversioned"
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
genericrest "k8s.io/kubernetes/pkg/registry/generic/rest"
"k8s.io/kubernetes/pkg/registry/pod"
"k8s.io/kubernetes/pkg/runtime"
"github.com/openshift/origin/pkg/build/api"
"github.com/openshift/origin/pkg/build/api/validation"
"github.com/openshift/origin/pkg/build/registry"
buildutil "github.com/openshift/origin/pkg/build/util"
)
// REST is an implementation of RESTStorage for the api server.
type REST struct {
Getter rest.Getter
Watcher rest.Watcher
PodGetter pod.ResourceGetter
ConnectionInfo kubeletclient.ConnectionInfoGetter
Timeout time.Duration
}
type podGetter struct {
podsNamespacer unversioned.PodsNamespacer
}
func (g *podGetter) Get(ctx kapi.Context, name string) (runtime.Object, error) {
ns, ok := kapi.NamespaceFrom(ctx)
if !ok {
return nil, errors.NewBadRequest("namespace parameter required.")
}
return g.podsNamespacer.Pods(ns).Get(name)
}
const defaultTimeout time.Duration = 10 * time.Second
// NewREST creates a new REST for BuildLog
// Takes build registry and pod client to get necessary attributes to assemble
// URL to which the request shall be redirected in order to get build logs.
func NewREST(getter rest.Getter, watcher rest.Watcher, pn unversioned.PodsNamespacer, connectionInfo kubeletclient.ConnectionInfoGetter) *REST {
return &REST{
Getter: getter,
Watcher: watcher,
PodGetter: &podGetter{pn},
ConnectionInfo: connectionInfo,
Timeout: defaultTimeout,
}
}
var _ = rest.GetterWithOptions(&REST{})
// Get returns a streamer resource with the contents of the build log
func (r *REST) Get(ctx kapi.Context, name string, opts runtime.Object) (runtime.Object, error) {
buildLogOpts, ok := opts.(*api.BuildLogOptions)
if !ok {
return nil, errors.NewBadRequest("did not get an expected options.")
}
if errs := validation.ValidateBuildLogOptions(buildLogOpts); len(errs) > 0 {
return nil, errors.NewInvalid(api.Kind("BuildLogOptions"), "", errs)
}
obj, err := r.Getter.Get(ctx, name)
if err != nil {
return nil, err
}
build := obj.(*api.Build)
if buildLogOpts.Previous {
version := buildutil.VersionForBuild(build)
// Use the previous version
version--
previousBuildName := buildutil.BuildNameForConfigVersion(buildutil.ConfigNameForBuild(build), version)
previous, err := r.Getter.Get(ctx, previousBuildName)
if err != nil {
return nil, err
}
build = previous.(*api.Build)
}
switch build.Status.Phase {
// Build has not launched, wait til it runs
case api.BuildPhaseNew, api.BuildPhasePending:
if buildLogOpts.NoWait {
glog.V(4).Infof("Build %s/%s is in %s state. No logs to retrieve yet.", build.Namespace, build.Name, build.Status.Phase)
// return empty content if not waiting for build
return &genericrest.LocationStreamer{}, nil
}
glog.V(4).Infof("Build %s/%s is in %s state, waiting for Build to start", build.Namespace, build.Name, build.Status.Phase)
latest, ok, err := registry.WaitForRunningBuild(r.Watcher, ctx, build, r.Timeout)
if err != nil {
return nil, errors.NewBadRequest(fmt.Sprintf("unable to wait for build %s to run: %v", build.Name, err))
}
switch latest.Status.Phase {
case api.BuildPhaseError:
return nil, errors.NewBadRequest(fmt.Sprintf("build %s encountered an error: %s", build.Name, buildutil.NoBuildLogsMessage))
case api.BuildPhaseCancelled:
return nil, errors.NewBadRequest(fmt.Sprintf("build %s was cancelled: %s", build.Name, buildutil.NoBuildLogsMessage))
}
if !ok {
return nil, errors.NewTimeoutError(fmt.Sprintf("timed out waiting for build %s to start after %s", build.Name, r.Timeout), 1)
}
// The build was cancelled
case api.BuildPhaseCancelled:
return nil, errors.NewBadRequest(fmt.Sprintf("build %s was cancelled. %s", build.Name, buildutil.NoBuildLogsMessage))
// An error occurred launching the build, return an error
case api.BuildPhaseError:
return nil, errors.NewBadRequest(fmt.Sprintf("build %s is in an error state. %s", build.Name, buildutil.NoBuildLogsMessage))
}
// The container should be the default build container, so setting it to blank
buildPodName := api.GetBuildPodName(build)
logOpts := api.BuildToPodLogOptions(buildLogOpts)
location, transport, err := pod.LogLocation(r.PodGetter, r.ConnectionInfo, ctx, buildPodName, logOpts)
if err != nil {
if errors.IsNotFound(err) {
return nil, errors.NewNotFound(kapi.Resource("pod"), buildPodName)
}
return nil, errors.NewBadRequest(err.Error())
}
return &genericrest.LocationStreamer{
Location: location,
Transport: transport,
ContentType: "text/plain",
Flush: buildLogOpts.Follow,
ResponseChecker: genericrest.NewGenericHttpResponseChecker(kapi.Resource("pod"), buildPodName),
}, nil
}
// NewGetOptions returns a new options object for build logs
func (r *REST) NewGetOptions() (runtime.Object, bool, string) {
return &api.BuildLogOptions{}, false, ""
}
// New creates an empty BuildLog resource
func (r *REST) New() runtime.Object {
return &api.BuildLog{}
}