Skip to content

Commit 7cc6f3f

Browse files
committed
generate build state events
1 parent 4b16943 commit 7cc6f3f

File tree

11 files changed

+139
-4
lines changed

11 files changed

+139
-4
lines changed

pkg/build/api/types.go

+25
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,31 @@ const (
6363
// forces the build to be processed by the build controller queue without waiting
6464
// for a resync.
6565
BuildAcceptedAnnotation = "build.openshift.io/accepted"
66+
67+
// BuildCreatedEvent is the reason associated with the event registered when a build is created.
68+
BuildCreatedEventReason = "BuildCreated"
69+
// BuildCreatedEventMessage is the message associatd with the event registered when a build is created.
70+
BuildCreatedEventMessage = "Build %s/%s has been created"
71+
// BuildStartedEvent is the reason associated with the event registered when a build is started (pod is created).
72+
BuildStartedEventReason = "BuildStarted"
73+
// BuildStartedEvent is the message associated with the event registered when a build is started (pod is created).
74+
BuildStartedEventMessage = "Pod has been created to run build %s/%s"
75+
// BuildRunningEvent is the reason associated with the event registered when the build pod starts running.
76+
BuildRunningEventReason = "BuildRunning"
77+
// BuildRunningEvent is the message associated with the event registered when the build pod starts running.
78+
BuildRunningEventMessage = "Pod for build %s/%s started running"
79+
// BuildCompletedEvent is the reason associated with the event registered when build completes successfully.
80+
BuildCompletedEventReason = "BuildCompleted"
81+
// BuildCompletedEvent is the message associated with the event registered when build completes successfully.
82+
BuildCompletedEventMessage = "Build %s/%s completed successfully"
83+
// BuildFailedEvent is the reason associated with the event registered when build fails.
84+
BuildFailedEventReason = "BuildFailed"
85+
// BuildFailedEvent is the message associated with the event registered when build fails.
86+
BuildFailedEventMessage = "Build %s/%s failed"
87+
// BuildCancelledEvent is the reason associated with the event registered when build is cancelled.
88+
BuildCancelledEventReason = "BuildCancelled"
89+
// BuildCancelledEvent is the message associated with the event registered when build is cancelled.
90+
BuildCancelledEventMessage = "Build %s/%s has been cancelled"
6691
)
6792

6893
// +genclient=true

pkg/build/client/clients.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ func (c OSClientBuildConfigClient) Update(buildConfig *buildapi.BuildConfig) err
3737
return err
3838
}
3939

