Skip to content

Commit

Permalink
generate build state events
Browse files Browse the repository at this point in the history
  • Loading branch information
bparees committed Apr 6, 2017
1 parent 4b16943 commit be1c042
Show file tree
Hide file tree
Showing 11 changed files with 139 additions and 4 deletions.
25 changes: 25 additions & 0 deletions pkg/build/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,31 @@ const (
// forces the build to be processed by the build controller queue without waiting
// for a resync.
BuildAcceptedAnnotation = "build.openshift.io/accepted"

// BuildCreatedEvent is the reason associated with the event registered when a build is created.
BuildCreatedEventReason = "BuildCreated"
// BuildCreatedEventMessage is the message associatd with the event registered when a build is created.
BuildCreatedEventMessage = "Build %s/%s has been created"
// BuildStartedEvent is the reason associated with the event registered when a build is started (pod is created).
BuildStartedEventReason = "BuildStarted"
// BuildStartedEvent is the message associated with the event registered when a build is started (pod is created).
BuildStartedEventMessage = "Pod has been created to run build %s/%s"
// BuildRunningEvent is the reason associated with the event registered when the build pod starts running.
BuildRunningEventReason = "BuildRunning"
// BuildRunningEvent is the message associated with the event registered when the build pod starts running.
BuildRunningEventMessage = "Pod for build %s/%s started running"
// BuildCompletedEvent is the reason associated with the event registered when build completes successfully.
BuildCompletedEventReason = "BuildCompleted"
// BuildCompletedEvent is the message associated with the event registered when build completes successfully.
BuildCompletedEventMessage = "Build %s/%s completed successfully"
// BuildFailedEvent is the reason associated with the event registered when build fails.
BuildFailedEventReason = "BuildFailed"
// BuildFailedEvent is the message associated with the event registered when build fails.
BuildFailedEventMessage = "Build %s/%s failed"
// BuildCancelledEvent is the reason associated with the event registered when build is cancelled.
BuildCancelledEventReason = "BuildCancelled"
// BuildCancelledEvent is the message associated with the event registered when build is cancelled.
BuildCancelledEventMessage = "Build %s/%s has been cancelled"
)

// +genclient=true
Expand Down
12 changes: 11 additions & 1 deletion pkg/build/client/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ func (c OSClientBuildConfigClient) Update(buildConfig *buildapi.BuildConfig) err
return err
}

// BuildGetter provides methods for getting existing Builds.
type BuildGetter interface {
Get(namespace, name string) (*buildapi.Build, error)
}

