From c07f7c594117eb07ef61f6c39458e35ec4ec0fd9 Mon Sep 17 00:00:00 2001 From: Prajyot-Parab Date: Wed, 13 Apr 2022 14:31:53 +0530 Subject: [PATCH] Add events recorder framework Signed-off-by: Prajyot-Parab --- cloud/scope/cluster.go | 30 +++++++++ cloud/scope/machine.go | 11 ++++ cloud/scope/powervs_image.go | 19 +++++- cloud/scope/powervs_machine.go | 12 +++- controllers/ibmpowervscluster_controller.go | 6 +- controllers/ibmpowervsimage_controller.go | 6 +- controllers/ibmpowervsmachine_controller.go | 6 +- controllers/ibmvpccluster_controller.go | 6 +- controllers/ibmvpcmachine_controller.go | 6 +- go.mod | 2 +- main.go | 47 +++++++++----- pkg/record/doc.go | 18 ++++++ pkg/record/record.go | 70 +++++++++++++++++++++ 13 files changed, 210 insertions(+), 29 deletions(-) create mode 100644 pkg/record/doc.go create mode 100644 pkg/record/record.go diff --git a/cloud/scope/cluster.go b/cloud/scope/cluster.go index e4f0b2035..32a78ed1a 100644 --- a/cloud/scope/cluster.go +++ b/cloud/scope/cluster.go @@ -30,6 +30,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" infrav1beta1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta1" + "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/record" ) // ClusterScopeParams defines the input parameters used to create a new ClusterScope. @@ -102,10 +103,13 @@ func (s *ClusterScope) CreateVPC() (*vpcv1.VPC, error) { options.SetName(s.IBMVPCCluster.Spec.VPC) vpc, _, err := s.IBMVPCClients.VPCService.CreateVPC(options) if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedCreateVPC", "Failed vpc creation - %v", err) return nil, err } else if err := s.updateDefaultSG(*vpc.DefaultSecurityGroup.ID); err != nil { + record.Warnf(s.IBMVPCCluster, "FailedUpdateDefaultSecurityGroup", "Failed to update default security group - %v", err) return nil, err } + record.Eventf(s.IBMVPCCluster, "SuccessfulCreateVPC", "Created VPC %q", *vpc.Name) return vpc, nil } @@ -114,6 +118,11 @@ func (s *ClusterScope) DeleteVPC() error { deleteVpcOptions := &vpcv1.DeleteVPCOptions{} deleteVpcOptions.SetID(s.IBMVPCCluster.Status.VPC.ID) _, err := s.IBMVPCClients.VPCService.DeleteVPC(deleteVpcOptions) + if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedDeleteVPC", "Failed vpc deletion - %v", err) + } else { + record.Eventf(s.IBMVPCCluster, "SuccessfulDeleteVPC", "Deleted VPC %q", s.IBMVPCCluster.Status.VPC.Name) + } return err } @@ -141,6 +150,9 @@ func (s *ClusterScope) updateDefaultSG(sgID string) error { IPVersion: core.StringPtr("ipv4"), }) _, _, err := s.IBMVPCClients.VPCService.CreateSecurityGroupRule(options) + if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedCreateSecurityGroupRule", "Failed security group rule creation - %v", err) + } return err } @@ -167,6 +179,9 @@ func (s *ClusterScope) ReserveFIP() (*vpcv1.FloatingIP, error) { }) floatingIP, _, err := s.IBMVPCClients.VPCService.CreateFloatingIP(options) + if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedCreateFloatingIP", "Failed floatingIP creation - %v", err) + } return floatingIP, err } @@ -190,6 +205,9 @@ func (s *ClusterScope) DeleteFloatingIP() error { deleteFIPOption := &vpcv1.DeleteFloatingIPOptions{} deleteFIPOption.SetID(fipID) _, err := s.IBMVPCClients.VPCService.DeleteFloatingIP(deleteFIPOption) + if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedDeleteFloatingIP", "Failed floatingIP deletion - %v", err) + } return err } return nil @@ -226,6 +244,9 @@ func (s *ClusterScope) CreateSubnet() (*vpcv1.Subnet, error) { }, }) subnet, _, err := s.IBMVPCClients.VPCService.CreateSubnet(options) + if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedCreateSubnet", "Failed subnet creation - %v", err) + } if subnet != nil { pgw, err := s.createPublicGateWay(s.IBMVPCCluster.Status.VPC.ID, s.IBMVPCCluster.Spec.Zone, s.IBMVPCCluster.Spec.ResourceGroup) if err != nil { @@ -293,6 +314,7 @@ func (s *ClusterScope) DeleteSubnet() error { deleteSubnetOption.SetID(subnetID) _, err = s.IBMVPCClients.VPCService.DeleteSubnet(deleteSubnetOption) if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedDeleteSubnet", "Failed subnet deletion - %v", err) return errors.Wrap(err, "Error when deleting subnet ") } return err @@ -310,6 +332,9 @@ func (s *ClusterScope) createPublicGateWay(vpcID string, zoneName string, resour ID: &resourceGroupID, }) publicGateway, _, err := s.IBMVPCClients.VPCService.CreatePublicGateway(options) + if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedCreatePublicGateway", "Failed publicgateway creation - %v", err) + } return publicGateway, err } @@ -320,6 +345,9 @@ func (s *ClusterScope) attachPublicGateWay(subnetID string, pgwID string) (*vpcv ID: &pgwID, }) publicGateway, _, err := s.IBMVPCClients.VPCService.SetSubnetPublicGateway(options) + if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedAttachPublicGateway", "Failed publicgateway attachment - %v", err) + } return publicGateway, err } @@ -329,6 +357,7 @@ func (s *ClusterScope) detachPublicGateway(subnetID string, pgwID string) error unsetPGWOption.SetID(subnetID) _, err := s.IBMVPCClients.VPCService.UnsetSubnetPublicGateway(unsetPGWOption) if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedDetachPublicGateway", "Failed publicgateway detachment - %v", err) return errors.Wrap(err, "Error when unsetting publicgateway for subnet "+subnetID) } @@ -337,6 +366,7 @@ func (s *ClusterScope) detachPublicGateway(subnetID string, pgwID string) error deletePGWOption.SetID(pgwID) _, err = s.IBMVPCClients.VPCService.DeletePublicGateway(deletePGWOption) if err != nil { + record.Warnf(s.IBMVPCCluster, "FailedDeletePublicGateway", "Failed publicgateway deletion - %v", err) return errors.Wrap(err, "Error when deleting publicgateway for subnet "+subnetID) } return err diff --git a/cloud/scope/machine.go b/cloud/scope/machine.go index ea22aa5f8..11c23eeaf 100644 --- a/cloud/scope/machine.go +++ b/cloud/scope/machine.go @@ -32,6 +32,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" infrav1beta1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta1" + "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/record" ) // MachineScopeParams defines the input parameters used to create a new MachineScope. @@ -143,6 +144,11 @@ func (m *MachineScope) CreateMachine() (*vpcv1.Instance, error) { options.SetInstancePrototype(instancePrototype) instance, response, err := m.IBMVPCClients.VPCService.CreateInstance(options) + if err != nil { + record.Warnf(m.IBMVPCMachine, "FailedCreateInstance", "Failed instance creation - %v", err) + } else { + record.Eventf(m.IBMVPCMachine, "SuccessfulCreateInstance", "Created Instance %q", *instance.Name) + } fmt.Printf("%v\n", response) return instance, err } @@ -152,6 +158,11 @@ func (m *MachineScope) DeleteMachine() error { options := &vpcv1.DeleteInstanceOptions{} options.SetID(m.IBMVPCMachine.Status.InstanceID) _, err := m.IBMVPCClients.VPCService.DeleteInstance(options) + if err != nil { + record.Warnf(m.IBMVPCMachine, "FailedDeleteInstance", "Failed instance deletion - %v", err) + } else { + record.Eventf(m.IBMVPCMachine, "SuccessfulDeleteInstance", "Deleted Instance %q", m.IBMVPCMachine.Name) + } return err } diff --git a/cloud/scope/powervs_image.go b/cloud/scope/powervs_image.go index 27d0dab74..dd037e893 100644 --- a/cloud/scope/powervs_image.go +++ b/cloud/scope/powervs_image.go @@ -36,6 +36,7 @@ import ( "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/powervs" "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/resourcecontroller" servicesutils "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/utils" + "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/record" ) // BucketAccess indicates if the bucket has public or private access public access. @@ -160,9 +161,11 @@ func (i *PowerVSImageScope) CreateImageCOSBucket() (*models.ImageReference, *mod imageReply, err := i.ensureImageUnique(m.Name) if err != nil { + record.Warnf(i.IBMPowerVSImage, "FailedRetriveImage", "Failed to retrieve image %q", *imageReply.Name) return nil, nil, err } else if imageReply != nil { i.Info("Image already exists") + record.Eventf(i.IBMPowerVSImage, "SuccessfulRetriveImage", "Retrieved Image %q", *imageReply.Name) return imageReply, nil, nil } @@ -185,9 +188,11 @@ func (i *PowerVSImageScope) CreateImageCOSBucket() (*models.ImageReference, *mod jobRef, err := i.IBMPowerVSClient.CreateCosImage(body) if err != nil { i.Info("Unable to create new import job request") + record.Warnf(i.IBMPowerVSImage, "FailedCreateImageImportJob", "Failed image import job creation - %v", err) return nil, nil, err } i.Info("New import job request created") + record.Eventf(i.IBMPowerVSImage, "SuccessfulCreateImageImportJob", "Created image import job %q", *jobRef.ID) return nil, jobRef, nil } @@ -203,7 +208,12 @@ func (i *PowerVSImageScope) Close() error { // DeleteImage will delete the image. func (i *PowerVSImageScope) DeleteImage() error { - return i.IBMPowerVSClient.DeleteImage(i.IBMPowerVSImage.Status.ImageID) + if err := i.IBMPowerVSClient.DeleteImage(i.IBMPowerVSImage.Status.ImageID); err != nil { + record.Warnf(i.IBMPowerVSImage, "FailedDeleteImage", "Failed image deletion - %v", err) + return err + } + record.Eventf(i.IBMPowerVSImage, "SuccessfulDeleteImage", "Deleted Image %q", i.IBMPowerVSImage.Status.ImageID) + return nil } // GetImportJob will get the image import job. @@ -213,7 +223,12 @@ func (i *PowerVSImageScope) GetImportJob() (*models.Job, error) { // DeleteImportJob will delete the image import job. func (i *PowerVSImageScope) DeleteImportJob() error { - return i.IBMPowerVSClient.DeleteJob(i.IBMPowerVSImage.Status.JobID) + if err := i.IBMPowerVSClient.DeleteJob(i.IBMPowerVSImage.Status.JobID); err != nil { + record.Warnf(i.IBMPowerVSImage, "FailedDeleteImageImoprtJob", "Failed image import job deletion - %v", err) + return err + } + record.Eventf(i.IBMPowerVSImage, "SuccessfulDeleteImageImoprtJob", "Deleted image import job %q", i.IBMPowerVSImage.Status.JobID) + return nil } // SetReady will set the status as ready for the image. diff --git a/cloud/scope/powervs_machine.go b/cloud/scope/powervs_machine.go index b62307f02..74480b0de 100644 --- a/cloud/scope/powervs_machine.go +++ b/cloud/scope/powervs_machine.go @@ -45,6 +45,7 @@ import ( "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/resourcecontroller" servicesutils "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/utils" "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/options" + "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/record" ) // PowerVSMachineScopeParams defines the input parameters used to create a new PowerVSMachineScope. @@ -213,12 +214,14 @@ func (m *PowerVSMachineScope) CreateMachine() (*models.PVMInstanceReference, err } else { imageID, err = getImageID(s.Image, m) if err != nil { + record.Warnf(m.IBMPowerVSMachine, "FailedRetriveImage", "Failed image retrival - %v", err) return nil, fmt.Errorf("error getting image ID: %v", err) } } networkID, err := getNetworkID(s.Network, m) if err != nil { + record.Warnf(m.IBMPowerVSMachine, "FailedRetriveNetwork", "Failed network retrival - %v", err) return nil, fmt.Errorf("error getting network ID: %v", err) } @@ -242,8 +245,10 @@ func (m *PowerVSMachineScope) CreateMachine() (*models.PVMInstanceReference, err } _, err = m.IBMPowerVSClient.CreateInstance(params.Body) if err != nil { + record.Warnf(m.IBMPowerVSMachine, "FailedCreateInstance", "Failed instance creation - %v", err) return nil, err } + record.Eventf(m.IBMPowerVSMachine, "SuccessfulCreateInstance", "Created Instance %q", m.IBMPowerVSMachine.Name) return nil, nil } @@ -259,7 +264,12 @@ func (m *PowerVSMachineScope) PatchObject() error { // DeleteMachine deletes the power vs machine associated with machine instance id and service instance id. func (m *PowerVSMachineScope) DeleteMachine() error { - return m.IBMPowerVSClient.DeleteInstance(m.IBMPowerVSMachine.Status.InstanceID) + if err := m.IBMPowerVSClient.DeleteInstance(m.IBMPowerVSMachine.Status.InstanceID); err != nil { + record.Warnf(m.IBMPowerVSMachine, "FailedDeleteInstance", "Failed instance deletion - %v", err) + return err + } + record.Eventf(m.IBMPowerVSMachine, "SuccessfulDeleteInstance", "Deleted Instance %q", m.IBMPowerVSMachine.Name) + return nil } // GetBootstrapData returns the base64 encoded bootstrap data from the secret in the Machine's bootstrap.dataSecretName. diff --git a/controllers/ibmpowervscluster_controller.go b/controllers/ibmpowervscluster_controller.go index a2db0656f..40118e16d 100644 --- a/controllers/ibmpowervscluster_controller.go +++ b/controllers/ibmpowervscluster_controller.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" kerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/client-go/tools/record" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util" ctrl "sigs.k8s.io/controller-runtime" @@ -41,8 +42,9 @@ import ( // IBMPowerVSClusterReconciler reconciles a IBMPowerVSCluster object. type IBMPowerVSClusterReconciler struct { client.Client - Log logr.Logger - Scheme *runtime.Scheme + Log logr.Logger + Recorder record.EventRecorder + Scheme *runtime.Scheme } // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=ibmpowervsclusters,verbs=get;list;watch;create;update;patch;delete diff --git a/controllers/ibmpowervsimage_controller.go b/controllers/ibmpowervsimage_controller.go index f474d10b2..d68e59fea 100644 --- a/controllers/ibmpowervsimage_controller.go +++ b/controllers/ibmpowervsimage_controller.go @@ -27,6 +27,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" clusterv1util "sigs.k8s.io/cluster-api/util" "sigs.k8s.io/cluster-api/util/conditions" @@ -43,8 +44,9 @@ import ( // IBMPowerVSImageReconciler reconciles a IBMPowerVSImage object. type IBMPowerVSImageReconciler struct { client.Client - Log logr.Logger - Scheme *runtime.Scheme + Log logr.Logger + Recorder record.EventRecorder + Scheme *runtime.Scheme } //+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=ibmpowervsimages,verbs=get;list;watch;create;update;patch;delete diff --git a/controllers/ibmpowervsmachine_controller.go b/controllers/ibmpowervsmachine_controller.go index 67ae45cb4..2c9d2d561 100644 --- a/controllers/ibmpowervsmachine_controller.go +++ b/controllers/ibmpowervsmachine_controller.go @@ -25,6 +25,7 @@ import ( "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util" "sigs.k8s.io/cluster-api/util/conditions" @@ -39,8 +40,9 @@ import ( // IBMPowerVSMachineReconciler reconciles a IBMPowerVSMachine object. type IBMPowerVSMachineReconciler struct { client.Client - Log logr.Logger - Scheme *runtime.Scheme + Log logr.Logger + Recorder record.EventRecorder + Scheme *runtime.Scheme } // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=ibmpowervsmachines,verbs=get;list;watch;create;update;patch;delete diff --git a/controllers/ibmvpccluster_controller.go b/controllers/ibmvpccluster_controller.go index 8dbb666f2..f91ae022c 100644 --- a/controllers/ibmvpccluster_controller.go +++ b/controllers/ibmvpccluster_controller.go @@ -24,6 +24,7 @@ import ( "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util" "sigs.k8s.io/cluster-api/util/predicates" @@ -40,8 +41,9 @@ import ( // IBMVPCClusterReconciler reconciles a IBMVPCCluster object. type IBMVPCClusterReconciler struct { client.Client - Log logr.Logger - Scheme *runtime.Scheme + Log logr.Logger + Recorder record.EventRecorder + Scheme *runtime.Scheme } // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=ibmvpcclusters,verbs=get;list;watch;create;update;patch;delete diff --git a/controllers/ibmvpcmachine_controller.go b/controllers/ibmvpcmachine_controller.go index 0445aa95b..7919af1ee 100644 --- a/controllers/ibmvpcmachine_controller.go +++ b/controllers/ibmvpcmachine_controller.go @@ -26,6 +26,7 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" "k8s.io/utils/pointer" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util" @@ -41,8 +42,9 @@ import ( // IBMVPCMachineReconciler reconciles a IBMVPCMachine object. type IBMVPCMachineReconciler struct { client.Client - Log logr.Logger - Scheme *runtime.Scheme + Log logr.Logger + Recorder record.EventRecorder + Scheme *runtime.Scheme } // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=ibmvpcmachines,verbs=get;list;watch;create;update;patch;delete diff --git a/go.mod b/go.mod index 4957c135d..a82a0878b 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/ppc64le-cloud/powervs-utils v0.0.0-20210415051532-4cdd6a79c8fa github.com/spf13/pflag v1.0.5 + golang.org/x/text v0.3.7 k8s.io/api v0.23.5 k8s.io/apimachinery v0.23.5 k8s.io/client-go v0.23.5 @@ -121,7 +122,6 @@ require ( golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/main.go b/main.go index 6cd2dea59..265413389 100644 --- a/main.go +++ b/main.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + cgrecord "k8s.io/client-go/tools/record" "k8s.io/klog/v2" "k8s.io/klog/v2/klogr" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -37,6 +38,7 @@ import ( infrav1beta1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta1" "sigs.k8s.io/cluster-api-provider-ibmcloud/controllers" "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/options" + "sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/record" ) var ( @@ -78,6 +80,12 @@ func main() { setupLog.Info("Watching cluster-api objects only in namespace for reconciliation", "namespace", watchNamespace) } + // Machine and cluster operations can create enough events to trigger the event recorder spam filter + // Setting the burst size higher ensures all events will be recorded and submitted to the API + broadcaster := cgrecord.NewBroadcasterWithCorrelatorOptions(cgrecord.CorrelatorOptions{ + BurstSize: 100, + }) + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, MetricsBindAddress: metricsAddr, @@ -86,6 +94,7 @@ func main() { LeaderElectionID: "effcf9b8.cluster.x-k8s.io", SyncPeriod: &syncPeriod, Namespace: watchNamespace, + EventBroadcaster: broadcaster, HealthProbeBindAddress: healthAddr, }) if err != nil { @@ -93,34 +102,41 @@ func main() { os.Exit(1) } + // Initialize event recorder. + record.InitFromRecorder(mgr.GetEventRecorderFor("ibmcloud-controller")) + if err = (&controllers.IBMVPCClusterReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("IBMVPCCluster"), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("IBMVPCCluster"), + Recorder: mgr.GetEventRecorderFor("ibmvpccluster-controller"), + Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "IBMVPCCluster") os.Exit(1) } if err = (&controllers.IBMVPCMachineReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("IBMVPCMachine"), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("IBMVPCMachine"), + Recorder: mgr.GetEventRecorderFor("ibmvpcmachine-controller"), + Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "IBMVPCMachine") os.Exit(1) } if err = (&controllers.IBMPowerVSClusterReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("IBMPowerVSCluster"), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("IBMPowerVSCluster"), + Recorder: mgr.GetEventRecorderFor("ibmpowervscluster-controller"), + Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "IBMPowerVSCluster") os.Exit(1) } if err = (&controllers.IBMPowerVSMachineReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("IBMPowerVSMachine"), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("IBMPowerVSMachine"), + Recorder: mgr.GetEventRecorderFor("ibmpowervsmachine-controller"), + Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "IBMPowerVSMachine") os.Exit(1) @@ -150,9 +166,10 @@ func main() { os.Exit(1) } if err = (&controllers.IBMPowerVSImageReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("IBMPowerVSImage"), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("IBMPowerVSImage"), + Recorder: mgr.GetEventRecorderFor("ibmpowervsimage-controller"), + Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "IBMPowerVSImage") os.Exit(1) diff --git a/pkg/record/doc.go b/pkg/record/doc.go new file mode 100644 index 000000000..8f5bf5026 --- /dev/null +++ b/pkg/record/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package record implements record framework code. +package record diff --git a/pkg/record/record.go b/pkg/record/record.go new file mode 100644 index 000000000..6182915d0 --- /dev/null +++ b/pkg/record/record.go @@ -0,0 +1,70 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package record + +import ( + "sync" + + "golang.org/x/text/cases" + "golang.org/x/text/language" + corev1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cgrecord "k8s.io/client-go/tools/record" +) + +var ( + initOnce sync.Once + defaultRecorder cgrecord.EventRecorder +) + +func init() { + defaultRecorder = new(cgrecord.FakeRecorder) +} + +// InitFromRecorder initializes the global default recorder. It can only be called once. +// Subsequent calls are considered noops. +func InitFromRecorder(recorder cgrecord.EventRecorder) { + initOnce.Do(func() { + defaultRecorder = recorder + }) +} + +// Event constructs an event from the given information and puts it in the queue for sending. +func Event(object runtime.Object, reason, message string) { + defaultRecorder.Event(object, corev1.EventTypeNormal, title(reason), message) +} + +// Eventf is just like Event, but with Sprintf for the message field. +func Eventf(object runtime.Object, reason, message string, args ...interface{}) { + defaultRecorder.Eventf(object, corev1.EventTypeNormal, title(reason), message, args...) +} + +// Warn constructs a warning event from the given information and puts it in the queue for sending. +func Warn(object runtime.Object, reason, message string) { + defaultRecorder.Event(object, corev1.EventTypeWarning, title(reason), message) +} + +// Warnf is just like Event, but with Sprintf for the message field. +func Warnf(object runtime.Object, reason, message string, args ...interface{}) { + defaultRecorder.Eventf(object, corev1.EventTypeWarning, title(reason), message, args...) +} + +// title returns a copy of the string s with all Unicode letters that begin words +// mapped to their Unicode title case. +func title(source string) string { + return cases.Title(language.Und, cases.NoLower).String(source) +}