40+
// BuildGetter provides methods for getting existing Builds.
41+
type BuildGetter interface {
42+
Get(namespace, name string) (*buildapi.Build, error)
43+
}
44+
4045
// BuildUpdater provides methods for updating existing Builds.
4146
type BuildUpdater interface {
4247
Update(namespace string, build *buildapi.Build) error
@@ -47,7 +52,7 @@ type BuildLister interface {
4752
List(namespace string, opts kapi.ListOptions) (*buildapi.BuildList, error)
4853
}
4954

50-
// OSClientBuildClient deletes build create and update operations to the OpenShift client interface
55+
// OSClientBuildClient delegates build create and update operations to the OpenShift client interface
5156
type OSClientBuildClient struct {
5257
Client osclient.Interface
5358
}
@@ -57,6 +62,11 @@ func NewOSClientBuildClient(client osclient.Interface) *OSClientBuildClient {
5762
return &OSClientBuildClient{Client: client}
5863
}
5964

65+
// Get returns a Build using the OpenShift client.
66+
func (c OSClientBuildClient) Get(namespace, name string) (*buildapi.Build, error) {
67+
return c.Client.Builds(namespace).Get(name)
68+
}
69+
6070
// Update updates builds using the OpenShift client.
6171
func (c OSClientBuildClient) Update(namespace string, build *buildapi.Build) error {
6272
_, e := c.Client.Builds(namespace).Update(build)

pkg/build/controller/buildpod/controller.go

+16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"k8s.io/kubernetes/pkg/client/cache"
1212
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
1313
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
14+
"k8s.io/kubernetes/pkg/client/record"
1415
kcontroller "k8s.io/kubernetes/pkg/controller"
1516
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
1617
"k8s.io/kubernetes/pkg/util/wait"
@@ -49,16 +50,22 @@ type BuildPodController struct {
4950
podStoreSynced func() bool
5051

5152
runPolicies []policy.RunPolicy
53+
54+
recorder record.EventRecorder
5255
}
5356

5457
// NewBuildPodController creates a new BuildPodController.
5558
func NewBuildPodController(buildInformer, podInformer cache.SharedIndexInformer, kc kclientset.Interface, oc osclient.Interface) *BuildPodController {
59+
eventBroadcaster := record.NewBroadcaster()
60+
eventBroadcaster.StartRecordingToSink(&kcoreclient.EventSinkImpl{Interface: kc.Core().Events("")})
61+
5662
buildListerUpdater := buildclient.NewOSClientBuildClient(oc)
5763
c := &BuildPodController{
5864
buildUpdater: buildListerUpdater,
5965
secretClient: kc.Core(), // TODO: Replace with cache client
6066
podClient: kc.Core(),
6167
queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
68+
recorder: eventBroadcaster.NewRecorder(kapi.EventSource{Component: "build-pod-controller"}),
6269
}
6370

6471
c.runPolicies = policy.GetAllRunPolicies(buildListerUpdater, buildListerUpdater)
@@ -189,10 +196,17 @@ func (bc *BuildPodController) HandlePod(pod *kapi.Pod) error {
189196

190197
if buildutil.IsBuildComplete(build) {
191198
common.SetBuildCompletionTimeAndDuration(build)
199+
switch build.Status.Phase {
200+
case buildapi.BuildPhaseComplete:
201+
bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildCompletedEventReason, fmt.Sprintf(buildapi.BuildCompletedEventMessage, build.Namespace, build.Name))
202+
case buildapi.BuildPhaseError, buildapi.BuildPhaseFailed:
203+
bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildFailedEventReason, fmt.Sprintf(buildapi.BuildFailedEventMessage, build.Namespace, build.Name))
204+
}
192205
}
193206
if build.Status.Phase == buildapi.BuildPhaseRunning {
194207
now := unversioned.Now()
195208
build.Status.StartTimestamp = &now
209+
bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildRunningEventReason, fmt.Sprintf(buildapi.BuildRunningEventMessage, build.Namespace, build.Name))
196210
}
197211
if err := bc.buildUpdater.Update(build.Namespace, build); err != nil {
198212
return fmt.Errorf("failed to update build %s/%s: %v", build.Namespace, build.Name, err)
@@ -241,6 +255,8 @@ func (bc *BuildPodController) HandleBuildPodDeletion(pod *kapi.Pod) error {
241255
build.Status.Reason = buildapi.StatusReasonBuildPodDeleted
242256
build.Status.Message = buildapi.StatusMessageBuildPodDeleted
243257
common.SetBuildCompletionTimeAndDuration(build)
258+
bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildFailedEventReason, fmt.Sprintf(buildapi.BuildFailedEventMessage, build.Namespace, build.Name))
259+
244260
if err := bc.buildUpdater.Update(build.Namespace, build); err != nil {
245261
return fmt.Errorf("Failed to update build %s/%s: %v", build.Namespace, build.Name, err)
246262
}

pkg/build/controller/controller.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ func (bc *BuildController) CancelBuild(build *buildapi.Build) error {
7272

7373
build.Status.Phase = buildapi.BuildPhaseCancelled
7474
common.SetBuildCompletionTimeAndDuration(build)
75+
bc.Recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildCancelledEventReason, fmt.Sprintf(buildapi.BuildCancelledEventMessage, build.Namespace, build.Name))
7576
// set the status details for the cancelled build before updating the build
7677
// object.
7778
build.Status.Reason = buildapi.StatusReasonCancelledBuild
@@ -219,8 +220,9 @@ func (bc *BuildController) nextBuildPhase(build *buildapi.Build) error {
219220
build.Status.Message = buildapi.StatusMessageCannotCreateBuildPod
220221
return fmt.Errorf("failed to create build pod: %v", err)
221222
}
222-
common.SetBuildPodNameAnnotation(build, podSpec.Name)
223223
glog.V(4).Infof("Created pod for build: %#v", podSpec)
224+
bc.Recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildStartedEventReason, fmt.Sprintf(buildapi.BuildStartedEventMessage, build.Namespace, build.Name))
225+
common.SetBuildPodNameAnnotation(build, podSpec.Name)
224226

225227
// Set the build phase, which will be persisted.
226228
build.Status.Phase = buildapi.BuildPhasePending

pkg/build/generator/generator.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ import (
1313
"k8s.io/kubernetes/pkg/api/errors"
1414
"k8s.io/kubernetes/pkg/api/unversioned"
1515
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
16+
"k8s.io/kubernetes/pkg/client/record"
1617
"k8s.io/kubernetes/pkg/credentialprovider"
1718
kvalidation "k8s.io/kubernetes/pkg/util/validation"
1819

1920
buildapi "github.com/openshift/origin/pkg/build/api"
21+
buildclient "github.com/openshift/origin/pkg/build/client"
2022
buildutil "github.com/openshift/origin/pkg/build/util"
2123
"github.com/openshift/origin/pkg/cmd/admin/policy"
2224
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
@@ -49,6 +51,8 @@ type BuildGenerator struct {
4951
DefaultServiceAccountName string
5052
ServiceAccounts kcoreclient.ServiceAccountsGetter
5153
Secrets kcoreclient.SecretsGetter
54+
Recorder record.EventRecorder
55+
Builds buildclient.BuildGetter
5256
}
5357

5458
// GeneratorClient is the API client used by the generator
@@ -430,7 +434,12 @@ func (g *BuildGenerator) createBuild(ctx kapi.Context, build *buildapi.Build) (*
430434
if err != nil {
431435
return nil, err
432436
}
433-
return g.Client.GetBuild(ctx, build.Name)
437+
b, err := g.Builds.Get(build.Namespace, build.Name)
438+
//b, err := g.Client.GetBuild(ctx, build.Name)
439+
if err == nil {
440+
g.Recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildCreatedEventReason, fmt.Sprintf(buildapi.BuildCreatedEventMessage, build.Namespace, build.Name))
441+
}
442+
return b, err
434443
}
435444

436445
// generateBuildFromConfig generates a build definition based on the current imageid

pkg/cmd/server/origin/master.go

+7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
"k8s.io/kubernetes/pkg/apiserver"
2929
kapiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
3030
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
31+
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
32+
"k8s.io/kubernetes/pkg/client/record"
3133
"k8s.io/kubernetes/pkg/client/restclient"
3234
"k8s.io/kubernetes/pkg/genericapiserver"
3335
kgenericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
@@ -743,6 +745,9 @@ func (c *MasterConfig) GetRestStorage() map[unversioned.GroupVersion]map[string]
743745
imageStreamImageStorage := imagestreamimage.NewREST(imageRegistry, imageStreamRegistry)
744746
imageStreamImageRegistry := imagestreamimage.NewRegistry(imageStreamImageStorage)
745747

748+
eventBroadcaster := record.NewBroadcaster()
749+
eventBroadcaster.StartRecordingToSink(&kcoreclient.EventSinkImpl{Interface: c.KubeClientset().Core().Events("")})
750+
generatorBuildClient, _ := c.BuildConfigChangeControllerClients()
746751
buildGenerator := &buildgenerator.BuildGenerator{
747752
Client: buildgenerator.Client{
748753
GetBuildConfigFunc: buildConfigRegistry.GetBuildConfig,
@@ -756,6 +761,8 @@ func (c *MasterConfig) GetRestStorage() map[unversioned.GroupVersion]map[string]
756761
},
757762
ServiceAccounts: c.KubeClientset(),
758763
Secrets: c.KubeClientset(),
764+
Builds: buildclient.NewOSClientBuildClient(generatorBuildClient),
765+
Recorder: eventBroadcaster.NewRecorder(kapi.EventSource{Component: "build-generator"}),
759766
}
760767

761768
// TODO: with sharding, this needs to be changed

test/common/build/controllers.go

+18
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,24 @@ func RunBuildRunningPodDeleteTest(t testingT, clusterAdminClient *client.Client,
612612
if newBuild.Status.Phase != buildapi.BuildPhaseError {
613613
t.Fatalf("expected build status to be marked error, but was marked %s", newBuild.Status.Phase)
614614
}
615+
events, err := clusterAdminKubeClientset.Core().Events(testutil.Namespace()).Search(newBuild)
616+
if err != nil {
617+
t.Fatalf("error getting build events: %v", err)
618+
}
619+
foundFailed := false
620+
for _, event := range events.Items {
621+
switch event.Reason {
622+
case buildapi.BuildFailedEventReason:
623+
foundFailed = true
624+
expect := fmt.Sprintf(buildapi.BuildFailedEventMessage, newBuild.Namespace, newBuild.Name)
625+
if event.Message != expect {
626+
t.Fatalf("expected failed event message to be %s, got %s", expect, event.Message)
627+
}
628+
}
629+
}
630+
if !foundFailed {
631+
t.Fatalf("expected to find a failed event on the build %s/%s", newBuild.Namespace, newBuild.Name)
632+
}
615633
}
616634

617635
func RunBuildCompletePodDeleteTest(t testingT, clusterAdminClient *client.Client, clusterAdminKubeClientset *kclientset.Clientset) {

test/extended/builds/failure_status.go

+16
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
5353
o.Expect(err).NotTo(o.HaveOccurred())
5454
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonPostCommitHookFailed))
5555
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessagePostCommitHookFailed))
56+
57+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
5658
})
5759
})
5860