// BuildUpdater provides methods for updating existing Builds.
type BuildUpdater interface {
Update(namespace string, build *buildapi.Build) error
Expand All @@ -47,7 +52,7 @@ type BuildLister interface {
List(namespace string, opts kapi.ListOptions) (*buildapi.BuildList, error)
}

// OSClientBuildClient deletes build create and update operations to the OpenShift client interface
// OSClientBuildClient delegates build create and update operations to the OpenShift client interface
type OSClientBuildClient struct {
Client osclient.Interface
}
Expand All @@ -57,6 +62,11 @@ func NewOSClientBuildClient(client osclient.Interface) *OSClientBuildClient {
return &OSClientBuildClient{Client: client}
}

// Get returns a Build using the OpenShift client.
func (c OSClientBuildClient) Get(namespace, name string) (*buildapi.Build, error) {
return c.Client.Builds(namespace).Get(name)
}

// Update updates builds using the OpenShift client.
func (c OSClientBuildClient) Update(namespace string, build *buildapi.Build) error {
_, e := c.Client.Builds(namespace).Update(build)
Expand Down
16 changes: 16 additions & 0 deletions pkg/build/controller/buildpod/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"k8s.io/kubernetes/pkg/client/cache"
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/client/record"
kcontroller "k8s.io/kubernetes/pkg/controller"
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
"k8s.io/kubernetes/pkg/util/wait"
Expand Down Expand Up @@ -49,16 +50,22 @@ type BuildPodController struct {
podStoreSynced func() bool

runPolicies []policy.RunPolicy

recorder record.EventRecorder
}

// NewBuildPodController creates a new BuildPodController.
func NewBuildPodController(buildInformer, podInformer cache.SharedIndexInformer, kc kclientset.Interface, oc osclient.Interface) *BuildPodController {
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartRecordingToSink(&kcoreclient.EventSinkImpl{Interface: kc.Core().Events("")})

buildListerUpdater := buildclient.NewOSClientBuildClient(oc)
c := &BuildPodController{
buildUpdater: buildListerUpdater,
secretClient: kc.Core(), // TODO: Replace with cache client
podClient: kc.Core(),
queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
recorder: eventBroadcaster.NewRecorder(kapi.EventSource{Component: "build-pod-controller"}),
}

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

if buildutil.IsBuildComplete(build) {
common.SetBuildCompletionTimeAndDuration(build)
switch build.Status.Phase {
case buildapi.BuildPhaseComplete:
bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildCompletedEventReason, fmt.Sprintf(buildapi.BuildCompletedEventMessage, build.Namespace, build.Name))
case buildapi.BuildPhaseError, buildapi.BuildPhaseFailed:
bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildFailedEventReason, fmt.Sprintf(buildapi.BuildFailedEventMessage, build.Namespace, build.Name))
}
}
if build.Status.Phase == buildapi.BuildPhaseRunning {
now := unversioned.Now()
build.Status.StartTimestamp = &now
bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildRunningEventReason, fmt.Sprintf(buildapi.BuildRunningEventMessage, build.Namespace, build.Name))
}
if err := bc.buildUpdater.Update(build.Namespace, build); err != nil {
return fmt.Errorf("failed to update build %s/%s: %v", build.Namespace, build.Name, err)
Expand Down Expand Up @@ -241,6 +255,8 @@ func (bc *BuildPodController) HandleBuildPodDeletion(pod *kapi.Pod) error {
build.Status.Reason = buildapi.StatusReasonBuildPodDeleted
build.Status.Message = buildapi.StatusMessageBuildPodDeleted
common.SetBuildCompletionTimeAndDuration(build)
bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildFailedEventReason, fmt.Sprintf(buildapi.BuildFailedEventMessage, build.Namespace, build.Name))

if err := bc.buildUpdater.Update(build.Namespace, build); err != nil {
return fmt.Errorf("Failed to update build %s/%s: %v", build.Namespace, build.Name, err)
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/build/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func (bc *BuildController) CancelBuild(build *buildapi.Build) error {

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

// Set the build phase, which will be persisted.
build.Status.Phase = buildapi.BuildPhasePending
Expand Down
11 changes: 10 additions & 1 deletion pkg/build/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import (
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/client/record"
"k8s.io/kubernetes/pkg/credentialprovider"
kvalidation "k8s.io/kubernetes/pkg/util/validation"

buildapi "github.com/openshift/origin/pkg/build/api"
buildclient "github.com/openshift/origin/pkg/build/client"
buildutil "github.com/openshift/origin/pkg/build/util"
"github.com/openshift/origin/pkg/cmd/admin/policy"
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
Expand Down Expand Up @@ -49,6 +51,8 @@ type BuildGenerator struct {
DefaultServiceAccountName string
ServiceAccounts kcoreclient.ServiceAccountsGetter
Secrets kcoreclient.SecretsGetter
Recorder record.EventRecorder
Builds buildclient.BuildGetter
}

// GeneratorClient is the API client used by the generator
Expand Down Expand Up @@ -430,7 +434,12 @@ func (g *BuildGenerator) createBuild(ctx kapi.Context, build *buildapi.Build) (*
if err != nil {
return nil, err
}
return g.Client.GetBuild(ctx, build.Name)
b, err := g.Builds.Get(build.Namespace, build.Name)
//b, err := g.Client.GetBuild(ctx, build.Name)
if err == nil {
g.Recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildCreatedEventReason, fmt.Sprintf(buildapi.BuildCreatedEventMessage, build.Namespace, build.Name))
}
return b, err
}

// generateBuildFromConfig generates a build definition based on the current imageid
Expand Down
7 changes: 7 additions & 0 deletions pkg/cmd/server/origin/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import (
"k8s.io/kubernetes/pkg/apiserver"
kapiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/client/record"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/genericapiserver"
kgenericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
Expand Down Expand Up @@ -743,6 +745,9 @@ func (c *MasterConfig) GetRestStorage() map[unversioned.GroupVersion]map[string]
imageStreamImageStorage := imagestreamimage.NewREST(imageRegistry, imageStreamRegistry)
imageStreamImageRegistry := imagestreamimage.NewRegistry(imageStreamImageStorage)

eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartRecordingToSink(&kcoreclient.EventSinkImpl{Interface: c.KubeClientset().Core().Events("")})
generatorBuildClient, _ := c.BuildControllerClients()
buildGenerator := &buildgenerator.BuildGenerator{
Client: buildgenerator.Client{
GetBuildConfigFunc: buildConfigRegistry.GetBuildConfig,
Expand All @@ -756,6 +761,8 @@ func (c *MasterConfig) GetRestStorage() map[unversioned.GroupVersion]map[string]
},
ServiceAccounts: c.KubeClientset(),
Secrets: c.KubeClientset(),
Builds: buildclient.NewOSClientBuildClient(generatorBuildClient),
Recorder: eventBroadcaster.NewRecorder(kapi.EventSource{Component: "build-generator"}),
}

// TODO: with sharding, this needs to be changed
Expand Down
18 changes: 18 additions & 0 deletions test/common/build/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,24 @@ func RunBuildRunningPodDeleteTest(t testingT, clusterAdminClient *client.Client,
if newBuild.Status.Phase != buildapi.BuildPhaseError {
t.Fatalf("expected build status to be marked error, but was marked %s", newBuild.Status.Phase)
}
events, err := clusterAdminKubeClientset.Core().Events(testutil.Namespace()).Search(newBuild)
if err != nil {
t.Fatalf("error getting build events: %v", err)
}
foundFailed := false
for _, event := range events.Items {
switch event.Reason {
case buildapi.BuildFailedEventReason:
foundFailed = true
expect := fmt.Sprintf(buildapi.BuildFailedEventMessage, newBuild.Namespace, newBuild.Name)
if event.Message != expect {
t.Fatalf("expected failed event message to be %s, got %s", expect, event.Message)
}
}
}
if !foundFailed {
t.Fatalf("expected to find a failed event on the build %s/%s", newBuild.Namespace, newBuild.Name)
}
}

func RunBuildCompletePodDeleteTest(t testingT, clusterAdminClient *client.Client, clusterAdminKubeClientset *kclientset.Clientset) {
Expand Down
16 changes: 16 additions & 0 deletions test/extended/builds/failure_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonPostCommitHookFailed))
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessagePostCommitHookFailed))

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
})
})