@@ -70,6 +72,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
7072
o.Expect(err).NotTo(o.HaveOccurred())
7173
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonFetchSourceFailed))
7274
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessageFetchSourceFailed))
75+
76+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
7377
})
7478
})
7579

@@ -87,6 +91,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
8791
o.Expect(err).NotTo(o.HaveOccurred())
8892
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonFetchSourceFailed))
8993
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessageFetchSourceFailed))
94+
95+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
9096
})
9197
})
9298

@@ -104,6 +110,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
104110
o.Expect(err).NotTo(o.HaveOccurred())
105111
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonPullBuilderImageFailed))
106112
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessagePullBuilderImageFailed))
113+
114+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
107115
})
108116
})
109117

@@ -121,6 +129,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
121129
o.Expect(err).NotTo(o.HaveOccurred())
122130
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonPushImageToRegistryFailed))
123131
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessagePushImageToRegistryFailed))
132+
133+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
124134
})
125135
})
126136

@@ -138,6 +148,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
138148
o.Expect(err).NotTo(o.HaveOccurred())
139149
o.Expect(build.Status.Reason).To(o.Equal(reasonAssembleFailed))
140150
o.Expect(build.Status.Message).To(o.Equal(messageAssembleFailed))
151+
152+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
141153
})
142154
})
143155

@@ -155,6 +167,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
155167
o.Expect(err).NotTo(o.HaveOccurred())
156168
o.Expect(build.Status.Reason).To(o.Equal(reasonFetchRuntimeArtifacts))
157169
o.Expect(build.Status.Message).To(o.Equal(messageFetchRuntimeArtifacts))
170+
171+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
158172
})
159173
})
160174

@@ -172,6 +186,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
172186
o.Expect(err).NotTo(o.HaveOccurred())
173187
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonGenericBuildFailed))
174188
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessageGenericBuildFailed))
189+
190+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
175191
})
176192
})
177193
})

test/extended/builds/s2i_quota.go

+11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
g "github.com/onsi/ginkgo"
77
o "github.com/onsi/gomega"
88

9+
buildapi "github.com/openshift/origin/pkg/build/api"
910
exutil "github.com/openshift/origin/test/extended/util"
1011
)
1112

@@ -52,6 +53,16 @@ var _ = g.Describe("[builds][Conformance] s2i build with a quota", func() {
5253
o.Expect(buildLog).To(o.ContainSubstring("SHARES=61"))
5354
o.Expect(buildLog).To(o.ContainSubstring("PERIOD=100000"))
5455
o.Expect(buildLog).To(o.ContainSubstring("QUOTA=6000"))
56+
57+
events, err := oc.KubeClient().Core().Events(oc.Namespace()).Search(br.Build)
58+
o.Expect(err).NotTo(o.HaveOccurred(), "Should be able to get events from the build")
59+
o.Expect(events).NotTo(o.BeNil(), "Build event list should not be nil")
60+
61+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildCreatedEventReason, buildapi.BuildCreatedEventMessage)
62+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildStartedEventReason, buildapi.BuildStartedEventMessage)
63+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildRunningEventReason, buildapi.BuildRunningEventMessage)
64+
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
65+
5566
})
5667
})
5768
})