Expand All @@ -70,6 +72,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonFetchSourceFailed))
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessageFetchSourceFailed))

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
})
})

Expand All @@ -87,6 +91,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonFetchSourceFailed))
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessageFetchSourceFailed))

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
})
})

Expand All @@ -104,6 +110,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonPullBuilderImageFailed))
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessagePullBuilderImageFailed))

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
})
})

Expand All @@ -121,6 +129,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonPushImageToRegistryFailed))
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessagePushImageToRegistryFailed))

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
})
})

Expand All @@ -138,6 +148,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Reason).To(o.Equal(reasonAssembleFailed))
o.Expect(build.Status.Message).To(o.Equal(messageAssembleFailed))

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
})
})

Expand All @@ -155,6 +167,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Reason).To(o.Equal(reasonFetchRuntimeArtifacts))
o.Expect(build.Status.Message).To(o.Equal(messageFetchRuntimeArtifacts))

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
})
})

Expand All @@ -172,6 +186,8 @@ var _ = g.Describe("[builds][Slow] update failure status", func() {
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Reason).To(o.Equal(buildapi.StatusReasonGenericBuildFailed))
o.Expect(build.Status.Message).To(o.Equal(buildapi.StatusMessageGenericBuildFailed))

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)
})
})
})
11 changes: 11 additions & 0 deletions test/extended/builds/s2i_quota.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
g "github.com/onsi/ginkgo"
o "github.com/onsi/gomega"