test/extended/builds/start.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ var _ = g.Describe("[builds][Slow] starting a build using CLI", func() {
216216
err := exutil.WaitForABuild(oc.Client().Builds(oc.Namespace()), "sample-build-binary-invalidnodeselector-1", nil, nil, cancelFn)
217217
o.Expect(err).NotTo(o.HaveOccurred())
218218
o.Expect(build.Status.Phase).To(o.Equal(buildapi.BuildPhaseCancelled))
219+
exutil.CheckForEvent(oc.KubeClient().Core(), build, buildapi.BuildCancelledEventReason, buildapi.BuildCancelledEventMessage)
219220
})
220221
})
221222

@@ -247,9 +248,13 @@ var _ = g.Describe("[builds][Slow] starting a build using CLI", func() {
247248
})
248249

249250
o.Expect(buildName).ToNot(o.BeEmpty())
251+
build, err := oc.Client().Builds(oc.Namespace()).Get(buildName)
252+
o.Expect(err).NotTo(o.HaveOccurred())
253+
o.Expect(build).NotTo(o.BeNil(), "build object should exist")
254+
exutil.CheckForEvent(oc.KubeClient().Core(), build, buildapi.BuildCancelledEventReason, buildapi.BuildCancelledEventMessage)
250255

251256
g.By(fmt.Sprintf("cancelling the build %q", buildName))
252-
err := oc.Run("cancel-build").Args(buildName).Execute()
257+
err = oc.Run("cancel-build").Args(buildName).Execute()
253258
o.Expect(err).ToNot(o.HaveOccurred())
254259
wg.Wait()
255260
})

test/extended/util/framework.go

+16
Original file line numberDiff line numberDiff line change
@@ -1400,3 +1400,19 @@ func CreateExecPodOnNode(client kcoreclient.CoreInterface, ns, nodeName, name st
14001400
o.Expect(err).NotTo(o.HaveOccurred())
14011401
return created.Name
14021402
}
1403+
1404+
func CheckForEvent(client kcoreclient.CoreInterface, build *buildapi.Build, reason, message string) {
1405+
events, err := client.Events(build.Namespace).Search(build)
1406+
o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred(), "Should be able to get events from the build")
1407+
o.ExpectWithOffset(1, events).NotTo(o.BeNil(), "Build event list should not be nil")
1408+
1409+
failed := false
1410+
for _, event := range events.Items {
1411+
switch event.Reason {
1412+
case reason:
1413+
failed = true
1414+
o.ExpectWithOffset(1, event.Message).To(o.Equal(fmt.Sprintf(message, build.Namespace, build.Name)))
1415+
}
1416+
}
1417+
o.ExpectWithOffset(1, failed).To(o.BeTrue(), "Did not find a %q event on build %s/%s", reason, build.Namespace, build.Name)
1418+
}

0 commit comments

Comments
 (0)