buildapi "github.com/openshift/origin/pkg/build/api"
exutil "github.com/openshift/origin/test/extended/util"
)

Expand Down Expand Up @@ -52,6 +53,16 @@ var _ = g.Describe("[builds][Conformance] s2i build with a quota", func() {
o.Expect(buildLog).To(o.ContainSubstring("SHARES=61"))
o.Expect(buildLog).To(o.ContainSubstring("PERIOD=100000"))
o.Expect(buildLog).To(o.ContainSubstring("QUOTA=6000"))

events, err := oc.KubeClient().Core().Events(oc.Namespace()).Search(br.Build)
o.Expect(err).NotTo(o.HaveOccurred(), "Should be able to get events from the build")
o.Expect(events).NotTo(o.BeNil(), "Build event list should not be nil")

exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildCreatedEventReason, buildapi.BuildCreatedEventMessage)
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildStartedEventReason, buildapi.BuildStartedEventMessage)
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildRunningEventReason, buildapi.BuildRunningEventMessage)
exutil.CheckForEvent(oc.KubeClient().Core(), br.Build, buildapi.BuildFailedEventReason, buildapi.BuildFailedEventMessage)

})
})
})
7 changes: 6 additions & 1 deletion test/extended/builds/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ var _ = g.Describe("[builds][Slow] starting a build using CLI", func() {
err := exutil.WaitForABuild(oc.Client().Builds(oc.Namespace()), "sample-build-binary-invalidnodeselector-1", nil, nil, cancelFn)
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(build.Status.Phase).To(o.Equal(buildapi.BuildPhaseCancelled))
exutil.CheckForEvent(oc.KubeClient().Core(), build, buildapi.BuildCancelledEventReason, buildapi.BuildCancelledEventMessage)
})
})

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

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

g.By(fmt.Sprintf("cancelling the build %q", buildName))
err := oc.Run("cancel-build").Args(buildName).Execute()
err = oc.Run("cancel-build").Args(buildName).Execute()
o.Expect(err).ToNot(o.HaveOccurred())
wg.Wait()
})
Expand Down
16 changes: 16 additions & 0 deletions test/extended/util/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -1400,3 +1400,19 @@ func CreateExecPodOnNode(client kcoreclient.CoreInterface, ns, nodeName, name st
o.Expect(err).NotTo(o.HaveOccurred())
return created.Name
}

func CheckForEvent(client kcoreclient.CoreInterface, build *buildapi.Build, reason, message string) {
events, err := client.Events(build.Namespace).Search(build)
o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred(), "Should be able to get events from the build")
o.ExpectWithOffset(1, events).NotTo(o.BeNil(), "Build event list should not be nil")

failed := false
for _, event := range events.Items {
switch event.Reason {
case reason:
failed = true
o.ExpectWithOffset(1, event.Message).To(o.Equal(fmt.Sprintf(message, build.Namespace, build.Name)))
}
}
o.ExpectWithOffset(1, failed).To(o.BeTrue(), "Did not find a %q event on build %s/%s", reason, build.Namespace, build.Name)
}

0 comments on commit be1c042

Please sign in to comment.