From 3c02243ee93131cc669b38eba85a271afc81a4ea Mon Sep 17 00:00:00 2001 From: Meng Yan Date: Thu, 11 Jul 2024 21:42:03 +0800 Subject: [PATCH 01/67] Consumer deletion (#154) * add consumer deletion Signed-off-by: myan * add test Signed-off-by: myan * fix e2e Signed-off-by: myan * trigger e2e Signed-off-by: myan * update the error type Signed-off-by: myan * add comment Signed-off-by: myan * creating resource when delete the consumer Signed-off-by: myan * update comment Signed-off-by: myan * create resource asyc Signed-off-by: myan * add conmment Signed-off-by: myan * comment the soft delete code Signed-off-by: myan * remove the unused soft deletion Signed-off-by: myan * move consumer deletion from after all Signed-off-by: myan * rerun Signed-off-by: myan * rerun Signed-off-by: myan --------- Signed-off-by: myan --- cmd/maestro/environments/service_types.go | 1 + cmd/maestro/server/routes.go | 2 +- pkg/dao/consumer.go | 8 +- pkg/dao/mocks/consumer.go | 2 +- pkg/dao/mocks/resource.go | 4 + pkg/dao/resource.go | 13 ++ pkg/handlers/consumer.go | 12 +- pkg/services/consumer.go | 12 +- pkg/services/util.go | 3 + test/e2e/pkg/consumer_test.go | 60 +++++-- test/integration/consumers_test.go | 198 ++++++++++++++++++++++ 11 files changed, 294 insertions(+), 21 deletions(-) diff --git a/cmd/maestro/environments/service_types.go b/cmd/maestro/environments/service_types.go index f47a2b41..7d62864f 100755 --- a/cmd/maestro/environments/service_types.go +++ b/cmd/maestro/environments/service_types.go @@ -49,6 +49,7 @@ func NewConsumerServiceLocator(env *Env) ConsumerServiceLocator { return services.NewConsumerService( db.NewAdvisoryLockFactory(env.Database.SessionFactory), dao.NewConsumerDao(&env.Database.SessionFactory), + dao.NewResourceDao(&env.Database.SessionFactory), env.Services.Events(), ) } diff --git a/cmd/maestro/server/routes.go b/cmd/maestro/server/routes.go index 4be41cc4..8cbaad36 100755 --- a/cmd/maestro/server/routes.go +++ b/cmd/maestro/server/routes.go @@ -23,7 +23,7 @@ func (s *apiServer) routes() *mux.Router { } resourceHandler := handlers.NewResourceHandler(services.Resources(), services.Generic()) - consumerHandler := handlers.NewConsumerHandler(services.Consumers(), services.Generic()) + consumerHandler := handlers.NewConsumerHandler(services.Consumers(), services.Resources(), services.Generic()) errorsHandler := handlers.NewErrorsHandler() var authMiddleware auth.JWTMiddleware diff --git a/pkg/dao/consumer.go b/pkg/dao/consumer.go index 32222973..e9aa9785 100644 --- a/pkg/dao/consumer.go +++ b/pkg/dao/consumer.go @@ -13,7 +13,7 @@ type ConsumerDao interface { Get(ctx context.Context, id string) (*api.Consumer, error) Create(ctx context.Context, consumer *api.Consumer) (*api.Consumer, error) Replace(ctx context.Context, consumer *api.Consumer) (*api.Consumer, error) - Delete(ctx context.Context, id string) error + Delete(ctx context.Context, id string, unscoped bool) error FindByIDs(ctx context.Context, ids []string) (api.ConsumerList, error) All(ctx context.Context) (api.ConsumerList, error) } @@ -55,8 +55,12 @@ func (d *sqlConsumerDao) Replace(ctx context.Context, consumer *api.Consumer) (* return consumer, nil } -func (d *sqlConsumerDao) Delete(ctx context.Context, id string) error { +func (d *sqlConsumerDao) Delete(ctx context.Context, id string, unscoped bool) error { g2 := (*d.sessionFactory).New(ctx) + if unscoped { + // Unscoped is used to permanently delete the record + g2 = g2.Unscoped() + } if err := g2.Omit(clause.Associations).Delete(&api.Consumer{Meta: api.Meta{ID: id}}).Error; err != nil { db.MarkForRollback(ctx, err) return err diff --git a/pkg/dao/mocks/consumer.go b/pkg/dao/mocks/consumer.go index 93033dd4..83b82c30 100644 --- a/pkg/dao/mocks/consumer.go +++ b/pkg/dao/mocks/consumer.go @@ -38,7 +38,7 @@ func (d *consumerDaoMock) Replace(ctx context.Context, consumer *api.Consumer) ( return nil, errors.NotImplemented("Consumer").AsError() } -func (d *consumerDaoMock) Delete(ctx context.Context, id string) error { +func (d *consumerDaoMock) Delete(ctx context.Context, id string, unscoped bool) error { return errors.NotImplemented("Consumer").AsError() } diff --git a/pkg/dao/mocks/resource.go b/pkg/dao/mocks/resource.go index 4b3565db..5ad5946b 100755 --- a/pkg/dao/mocks/resource.go +++ b/pkg/dao/mocks/resource.go @@ -81,3 +81,7 @@ func (d *resourceDaoMock) FindBySource(ctx context.Context, source string) (api. func (d *resourceDaoMock) All(ctx context.Context) (api.ResourceList, error) { return d.resources, nil } + +func (d *resourceDaoMock) FirstByConsumerName(ctx context.Context, consumerName string, unscoped bool) (api.Resource, error) { + return *d.resources[0], errors.NotImplemented("Resource").AsError() +} diff --git a/pkg/dao/resource.go b/pkg/dao/resource.go index fabf9add..5ce0c287 100755 --- a/pkg/dao/resource.go +++ b/pkg/dao/resource.go @@ -19,6 +19,7 @@ type ResourceDao interface { FindBySource(ctx context.Context, source string) (api.ResourceList, error) FindByConsumerName(ctx context.Context, consumerName string) (api.ResourceList, error) All(ctx context.Context) (api.ResourceList, error) + FirstByConsumerName(ctx context.Context, name string, unscoped bool) (api.Resource, error) } var _ ResourceDao = &sqlResourceDao{} @@ -115,3 +116,15 @@ func (d *sqlResourceDao) All(ctx context.Context) (api.ResourceList, error) { } return resources, nil } + +// FirstByConsumerName will take the first item of the resources on the consumer. it can be used to determine whether the resource exists for the consumer. +func (d *sqlResourceDao) FirstByConsumerName(ctx context.Context, consumerName string, unscoped bool) (api.Resource, error) { + g2 := (*d.sessionFactory).New(ctx) + if unscoped { + // Unscoped is used to find the deleting resources + g2 = g2.Unscoped() + } + resource := api.Resource{} + err := g2.Where("consumer_name = ?", consumerName).First(&resource).Error + return resource, err +} diff --git a/pkg/handlers/consumer.go b/pkg/handlers/consumer.go index a9b08006..cc3bb58f 100644 --- a/pkg/handlers/consumer.go +++ b/pkg/handlers/consumer.go @@ -17,12 +17,14 @@ var _ RestHandler = consumerHandler{} type consumerHandler struct { consumer services.ConsumerService + resource services.ResourceService generic services.GenericService } -func NewConsumerHandler(consumer services.ConsumerService, generic services.GenericService) *consumerHandler { +func NewConsumerHandler(consumer services.ConsumerService, resource services.ResourceService, generic services.GenericService) *consumerHandler { return &consumerHandler{ consumer: consumer, + resource: resource, generic: generic, } } @@ -84,7 +86,7 @@ func (h consumerHandler) List(w http.ResponseWriter, r *http.Request) { ctx := r.Context() listArgs := services.NewListArguments(r.URL.Query()) - var consumers = []api.Consumer{} + consumers := []api.Consumer{} paging, err := h.generic.List(ctx, "username", listArgs, &consumers) if err != nil { return nil, err @@ -135,7 +137,11 @@ func (h consumerHandler) Get(w http.ResponseWriter, r *http.Request) { func (h consumerHandler) Delete(w http.ResponseWriter, r *http.Request) { cfg := &handlerConfig{ Action: func() (interface{}, *errors.ServiceError) { - return nil, errors.NotImplemented("delete") + id := mux.Vars(r)["id"] + if err := h.consumer.Delete(r.Context(), id); err != nil { + return nil, err + } + return nil, nil }, } handleDelete(w, r, cfg, http.StatusNoContent) diff --git a/pkg/services/consumer.go b/pkg/services/consumer.go index d59d0f1e..df1a4b95 100644 --- a/pkg/services/consumer.go +++ b/pkg/services/consumer.go @@ -20,9 +20,10 @@ type ConsumerService interface { FindByIDs(ctx context.Context, ids []string) (api.ConsumerList, *errors.ServiceError) } -func NewConsumerService(lockFactory db.LockFactory, consumerDao dao.ConsumerDao, events EventService) ConsumerService { +func NewConsumerService(lockFactory db.LockFactory, consumerDao dao.ConsumerDao, resourceDao dao.ResourceDao, events EventService) ConsumerService { return &sqlConsumerService{ consumerDao: consumerDao, + resourceDao: resourceDao, } } @@ -30,6 +31,7 @@ var _ ConsumerService = &sqlConsumerService{} type sqlConsumerService struct { consumerDao dao.ConsumerDao + resourceDao dao.ResourceDao } func (s *sqlConsumerService) Get(ctx context.Context, id string) (*api.Consumer, *errors.ServiceError) { @@ -62,9 +64,13 @@ func (s *sqlConsumerService) Replace(ctx context.Context, consumer *api.Consumer return consumer, nil } +// Delete will remove the consumer from the storage: +// 1. Perform a hard delete on the consumer, the resource creation will be blocked after it. +// 2. Forbid consumer deletion if there are associated resources(include the marked as deleted resources). +// TODO: Add deletion options or strategies. func (s *sqlConsumerService) Delete(ctx context.Context, id string) *errors.ServiceError { - if err := s.consumerDao.Delete(ctx, id); err != nil { - return handleDeleteError("Consumer", errors.GeneralError("Unable to delete consumer: %s", err)) + if err := s.consumerDao.Delete(ctx, id, true); err != nil { + return handleDeleteError("Consumer", err) } return nil } diff --git a/pkg/services/util.go b/pkg/services/util.go index bcd96469..a75f9bc6 100755 --- a/pkg/services/util.go +++ b/pkg/services/util.go @@ -48,6 +48,9 @@ func handleUpdateError(resourceType string, err error) *errors.ServiceError { } func handleDeleteError(resourceType string, err error) *errors.ServiceError { + if strings.Contains(err.Error(), "violates foreign key constraint") { + return errors.Forbidden("Unable to delete %s: %s", resourceType, err) + } return errors.GeneralError("Unable to delete %s: %s", resourceType, err.Error()) } diff --git a/test/e2e/pkg/consumer_test.go b/test/e2e/pkg/consumer_test.go index 35cb3e33..96ed84fb 100644 --- a/test/e2e/pkg/consumer_test.go +++ b/test/e2e/pkg/consumer_test.go @@ -9,27 +9,43 @@ import ( "github.com/openshift-online/maestro/pkg/api/openapi" ) -// go test -v ./test/e2e/pkg -args -api-server=$api_server -consumer-name=$consumer_name -consumer-kubeconfig=$consumer_kubeconfig -ginkgo.focus "Consumer" var _ = Describe("Consumer", Ordered, func() { - var testConsumerName string - var testConsumerID string + var consumer openapi.Consumer + var resourceConsumer openapi.Consumer + var resource openapi.Resource BeforeAll(func() { - testConsumerName = "test-consumer" + consumer = openapi.Consumer{Name: openapi.PtrString("linda")} + resourceConsumer = openapi.Consumer{Name: openapi.PtrString("susan")} + resource = helper.NewAPIResource(*resourceConsumer.Name, 1) }) Context("Consumer CRUD Tests", func() { It("create consumer", func() { - consumer := openapi.Consumer{Name: &testConsumerName} + // create a consumer without resource created, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(consumer).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) Expect(*created.Id).NotTo(BeEmpty()) - testConsumerID = *created.Id + consumer = *created - got, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, testConsumerID).Execute() + got, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumer.Id).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) Expect(got).NotTo(BeNil()) + + // create a consumer with resource + created, resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(resourceConsumer).Execute() + Expect(err).To(Succeed()) + Expect(resp.StatusCode).To(Equal(http.StatusCreated)) + Expect(*created.Id).NotTo(BeEmpty()) + resourceConsumer = *created + + res, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(resource).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusCreated)) + Expect(*res.Id).ShouldNot(BeEmpty()) + Expect(*res.Version).To(Equal(int32(1))) + resource = *res }) It("list consumer", func() { @@ -41,7 +57,7 @@ var _ = Describe("Consumer", Ordered, func() { got := false for _, c := range consumerList.Items { - if *c.Name == testConsumerName { + if *c.Name == *consumer.Name { got = true } } @@ -50,14 +66,14 @@ var _ = Describe("Consumer", Ordered, func() { It("patch consumer", func() { labels := &map[string]string{"hello": "world"} - patched, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdPatch(ctx, testConsumerID). + patched, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdPatch(ctx, *consumer.Id). ConsumerPatchRequest(openapi.ConsumerPatchRequest{Labels: labels}).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) _, ok := patched.GetLabelsOk() Expect(ok).To(BeTrue()) - got, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, testConsumerID).Execute() + got, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumer.Id).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) Expect(got).NotTo(BeNil()) @@ -66,7 +82,29 @@ var _ = Describe("Consumer", Ordered, func() { }) AfterAll(func() { - // TODO: add the consumer deletion + // delete the consumer + resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *consumer.Id).Execute() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + + _, resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumer.Id).Execute() + Expect(err.Error()).To(ContainSubstring("Not Found")) + Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) + + // delete the consumer associated with resource + resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *resourceConsumer.Id).Execute() + Expect(err).To(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusForbidden)) // 403 forbid deletion + + // delete the resource on the consumer + resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource.Id).Execute() + Expect(err).To(Succeed()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + + // only if permanently delete the resource, the consumer can be deleted + resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *resourceConsumer.Id).Execute() + Expect(err).To(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusForbidden)) // 403 forbid deletion }) }) }) diff --git a/test/integration/consumers_test.go b/test/integration/consumers_test.go index adbb7bc6..87cfdbe3 100644 --- a/test/integration/consumers_test.go +++ b/test/integration/consumers_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "sync" "testing" . "github.com/onsi/gomega" @@ -137,6 +138,195 @@ func TestConsumerPatch(t *testing.T) { Expect(restyResp.StatusCode()).To(Equal(http.StatusBadRequest)) } +func TestConsumerDelete(t *testing.T) { + h, client := test.RegisterIntegration(t) + account := h.NewRandAccount() + ctx := h.NewAuthenticatedContext(account) + + // POST responses per openapi spec: 201, 409, 500 + c := openapi.Consumer{ + Name: openapi.PtrString("bazqux"), + } + + // 201 Created + consumer, resp, err := client.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(c).Execute() + Expect(err).NotTo(HaveOccurred(), "Error posting object: %v", err) + Expect(resp.StatusCode).To(Equal(http.StatusCreated)) + Expect(*consumer.Id).NotTo(BeEmpty(), "Expected ID assigned on creation") + + // 200 Got + got, resp, err := client.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumer.Id).Execute() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + Expect(*got.Id).To(Equal(*consumer.Id)) + Expect(*got.Name).To(Equal(*consumer.Name)) + + // 204 Deleted + resp, err = client.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *consumer.Id).Execute() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + + // 404 Not Found + _, resp, err = client.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumer.Id).Execute() + Expect(err.Error()).To(ContainSubstring("Not Found")) + Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) +} + +func TestConsumerDeleteForbidden(t *testing.T) { + h, client := test.RegisterIntegration(t) + account := h.NewRandAccount() + ctx := h.NewAuthenticatedContext(account) + + // create a consumser + c := openapi.Consumer{ + Name: openapi.PtrString("jamie"), + } + consumer, resp, err := client.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(c).Execute() + Expect(err).To(Succeed()) + Expect(resp.StatusCode).To(Equal(http.StatusCreated)) + Expect(*consumer.Id).NotTo(BeEmpty()) + + // attach resource to the consumer + res := h.NewAPIResource(*consumer.Name, 1) + resource, resp, err := client.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() + Expect(err).To(Succeed()) + Expect(resp.StatusCode).To(Equal(http.StatusCreated)) + Expect(*resource.Id).ShouldNot(BeEmpty()) + Expect(*resource.Version).To(Equal(int32(1))) + + // 403 forbid deletion + resp, err = client.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *consumer.Id).Execute() + Expect(err).To(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusForbidden)) + + // delete the resource + resp, err = client.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource.Id).Execute() + Expect(err).To(Succeed()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + + // still forbid deletion for the deleting resource + resp, err = client.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *consumer.Id).Execute() + Expect(err).To(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusForbidden)) +} + +func TestConsumerDeleting(t *testing.T) { + h, client := test.RegisterIntegration(t) + account := h.NewRandAccount() + ctx := h.NewAuthenticatedContext(account) + + // create 10 consumers + consumerNum := 10 + consumerIdToName := map[string]string{} + for i := 0; i < consumerNum; i++ { + consumerName := "tom" + fmt.Sprint(i) + consumer, resp, err := client.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(openapi.Consumer{ + Name: openapi.PtrString(consumerName), + }).Execute() + Expect(err).To(Succeed()) + Expect(resp.StatusCode).To(Equal(http.StatusCreated)) + Expect(*consumer.Id).NotTo(BeEmpty()) + consumerIdToName[*consumer.Id] = consumerName + } + + resourceNum := 10 + resourceCreatorNum := 10 + resourceChan := make(chan *Result, resourceCreatorNum*resourceNum*consumerNum) + consumerChan := make(chan *Result, consumerNum) + + for id, name := range consumerIdToName { + + var wg sync.WaitGroup + // 10 creator for each consumer + for i := 0; i < resourceCreatorNum; i++ { + wg.Add(1) + // each creator create resources to the consumer constantly + go func(name, id string) { + defer wg.Done() + for i := 0; i < resourceNum; i++ { + res := h.NewAPIResource(name, 1) + resource, resp, err := client.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() + resourceChan <- &Result{ + resource: resource, + resp: resp, + consumerName: name, + consumerId: id, + err: err, + } + } + }(name, id) + } + + // delete the consumer when creating resources on it + wg.Add(1) + go func(name, id string) { + defer wg.Done() + resp, err := client.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, id).Execute() + consumerChan <- &Result{ + consumerName: name, + consumerId: id, + resp: resp, + err: err, + } + }(name, id) + + wg.Wait() + } + + // verify the deleting consumer: + // 1. success -> no resources is associated with it + // 2. failed -> resources are associated with it + for i := 0; i < consumerNum; i++ { + result := <-consumerChan + + consumerName := result.consumerName + consumerStatusCode := result.resp.StatusCode + consumerErr := result.err + + search := fmt.Sprintf("consumer_name = '%s'", consumerName) + resourceList, resp, err := client.DefaultApi.ApiMaestroV1ResourcesGet(ctx).Search(search).Execute() + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + Expect(err).To(Succeed()) + + if consumerStatusCode == http.StatusNoContent { + // no resource is assocaited with the consumer + fmt.Println("consumer", consumerName, "deleted successfully!") + Expect(resourceList.Items).To(BeEmpty()) + } else { + // at least one resource on the consumer, the statusCode should be 403 or 500 + fmt.Printf("failed to delete consumer(%s), associated with resource(%d), statusCode: %d, err: %v \n", consumerName, len(resourceList.Items), consumerStatusCode, consumerErr) + Expect(resourceList.Items).NotTo(BeEmpty(), resourceList.Items) + } + } + close(consumerChan) + + // verify the creating resources: + // 1. success: consumer exists + // 2. failed: consumer is deleted + for i := 0; i < consumerNum*resourceNum*resourceCreatorNum; i++ { + result := <-resourceChan + + resourceStatusCode := result.resp.StatusCode + resourceConsumerId := result.consumerId + resourceConsumerName := result.consumerName + + // get the consumer + consumer, resp, err := client.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, resourceConsumerId).Execute() + + if resourceStatusCode == http.StatusCreated { + Expect(err).To(Succeed()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + Expect(*consumer.Id).To(Equal(resourceConsumerId)) + Expect(*consumer.Name).To(Equal(resourceConsumerName)) + } else { + fmt.Printf("failed to create resource on consumer(%s), statusCode: %d, err: %v \n", resourceConsumerName, resourceStatusCode, result.err) + Expect(err.Error()).To(ContainSubstring("Not Found")) + Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) + } + } + close(resourceChan) +} + func TestConsumerPaging(t *testing.T) { h, client := test.RegisterIntegration(t) @@ -162,3 +352,11 @@ func TestConsumerPaging(t *testing.T) { Expect(list.Total).To(Equal(int32(20))) Expect(list.Page).To(Equal(int32(2))) } + +type Result struct { + resource *openapi.Resource + consumerName string + consumerId string + resp *http.Response + err error +} From cbb3d9f57a4b6b09c272dbefc9e362f47115aa41 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Fri, 12 Jul 2024 09:50:39 +0800 Subject: [PATCH 02/67] fix creation and deletion timestamp for work metadata. (#159) * fix creation and deletion timestamp for work metadata. Signed-off-by: morvencao * address comments. Signed-off-by: morvencao --------- Signed-off-by: morvencao --- cmd/maestro/server/grpc_server.go | 56 +++++++++++++++++++++++++------ pkg/api/resource_bundle_types.go | 3 +- pkg/handlers/resource.go | 3 +- pkg/services/resource.go | 44 +++++++++++++++++++++--- 4 files changed, 88 insertions(+), 18 deletions(-) diff --git a/cmd/maestro/server/grpc_server.go b/cmd/maestro/server/grpc_server.go index 82d9f6cf..d043f884 100644 --- a/cmd/maestro/server/grpc_server.go +++ b/cmd/maestro/server/grpc_server.go @@ -2,6 +2,7 @@ package server import ( "context" + "encoding/json" "fmt" "net" "time" @@ -9,12 +10,14 @@ import ( ce "github.com/cloudevents/sdk-go/v2" "github.com/cloudevents/sdk-go/v2/binding" cetypes "github.com/cloudevents/sdk-go/v2/types" + cloudeventstypes "github.com/cloudevents/sdk-go/v2/types" "github.com/golang/glog" "github.com/google/uuid" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" "google.golang.org/protobuf/types/known/emptypb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog/v2" pbv1 "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protobuf/v1" grpcprotocol "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protocol" @@ -121,18 +124,41 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return &emptypb.Empty{}, nil } - res, err := decode(eventType.CloudEventsDataType, evt) - if err != nil { - return nil, fmt.Errorf("failed to decode cloudevent: %v", err) - } - + var res *api.Resource switch eventType.Action { case common.CreateRequestAction: + // set creation timestamp in work metadata + creationTimestamp := time.Now() + if workMeta, ok := evt.Extensions()[codec.ExtensionWorkMeta]; ok { + metaJSON, err := cloudeventstypes.ToString(workMeta) + if err != nil { + return nil, fmt.Errorf("failed to convert work meta extension to json: %v", err) + } + metaObj := metav1.ObjectMeta{} + if err := json.Unmarshal([]byte(metaJSON), &metaObj); err != nil { + return nil, fmt.Errorf("failed to unmarshal work meta extension: %v", err) + } + metaObj.CreationTimestamp = metav1.Time{Time: creationTimestamp} + metaJSONBytes, err := json.Marshal(metaObj) + if err != nil { + return nil, fmt.Errorf("failed to marshal work meta extension: %v", err) + } + evt.SetExtension(codec.ExtensionWorkMeta, string(metaJSONBytes)) + } + res, err = decode(eventType.CloudEventsDataType, evt) + if err != nil { + return nil, fmt.Errorf("failed to decode cloudevent: %v", err) + } + res.Meta.CreatedAt = creationTimestamp _, err := svr.resourceService.Create(ctx, res) if err != nil { return nil, fmt.Errorf("failed to create resource: %v", err) } case common.UpdateRequestAction: + res, err = decode(eventType.CloudEventsDataType, evt) + if err != nil { + return nil, fmt.Errorf("failed to decode cloudevent: %v", err) + } if res.Type == api.ResourceTypeBundle { found, err := svr.resourceService.Get(ctx, res.ID) if err != nil { @@ -150,8 +176,21 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return nil, fmt.Errorf("failed to update resource: %v", err) } case common.DeleteRequestAction: - err := svr.resourceService.MarkAsDeleting(ctx, res.ID) + res, err = decode(eventType.CloudEventsDataType, evt) if err != nil { + return nil, fmt.Errorf("failed to decode cloudevent: %v", err) + } + var deletionTimestamp time.Time + evtExtensions := evt.Context.GetExtensions() + if _, ok := evtExtensions[codec.ExtensionWorkMeta]; ok { + if _, exists := evtExtensions[types.ExtensionDeletionTimestamp]; exists { + // Use the server-generated deletion timestamp from the Maestro server instead of the source client's timestamp + // to account for potential timezone discrepancies between the source client and the Maestro server. + deletionTimestamp = time.Now() + } + } + sErr := svr.resourceService.MarkAsDeleting(ctx, res.ID, deletionTimestamp) + if sErr != nil { return nil, fmt.Errorf("failed to update resource: %v", err) } default: @@ -291,11 +330,6 @@ func encode(resource *api.Resource) (*ce.Event, error) { return nil, err } - // set work meta back from spec event - if workMeta, ok := specEvt.Extensions()[codec.ExtensionWorkMeta]; ok { - evt.SetExtension(codec.ExtensionWorkMeta, workMeta) - } - // set work spec back from spec event manifestBundle := &workpayload.ManifestBundle{} if err := specEvt.DataAs(manifestBundle); err != nil { diff --git a/pkg/api/resource_bundle_types.go b/pkg/api/resource_bundle_types.go index 8ad881fe..84cc8c5a 100755 --- a/pkg/api/resource_bundle_types.go +++ b/pkg/api/resource_bundle_types.go @@ -9,6 +9,7 @@ import ( cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" workpayload "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" + "open-cluster-management.io/sdk-go/pkg/cloudevents/work/source/codec" ) type ResourceBundleStatus struct { @@ -31,7 +32,7 @@ func DecodeManifestBundle(manifest datatypes.JSONMap) (map[string]any, *workpayl metaData := map[string]any{} extensions := evt.Extensions() - if meta, ok := extensions["metadata"]; ok { + if meta, ok := extensions[codec.ExtensionWorkMeta]; ok { metaJson, err := cloudeventstypes.ToString(meta) if err != nil { return nil, nil, err diff --git a/pkg/handlers/resource.go b/pkg/handlers/resource.go index d225e148..c589c891 100755 --- a/pkg/handlers/resource.go +++ b/pkg/handlers/resource.go @@ -3,6 +3,7 @@ package handlers import ( "fmt" "net/http" + "time" "github.com/gorilla/mux" @@ -172,7 +173,7 @@ func (h resourceHandler) Delete(w http.ResponseWriter, r *http.Request) { Action: func() (interface{}, *errors.ServiceError) { id := mux.Vars(r)["id"] ctx := r.Context() - err := h.resource.MarkAsDeleting(ctx, id) + err := h.resource.MarkAsDeleting(ctx, id, time.Time{}) if err != nil { return nil, err } diff --git a/pkg/services/resource.go b/pkg/services/resource.go index 18a415c7..76c3a122 100755 --- a/pkg/services/resource.go +++ b/pkg/services/resource.go @@ -4,11 +4,13 @@ import ( "context" "fmt" "reflect" + "time" cloudeventstypes "github.com/cloudevents/sdk-go/v2/types" "github.com/openshift-online/maestro/pkg/dao" "github.com/openshift-online/maestro/pkg/db" logger "github.com/openshift-online/maestro/pkg/logger" + "gorm.io/gorm" cegeneric "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" @@ -23,7 +25,7 @@ type ResourceService interface { Create(ctx context.Context, resource *api.Resource) (*api.Resource, *errors.ServiceError) Update(ctx context.Context, resource *api.Resource) (*api.Resource, *errors.ServiceError) UpdateStatus(ctx context.Context, resource *api.Resource) (*api.Resource, bool, *errors.ServiceError) - MarkAsDeleting(ctx context.Context, id string) *errors.ServiceError + MarkAsDeleting(ctx context.Context, id string, deletionTimestamp time.Time) *errors.ServiceError Delete(ctx context.Context, id string) *errors.ServiceError All(ctx context.Context) (api.ResourceList, *errors.ServiceError) @@ -214,16 +216,48 @@ func (s *sqlResourceService) UpdateStatus(ctx context.Context, resource *api.Res return updated, true, nil } -// MarkAsDeleting marks the resource as deleting by setting the delete_at timestamp. +// MarkAsDeleting marks the resource as deleting by setting the deletion timestamp. +// There are two cases: +// 1. If deletionTimestamp is not provided, the resource will be deleted and the deleteAt +// will be set by the database. +// 2. If deletionTimestamp is provided, the resource will be marked as deleting in both +// the deleteAt field and deletionTimestamp in the work metadata before deletion. +// // The Resource Deletion Flow: // 1. User requests deletion // 2. Maestro marks resource as deleting by soft delete, adds delete event to DB // 3. Maestro handles delete event and sends CloudEvent to work-agent // 4. Work-agent deletes resource, sends CloudEvent back to Maestro // 5. Maestro hard deletes resource from DB -func (s *sqlResourceService) MarkAsDeleting(ctx context.Context, id string) *errors.ServiceError { - if err := s.resourceDao.Delete(ctx, id, false); err != nil { - return handleDeleteError("Resource", errors.GeneralError("Unable to delete resource: %s", err)) +func (s *sqlResourceService) MarkAsDeleting(ctx context.Context, id string, deletionTimestamp time.Time) *errors.ServiceError { + if deletionTimestamp.IsZero() { + // If deletionTimestamp is not provided, delete the resource immediately. + // The database deletion mechanism ensures the deleteAt field of the resource is set. + if err := s.resourceDao.Delete(ctx, id, false); err != nil { + return handleDeleteError("Resource", errors.GeneralError("Unable to delete resource: %s", err)) + } + } else { + // If deletionTimestamp is provided, the resource will be marked as deleting in both + // the deleteAt field and deletionTimestamp in the work metadata before deletion. + found, err := s.resourceDao.Get(ctx, id) + if err != nil { + return handleGetError("Resource", "id", id, err) + } + // set deletionTimestamp in work metadata + workMetaValue, ok := found.Payload["metadata"] + if ok { + workMeta, ok := workMetaValue.(map[string]interface{}) + if ok { + workMeta["deletionTimestamp"] = deletionTimestamp.Format(time.RFC3339) + found.Payload["metadata"] = workMeta + } + } + // set deletedAt in resource meta + found.DeletedAt = gorm.DeletedAt{Time: deletionTimestamp, Valid: true} + _, err = s.resourceDao.Update(ctx, found) + if err != nil { + return handleUpdateError("Resource", err) + } } if _, err := s.events.Create(ctx, &api.Event{ From b65178176cf59907febff9ac4388341eb0e7b801 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Mon, 15 Jul 2024 11:39:42 +0800 Subject: [PATCH 03/67] handle creationTimestamp and deletionTimestamp in work metadata. (#160) Signed-off-by: morvencao --- cmd/maestro/environments/service_types.go | 1 + cmd/maestro/server/grpc_server.go | 53 ++----------- pkg/dao/mocks/resource.go | 11 --- pkg/dao/resource.go | 10 --- pkg/handlers/resource.go | 7 +- pkg/services/resource.go | 92 +++++++++++------------ pkg/services/resource_test.go | 5 +- test/e2e/pkg/resources_test.go | 16 ++++ test/e2e/pkg/sourceclient_test.go | 8 +- 9 files changed, 79 insertions(+), 124 deletions(-) diff --git a/cmd/maestro/environments/service_types.go b/cmd/maestro/environments/service_types.go index 7d62864f..6b383046 100755 --- a/cmd/maestro/environments/service_types.go +++ b/cmd/maestro/environments/service_types.go @@ -14,6 +14,7 @@ func NewResourceServiceLocator(env *Env) ResourceServiceLocator { db.NewAdvisoryLockFactory(env.Database.SessionFactory), dao.NewResourceDao(&env.Database.SessionFactory), env.Services.Events(), + env.Services.Generic(), ) } } diff --git a/cmd/maestro/server/grpc_server.go b/cmd/maestro/server/grpc_server.go index d043f884..bb77d97c 100644 --- a/cmd/maestro/server/grpc_server.go +++ b/cmd/maestro/server/grpc_server.go @@ -2,7 +2,6 @@ package server import ( "context" - "encoding/json" "fmt" "net" "time" @@ -10,14 +9,12 @@ import ( ce "github.com/cloudevents/sdk-go/v2" "github.com/cloudevents/sdk-go/v2/binding" cetypes "github.com/cloudevents/sdk-go/v2/types" - cloudeventstypes "github.com/cloudevents/sdk-go/v2/types" "github.com/golang/glog" "github.com/google/uuid" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" "google.golang.org/protobuf/types/known/emptypb" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog/v2" pbv1 "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protobuf/v1" grpcprotocol "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protocol" @@ -124,41 +121,18 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return &emptypb.Empty{}, nil } - var res *api.Resource + res, err := decode(eventType.CloudEventsDataType, evt) + if err != nil { + return nil, fmt.Errorf("failed to decode cloudevent: %v", err) + } + switch eventType.Action { case common.CreateRequestAction: - // set creation timestamp in work metadata - creationTimestamp := time.Now() - if workMeta, ok := evt.Extensions()[codec.ExtensionWorkMeta]; ok { - metaJSON, err := cloudeventstypes.ToString(workMeta) - if err != nil { - return nil, fmt.Errorf("failed to convert work meta extension to json: %v", err) - } - metaObj := metav1.ObjectMeta{} - if err := json.Unmarshal([]byte(metaJSON), &metaObj); err != nil { - return nil, fmt.Errorf("failed to unmarshal work meta extension: %v", err) - } - metaObj.CreationTimestamp = metav1.Time{Time: creationTimestamp} - metaJSONBytes, err := json.Marshal(metaObj) - if err != nil { - return nil, fmt.Errorf("failed to marshal work meta extension: %v", err) - } - evt.SetExtension(codec.ExtensionWorkMeta, string(metaJSONBytes)) - } - res, err = decode(eventType.CloudEventsDataType, evt) - if err != nil { - return nil, fmt.Errorf("failed to decode cloudevent: %v", err) - } - res.Meta.CreatedAt = creationTimestamp _, err := svr.resourceService.Create(ctx, res) if err != nil { return nil, fmt.Errorf("failed to create resource: %v", err) } case common.UpdateRequestAction: - res, err = decode(eventType.CloudEventsDataType, evt) - if err != nil { - return nil, fmt.Errorf("failed to decode cloudevent: %v", err) - } if res.Type == api.ResourceTypeBundle { found, err := svr.resourceService.Get(ctx, res.ID) if err != nil { @@ -176,22 +150,9 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return nil, fmt.Errorf("failed to update resource: %v", err) } case common.DeleteRequestAction: - res, err = decode(eventType.CloudEventsDataType, evt) + err := svr.resourceService.MarkAsDeleting(ctx, res.ID) if err != nil { - return nil, fmt.Errorf("failed to decode cloudevent: %v", err) - } - var deletionTimestamp time.Time - evtExtensions := evt.Context.GetExtensions() - if _, ok := evtExtensions[codec.ExtensionWorkMeta]; ok { - if _, exists := evtExtensions[types.ExtensionDeletionTimestamp]; exists { - // Use the server-generated deletion timestamp from the Maestro server instead of the source client's timestamp - // to account for potential timezone discrepancies between the source client and the Maestro server. - deletionTimestamp = time.Now() - } - } - sErr := svr.resourceService.MarkAsDeleting(ctx, res.ID, deletionTimestamp) - if sErr != nil { - return nil, fmt.Errorf("failed to update resource: %v", err) + return nil, fmt.Errorf("failed to delete resource: %v", err) } default: return nil, fmt.Errorf("unsupported action %s", eventType.Action) diff --git a/pkg/dao/mocks/resource.go b/pkg/dao/mocks/resource.go index 5ad5946b..f75bd07d 100755 --- a/pkg/dao/mocks/resource.go +++ b/pkg/dao/mocks/resource.go @@ -30,17 +30,6 @@ func (d *resourceDaoMock) Get(ctx context.Context, id string) (*api.Resource, er return nil, gorm.ErrRecordNotFound } -func (d *resourceDaoMock) GetBundle(ctx context.Context, id string) (*api.Resource, error) { - for _, resource := range d.resources { - if resource.ID == id { - if resource.Type == api.ResourceTypeBundle { - return resource, nil - } - } - } - return nil, gorm.ErrRecordNotFound -} - func (d *resourceDaoMock) Create(ctx context.Context, resource *api.Resource) (*api.Resource, error) { d.resources = append(d.resources, resource) return resource, nil diff --git a/pkg/dao/resource.go b/pkg/dao/resource.go index 5ce0c287..2ef1333e 100755 --- a/pkg/dao/resource.go +++ b/pkg/dao/resource.go @@ -11,7 +11,6 @@ import ( type ResourceDao interface { Get(ctx context.Context, id string) (*api.Resource, error) - GetBundle(ctx context.Context, id string) (*api.Resource, error) Create(ctx context.Context, resource *api.Resource) (*api.Resource, error) Update(ctx context.Context, resource *api.Resource) (*api.Resource, error) Delete(ctx context.Context, id string, unscoped bool) error @@ -41,15 +40,6 @@ func (d *sqlResourceDao) Get(ctx context.Context, id string) (*api.Resource, err return &resource, nil } -func (d *sqlResourceDao) GetBundle(ctx context.Context, id string) (*api.Resource, error) { - g2 := (*d.sessionFactory).New(ctx) - var resource api.Resource - if err := g2.Unscoped().Take(&resource, "id = ? AND type = ?", id, api.ResourceTypeBundle).Error; err != nil { - return nil, err - } - return &resource, nil -} - func (d *sqlResourceDao) Create(ctx context.Context, resource *api.Resource) (*api.Resource, error) { g2 := (*d.sessionFactory).New(ctx) if err := g2.Omit(clause.Associations).Create(resource).Error; err != nil { diff --git a/pkg/handlers/resource.go b/pkg/handlers/resource.go index c589c891..501ddc60 100755 --- a/pkg/handlers/resource.go +++ b/pkg/handlers/resource.go @@ -3,7 +3,6 @@ package handlers import ( "fmt" "net/http" - "time" "github.com/gorilla/mux" @@ -173,7 +172,7 @@ func (h resourceHandler) Delete(w http.ResponseWriter, r *http.Request) { Action: func() (interface{}, *errors.ServiceError) { id := mux.Vars(r)["id"] ctx := r.Context() - err := h.resource.MarkAsDeleting(ctx, id, time.Time{}) + err := h.resource.MarkAsDeleting(ctx, id) if err != nil { return nil, err } @@ -188,7 +187,7 @@ func (h resourceHandler) GetBundle(w http.ResponseWriter, r *http.Request) { Action: func() (interface{}, *errors.ServiceError) { id := mux.Vars(r)["id"] ctx := r.Context() - resource, serviceErr := h.resource.GetBundle(ctx, id) + resource, serviceErr := h.resource.Get(ctx, id) if serviceErr != nil { return nil, serviceErr } @@ -216,7 +215,7 @@ func (h resourceHandler) ListBundle(w http.ResponseWriter, r *http.Request) { listArgs.Search = fmt.Sprintf("%s and type='%s'", listArgs.Search, api.ResourceTypeBundle) } var resources []api.Resource - paging, serviceErr := h.generic.List(ctx, "username", listArgs, &resources) + paging, serviceErr := h.resource.ListWithArgs(ctx, "username", listArgs, &resources) if serviceErr != nil { return nil, serviceErr } diff --git a/pkg/services/resource.go b/pkg/services/resource.go index 76c3a122..24723365 100755 --- a/pkg/services/resource.go +++ b/pkg/services/resource.go @@ -10,7 +10,6 @@ import ( "github.com/openshift-online/maestro/pkg/dao" "github.com/openshift-online/maestro/pkg/db" logger "github.com/openshift-online/maestro/pkg/logger" - "gorm.io/gorm" cegeneric "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" @@ -21,24 +20,25 @@ import ( type ResourceService interface { Get(ctx context.Context, id string) (*api.Resource, *errors.ServiceError) - GetBundle(ctx context.Context, id string) (*api.Resource, *errors.ServiceError) Create(ctx context.Context, resource *api.Resource) (*api.Resource, *errors.ServiceError) Update(ctx context.Context, resource *api.Resource) (*api.Resource, *errors.ServiceError) UpdateStatus(ctx context.Context, resource *api.Resource) (*api.Resource, bool, *errors.ServiceError) - MarkAsDeleting(ctx context.Context, id string, deletionTimestamp time.Time) *errors.ServiceError + MarkAsDeleting(ctx context.Context, id string) *errors.ServiceError Delete(ctx context.Context, id string) *errors.ServiceError All(ctx context.Context) (api.ResourceList, *errors.ServiceError) FindByIDs(ctx context.Context, ids []string) (api.ResourceList, *errors.ServiceError) FindBySource(ctx context.Context, source string) (api.ResourceList, *errors.ServiceError) List(listOpts cetypes.ListOptions) ([]*api.Resource, error) + ListWithArgs(ctx context.Context, username string, args *ListArguments, resources *[]api.Resource) (*api.PagingMeta, *errors.ServiceError) } -func NewResourceService(lockFactory db.LockFactory, resourceDao dao.ResourceDao, events EventService) ResourceService { +func NewResourceService(lockFactory db.LockFactory, resourceDao dao.ResourceDao, events EventService, generic GenericService) ResourceService { return &sqlResourceService{ lockFactory: lockFactory, resourceDao: resourceDao, events: events, + generic: generic, } } @@ -48,6 +48,7 @@ type sqlResourceService struct { lockFactory db.LockFactory resourceDao dao.ResourceDao events EventService + generic GenericService } func (s *sqlResourceService) Get(ctx context.Context, id string) (*api.Resource, *errors.ServiceError) { @@ -55,14 +56,10 @@ func (s *sqlResourceService) Get(ctx context.Context, id string) (*api.Resource, if err != nil { return nil, handleGetError("Resource", "id", id, err) } - return resource, nil -} -func (s *sqlResourceService) GetBundle(ctx context.Context, id string) (*api.Resource, *errors.ServiceError) { - resource, err := s.resourceDao.GetBundle(ctx, id) - if err != nil { - return nil, handleGetError("Resource Bundle", "id", id, err) - } + // sync the creationTimestamp and deletionTimestamp from resource meta to work metadata + s.syncTimestampsFromResourceMeta(resource) + return resource, nil } @@ -216,48 +213,16 @@ func (s *sqlResourceService) UpdateStatus(ctx context.Context, resource *api.Res return updated, true, nil } -// MarkAsDeleting marks the resource as deleting by setting the deletion timestamp. -// There are two cases: -// 1. If deletionTimestamp is not provided, the resource will be deleted and the deleteAt -// will be set by the database. -// 2. If deletionTimestamp is provided, the resource will be marked as deleting in both -// the deleteAt field and deletionTimestamp in the work metadata before deletion. -// +// MarkAsDeleting marks the resource as deleting by setting the delete_at timestamp. // The Resource Deletion Flow: // 1. User requests deletion // 2. Maestro marks resource as deleting by soft delete, adds delete event to DB // 3. Maestro handles delete event and sends CloudEvent to work-agent // 4. Work-agent deletes resource, sends CloudEvent back to Maestro // 5. Maestro hard deletes resource from DB -func (s *sqlResourceService) MarkAsDeleting(ctx context.Context, id string, deletionTimestamp time.Time) *errors.ServiceError { - if deletionTimestamp.IsZero() { - // If deletionTimestamp is not provided, delete the resource immediately. - // The database deletion mechanism ensures the deleteAt field of the resource is set. - if err := s.resourceDao.Delete(ctx, id, false); err != nil { - return handleDeleteError("Resource", errors.GeneralError("Unable to delete resource: %s", err)) - } - } else { - // If deletionTimestamp is provided, the resource will be marked as deleting in both - // the deleteAt field and deletionTimestamp in the work metadata before deletion. - found, err := s.resourceDao.Get(ctx, id) - if err != nil { - return handleGetError("Resource", "id", id, err) - } - // set deletionTimestamp in work metadata - workMetaValue, ok := found.Payload["metadata"] - if ok { - workMeta, ok := workMetaValue.(map[string]interface{}) - if ok { - workMeta["deletionTimestamp"] = deletionTimestamp.Format(time.RFC3339) - found.Payload["metadata"] = workMeta - } - } - // set deletedAt in resource meta - found.DeletedAt = gorm.DeletedAt{Time: deletionTimestamp, Valid: true} - _, err = s.resourceDao.Update(ctx, found) - if err != nil { - return handleUpdateError("Resource", err) - } +func (s *sqlResourceService) MarkAsDeleting(ctx context.Context, id string) *errors.ServiceError { + if err := s.resourceDao.Delete(ctx, id, false); err != nil { + return handleDeleteError("Resource", errors.GeneralError("Unable to delete resource: %s", err)) } if _, err := s.events.Create(ctx, &api.Event{ @@ -305,6 +270,9 @@ func (s *sqlResourceService) All(ctx context.Context) (api.ResourceList, *errors var _ cegeneric.Lister[*api.Resource] = &sqlResourceService{} +// List implements the cegeneric.Lister interface, enabling the cloudevents source client to list resources for responding spec resync from the agent. +// For more details, refer to the cegeneric.Lister interface: +// https://github.com/open-cluster-management-io/sdk-go/blob/d3c47c228d7905ebb20f331f9b72bc5ff6a84789/pkg/cloudevents/generic/interface.go#L36-L39 func (s *sqlResourceService) List(listOpts cetypes.ListOptions) ([]*api.Resource, error) { resourceList, err := s.resourceDao.FindByConsumerName(context.TODO(), listOpts.ClusterName) if err != nil { @@ -312,3 +280,33 @@ func (s *sqlResourceService) List(listOpts cetypes.ListOptions) ([]*api.Resource } return resourceList, nil } + +// ListWithArgs lists resources based on the provided page and filter arguments. +func (s *sqlResourceService) ListWithArgs(ctx context.Context, username string, args *ListArguments, resources *[]api.Resource) (*api.PagingMeta, *errors.ServiceError) { + paging, serviceErr := s.generic.List(ctx, username, args, resources) + if serviceErr != nil { + return nil, serviceErr + } + + for _, resource := range *resources { + // sync the creationTimestamp and deletionTimestamp from resource meta to work metadata + s.syncTimestampsFromResourceMeta(&resource) + } + + return paging, nil +} + +func (s *sqlResourceService) syncTimestampsFromResourceMeta(resource *api.Resource) { + // fill back the creationTimestamp and deletionTimestamp from resource meta to work metadata if it exists + workMetaValue, ok := resource.Payload["metadata"] + if ok { + workMeta, ok := workMetaValue.(map[string]interface{}) + if ok { + workMeta["creationTimestamp"] = resource.CreatedAt.Format(time.RFC3339) + if !resource.DeletedAt.Time.IsZero() { + workMeta["deletionTimestamp"] = resource.DeletedAt.Time.Format(time.RFC3339) + } + resource.Payload["metadata"] = workMeta + } + } +} diff --git a/pkg/services/resource_test.go b/pkg/services/resource_test.go index 07e7ee3f..69cca6b4 100755 --- a/pkg/services/resource_test.go +++ b/pkg/services/resource_test.go @@ -16,7 +16,8 @@ func TestResourceFindByConsumerID(t *testing.T) { resourceDAO := mocks.NewResourceDao() events := NewEventService(mocks.NewEventDao()) - resourceService := NewResourceService(dbmocks.NewMockAdvisoryLockFactory(), resourceDAO, events) + + resourceService := NewResourceService(dbmocks.NewMockAdvisoryLockFactory(), resourceDAO, events, nil) const Fukuisaurus = "b288a9da-8bfe-4c82-94cc-2b48e773fc46" const Seismosaurus = "e3eb7db1-b124-4a4d-8bb6-cc779c01b402" @@ -53,7 +54,7 @@ func TestCreateInvalidResource(t *testing.T) { resourceDAO := mocks.NewResourceDao() events := NewEventService(mocks.NewEventDao()) - resourceService := NewResourceService(dbmocks.NewMockAdvisoryLockFactory(), resourceDAO, events) + resourceService := NewResourceService(dbmocks.NewMockAdvisoryLockFactory(), resourceDAO, events, nil) resource := &api.Resource{ConsumerName: "invalidation", Payload: newPayload(t, "{}")} diff --git a/test/e2e/pkg/resources_test.go b/test/e2e/pkg/resources_test.go index 2efde412..918087b8 100644 --- a/test/e2e/pkg/resources_test.go +++ b/test/e2e/pkg/resources_test.go @@ -352,12 +352,28 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(err).ShouldNot(HaveOccurred()) }) + It("get the resource via restful API", func() { + gotResourceBundleList, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourceBundlesGet(ctx).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + Expect(len(gotResourceBundleList.Items)).To(Equal(1)) + resourceBundle := gotResourceBundleList.Items[0] + Expect(resourceBundle.Metadata["creationTimestamp"]).ShouldNot(BeEmpty()) + gotResourceBundle, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(ctx, *resourceBundle.Id).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + Expect(gotResourceBundle.Metadata["creationTimestamp"]).ShouldNot(BeEmpty()) + }) + It("get the resource status back", func() { Eventually(func() error { work, err := workClient.ManifestWorks(consumer.Name).Get(ctx, workName, metav1.GetOptions{}) if err != nil { return err } + if work.CreationTimestamp.Time.IsZero() { + return fmt.Errorf("work creationTimestamp is empty") + } manifest := work.Status.ResourceStatus.Manifests if len(manifest) > 0 && len(manifest[0].StatusFeedbacks.Values) != 0 { diff --git a/test/e2e/pkg/sourceclient_test.go b/test/e2e/pkg/sourceclient_test.go index 7e077f4f..cd68abaf 100644 --- a/test/e2e/pkg/sourceclient_test.go +++ b/test/e2e/pkg/sourceclient_test.go @@ -431,19 +431,19 @@ func AssertWatchResult(result *WatchedResult) error { hasDeletedWork := false for _, watchedWork := range result.WatchedWorks { - if strings.HasPrefix(watchedWork.Name, "init-work-a") { + if strings.HasPrefix(watchedWork.Name, "init-work-a") && !watchedWork.CreationTimestamp.IsZero() { hasFirstInitWork = true } - if strings.HasPrefix(watchedWork.Name, "init-work-b") { + if strings.HasPrefix(watchedWork.Name, "init-work-b") && !watchedWork.CreationTimestamp.IsZero() { hasSecondInitWork = true } - if strings.HasPrefix(watchedWork.Name, "work-") { + if strings.HasPrefix(watchedWork.Name, "work-") && !watchedWork.CreationTimestamp.IsZero() { hasWork = true } - if meta.IsStatusConditionTrue(watchedWork.Status.Conditions, common.ManifestsDeleted) { + if meta.IsStatusConditionTrue(watchedWork.Status.Conditions, common.ManifestsDeleted) && !watchedWork.DeletionTimestamp.IsZero() { hasDeletedWork = true } } From 8a87a7d1dac2d02a82f61d3cffe13c4029a771f3 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 13:48:57 +0800 Subject: [PATCH 04/67] chore(deps): update openapitools/openapi-generator-cli docker tag to v7.7.0 (#153) Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- Dockerfile.openapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.openapi b/Dockerfile.openapi index d8c4194a..28071923 100755 --- a/Dockerfile.openapi +++ b/Dockerfile.openapi @@ -1,4 +1,4 @@ -FROM openapitools/openapi-generator-cli:v7.6.0 +FROM openapitools/openapi-generator-cli:v7.7.0 RUN apt-get update RUN apt-get install -y make sudo git From e4bce47d5686c14c1dc83774e398d40689ddf0c8 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 13:49:34 +0800 Subject: [PATCH 05/67] chore(deps): update konflux references (#151) Signed-off-by: red-hat-konflux <123456+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-pull-request.yaml | 14 +++++++------- .tekton/maestro-push.yaml | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index 6ece7fbf..6080c1cd 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -195,7 +195,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:9aec3ae9f0f50a05abdc739faf4cbc82832cff16c77ac74e1d54072a882c0503 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:e253dd708ec9520a0286e7abdb4fa1c2ff3f78eba28c22d32f8861fd8a5761d5 - name: kind value: task resolver: bundles @@ -230,7 +230,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:021f7029d0d8a1834bc45a4cd3cc451c03d0f87a5793eb19e1902f8b00dd3d4c + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:b2d7986b918a77b328864bcdd25526ef59e781f098aa2f35b1db806fd893ed41 - name: kind value: task resolver: bundles @@ -286,7 +286,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:aaf998c36c66d2330cf45894f9cca52486fcdd73e030620e7107e28da247ed87 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:54bbf968893823622cfbab2dd5a6e08e66ec7649673e21f5a4ebb8944e23535b - name: kind value: task resolver: bundles @@ -308,7 +308,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:de7d372d90939db203072a024f1b13869dd11fac9b196e2a485bdf2a20099902 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:4545291a178d5643d64b51424dffb2a48fe35e9918d7385707d7407522a8a7e0 - name: kind value: task resolver: bundles @@ -325,7 +325,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:5aa816e7d7f5e03448d658edfeb26e086aa8a2102c4c3c1113651cf5ccfe55b1 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:60774c68333a34579d4f5044d395ee8edf87738a7d56205bfb1b83e93dbe0a41 - name: kind value: task resolver: bundles @@ -350,7 +350,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fc4f8cd9826cb0eef863237fdb15240a13c075f624f0c6f8433d1ba8e53725ac + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3d175c521a65a8c00f509e67e62def03ab28911f70868399619c9804b81e38a0 - name: kind value: task resolver: bundles @@ -372,7 +372,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:1f7ae5f2660ddfd447727cdc4a8311ce4d991e5fd8f0a23f1b13d6968d8a97e1 + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:d34362be8843715b1bcdaf55fcbf1be315094e0dc840562c5cec22716a37a1fe - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index ab7b3bf0..ec1b5f1d 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -192,7 +192,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:9aec3ae9f0f50a05abdc739faf4cbc82832cff16c77ac74e1d54072a882c0503 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:e253dd708ec9520a0286e7abdb4fa1c2ff3f78eba28c22d32f8861fd8a5761d5 - name: kind value: task resolver: bundles @@ -227,7 +227,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:021f7029d0d8a1834bc45a4cd3cc451c03d0f87a5793eb19e1902f8b00dd3d4c + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:b2d7986b918a77b328864bcdd25526ef59e781f098aa2f35b1db806fd893ed41 - name: kind value: task resolver: bundles @@ -283,7 +283,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:aaf998c36c66d2330cf45894f9cca52486fcdd73e030620e7107e28da247ed87 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:54bbf968893823622cfbab2dd5a6e08e66ec7649673e21f5a4ebb8944e23535b - name: kind value: task resolver: bundles @@ -305,7 +305,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:de7d372d90939db203072a024f1b13869dd11fac9b196e2a485bdf2a20099902 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:4545291a178d5643d64b51424dffb2a48fe35e9918d7385707d7407522a8a7e0 - name: kind value: task resolver: bundles @@ -322,7 +322,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:5aa816e7d7f5e03448d658edfeb26e086aa8a2102c4c3c1113651cf5ccfe55b1 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:60774c68333a34579d4f5044d395ee8edf87738a7d56205bfb1b83e93dbe0a41 - name: kind value: task resolver: bundles @@ -347,7 +347,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fc4f8cd9826cb0eef863237fdb15240a13c075f624f0c6f8433d1ba8e53725ac + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3d175c521a65a8c00f509e67e62def03ab28911f70868399619c9804b81e38a0 - name: kind value: task resolver: bundles @@ -369,7 +369,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:1f7ae5f2660ddfd447727cdc4a8311ce4d991e5fd8f0a23f1b13d6968d8a97e1 + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:d34362be8843715b1bcdaf55fcbf1be315094e0dc840562c5cec22716a37a1fe - name: kind value: task resolver: bundles From fdaabcd539db736f1f0076312bd4836c064c44c3 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Wed, 17 Jul 2024 14:24:06 +0800 Subject: [PATCH 06/67] upgrade sdk-go (#161) Signed-off-by: Wei Liu --- .tekton/maestro-pull-request.yaml | 2 +- .tekton/maestro-push.yaml | 2 +- go.mod | 2 +- go.sum | 4 ++-- pkg/client/cloudevents/grpcsource/watcherstore.go | 14 +++++++++----- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index 6080c1cd..626afc1e 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -350,7 +350,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3d175c521a65a8c00f509e67e62def03ab28911f70868399619c9804b81e38a0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:559d281b58584386a6faaf0e6641c814f9d877432d1a13bd03076745fffffaf1 - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index ec1b5f1d..4894ac82 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -347,7 +347,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3d175c521a65a8c00f509e67e62def03ab28911f70868399619c9804b81e38a0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:559d281b58584386a6faaf0e6641c814f9d877432d1a13bd03076745fffffaf1 - name: kind value: task resolver: bundles diff --git a/go.mod b/go.mod index b835a91e..5f926076 100755 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( k8s.io/klog/v2 v2.120.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 - open-cluster-management.io/sdk-go v0.14.1-0.20240628095929-9ffb1b19e566 + open-cluster-management.io/sdk-go v0.14.1-0.20240717021054-955108a181ee ) require ( diff --git a/go.sum b/go.sum index ed25cb12..1d700872 100755 --- a/go.sum +++ b/go.sum @@ -825,8 +825,8 @@ open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c h1:gYfgkX/U open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 h1:7uPjyn1x25QZIzfZqeSFfZdNrzc2hlHm6t/JKYKu9fI= open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33/go.mod h1:KzUwhPZAg6Wq+4xRu10fVVpqNADyz5CtRW4ziqIC2z4= -open-cluster-management.io/sdk-go v0.14.1-0.20240628095929-9ffb1b19e566 h1:8dgPiM3byX/rtOrFJIsea2haV4hSFTND65Tlj1EdK18= -open-cluster-management.io/sdk-go v0.14.1-0.20240628095929-9ffb1b19e566/go.mod h1:xFmN3Db5nN68oLGnstmIRv4us8HJCdXFnBNMXVp0jWY= +open-cluster-management.io/sdk-go v0.14.1-0.20240717021054-955108a181ee h1:aQ4AoR8SKz/byOyZbbYC9Tbp4VCtRHje8uHbn438o84= +open-cluster-management.io/sdk-go v0.14.1-0.20240717021054-955108a181ee/go.mod h1:xFmN3Db5nN68oLGnstmIRv4us8HJCdXFnBNMXVp0jWY= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= diff --git a/pkg/client/cloudevents/grpcsource/watcherstore.go b/pkg/client/cloudevents/grpcsource/watcherstore.go index f0185875..aa5bd77b 100644 --- a/pkg/client/cloudevents/grpcsource/watcherstore.go +++ b/pkg/client/cloudevents/grpcsource/watcherstore.go @@ -10,7 +10,6 @@ import ( "github.com/openshift-online/maestro/pkg/api/openapi" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -126,18 +125,23 @@ func (m *RESTFulAPIWatcherStore) HandleReceivedWork(action types.ResourceAction, } // Get a work from maestro server with its namespace and name -func (m *RESTFulAPIWatcherStore) Get(namespace, name string) (*workv1.ManifestWork, error) { +func (m *RESTFulAPIWatcherStore) Get(namespace, name string) (*workv1.ManifestWork, bool, error) { id := utils.UID(m.sourceID, namespace, name) rb, resp, err := m.apiClient.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(context.Background(), id).Execute() if err != nil { if resp != nil && resp.StatusCode == http.StatusNotFound { - return nil, errors.NewNotFound(common.ManifestWorkGR, id) + return nil, false, nil } - return nil, err + return nil, false, err + } + + work, err := ToManifestWork(rb) + if err != nil { + return nil, false, err } - return ToManifestWork(rb) + return work, true, nil } // List works from maestro server with a specified namespace and list options. From c2b1c73daef6a946f6641867e47ce23874184155 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Wed, 24 Jul 2024 14:21:43 +0800 Subject: [PATCH 07/67] fix typo in service-template-aro-hc (#166) Signed-off-by: Wei Liu --- templates/service-template-aro-hcp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/service-template-aro-hcp.yml b/templates/service-template-aro-hcp.yml index 8dc30d25..c59fd522 100755 --- a/templates/service-template-aro-hcp.yml +++ b/templates/service-template-aro-hcp.yml @@ -84,7 +84,7 @@ parameters: description: HTTP server bind port value: "8000" -- nane: ENABLE_GRPC_SERVER +- name: ENABLE_GRPC_SERVER displayName: Enable gRPC Server description: Enable gRPC server value: "true" From fb5c0363deddfc9269f7ba5eeec8d808ee566bc3 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 16:32:59 +0800 Subject: [PATCH 08/67] chore(deps): update konflux references (#164) Signed-off-by: red-hat-konflux <123456+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-pull-request.yaml | 20 ++++++++++---------- .tekton/maestro-push.yaml | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index 626afc1e..1715b6dd 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -41,7 +41,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:9cd4bf015b18621834f40ed02c8dccda1f7834c7d989521a8314bdb3a596e96b + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:3ea2255c6ad2dd1074de45227deab51b69dba57901f44dbca80fe1c57646b107 - name: kind value: task resolver: bundles @@ -60,7 +60,7 @@ spec: - name: name value: summary - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:51d5aaa4e13e9fb4303f667e38d07e758820040032ed9fb3ab5f6afaaffc60d8 + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:abdf426424f1331c27be80ed98a0fbcefb8422767d1724308b9d57b37f977155 - name: kind value: task resolver: bundles @@ -153,7 +153,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:b23c7a924f303a67b3a00b32a6713ae1a4fccbc5327daa76a6edd250501ea7a3 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:61f1202766cd66242c8472b16aa7fa1a20f8d9a5d674cbad27ffd4b3d067e936 - name: kind value: task resolver: bundles @@ -170,7 +170,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:2be7c9c83159c5247f1f9aab8fa1a2cb29d0df66f6c5bb48a012320bdcb03c7d + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:e1f7a275d722bc3147a65fcd772b16b54ccb6ce81c76939bc1052b2438dd2ccf - name: kind value: task resolver: bundles @@ -195,7 +195,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:e253dd708ec9520a0286e7abdb4fa1c2ff3f78eba28c22d32f8861fd8a5761d5 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:fc03e91c047948f1e4906a82a7ad43c3ca35e66c9468c180f405e08affa73bbf - name: kind value: task resolver: bundles @@ -230,7 +230,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:b2d7986b918a77b328864bcdd25526ef59e781f098aa2f35b1db806fd893ed41 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:2e49aeca14ec287ff5f57834532e6f5637300b2a88c2cb9bcc7c9286ca87760c - name: kind value: task resolver: bundles @@ -255,7 +255,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:83ee909cb8f7d659fac380a2521fb60f30c309e5ecb91f3aad2433936e690d98 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:b1e5a49fed40f9736242f5601d2accb6dba26669dfa1470d6c8d691b3ac46e81 - name: kind value: task resolver: bundles @@ -286,7 +286,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:54bbf968893823622cfbab2dd5a6e08e66ec7649673e21f5a4ebb8944e23535b + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:3f956e0cd9b0a183e4fd95e010aa668a788ef564d3af1f7aecaaf6e2ccc2ce93 - name: kind value: task resolver: bundles @@ -308,7 +308,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:4545291a178d5643d64b51424dffb2a48fe35e9918d7385707d7407522a8a7e0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:3d9d05162d5807cde4431e80f0f126f4c19994c0c1633629a62ece9a43b966cd - name: kind value: task resolver: bundles @@ -325,7 +325,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:60774c68333a34579d4f5044d395ee8edf87738a7d56205bfb1b83e93dbe0a41 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:e6acf744313561b376b44724e81188f354b84cf3b0b3875e75efe7e0209637a2 - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index 4894ac82..d58bdc80 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -38,7 +38,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:9cd4bf015b18621834f40ed02c8dccda1f7834c7d989521a8314bdb3a596e96b + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:3ea2255c6ad2dd1074de45227deab51b69dba57901f44dbca80fe1c57646b107 - name: kind value: task resolver: bundles @@ -57,7 +57,7 @@ spec: - name: name value: summary - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:51d5aaa4e13e9fb4303f667e38d07e758820040032ed9fb3ab5f6afaaffc60d8 + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:abdf426424f1331c27be80ed98a0fbcefb8422767d1724308b9d57b37f977155 - name: kind value: task resolver: bundles @@ -150,7 +150,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:b23c7a924f303a67b3a00b32a6713ae1a4fccbc5327daa76a6edd250501ea7a3 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:61f1202766cd66242c8472b16aa7fa1a20f8d9a5d674cbad27ffd4b3d067e936 - name: kind value: task resolver: bundles @@ -167,7 +167,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:2be7c9c83159c5247f1f9aab8fa1a2cb29d0df66f6c5bb48a012320bdcb03c7d + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:e1f7a275d722bc3147a65fcd772b16b54ccb6ce81c76939bc1052b2438dd2ccf - name: kind value: task resolver: bundles @@ -192,7 +192,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:e253dd708ec9520a0286e7abdb4fa1c2ff3f78eba28c22d32f8861fd8a5761d5 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:fc03e91c047948f1e4906a82a7ad43c3ca35e66c9468c180f405e08affa73bbf - name: kind value: task resolver: bundles @@ -227,7 +227,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:b2d7986b918a77b328864bcdd25526ef59e781f098aa2f35b1db806fd893ed41 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:2e49aeca14ec287ff5f57834532e6f5637300b2a88c2cb9bcc7c9286ca87760c - name: kind value: task resolver: bundles @@ -252,7 +252,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:83ee909cb8f7d659fac380a2521fb60f30c309e5ecb91f3aad2433936e690d98 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:b1e5a49fed40f9736242f5601d2accb6dba26669dfa1470d6c8d691b3ac46e81 - name: kind value: task resolver: bundles @@ -283,7 +283,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:54bbf968893823622cfbab2dd5a6e08e66ec7649673e21f5a4ebb8944e23535b + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:3f956e0cd9b0a183e4fd95e010aa668a788ef564d3af1f7aecaaf6e2ccc2ce93 - name: kind value: task resolver: bundles @@ -305,7 +305,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:4545291a178d5643d64b51424dffb2a48fe35e9918d7385707d7407522a8a7e0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:3d9d05162d5807cde4431e80f0f126f4c19994c0c1633629a62ece9a43b966cd - name: kind value: task resolver: bundles @@ -322,7 +322,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:60774c68333a34579d4f5044d395ee8edf87738a7d56205bfb1b83e93dbe0a41 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:e6acf744313561b376b44724e81188f354b84cf3b0b3875e75efe7e0209637a2 - name: kind value: task resolver: bundles From c235e0c9017d8da4b30afd6921439c4420f0fabe Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Wed, 7 Aug 2024 16:42:24 +0800 Subject: [PATCH 09/67] add grpc broker. (#157) * add grpc broker. Signed-off-by: morvencao * fix testing. Signed-off-by: morvencao * address comments. Signed-off-by: morvencao * remove multiple grpc broker instances support. Signed-off-by: morvencao * unify message broker type. Signed-off-by: morvencao --------- Signed-off-by: morvencao --- .github/workflows/e2e.yml | 23 +- Makefile | 14 +- cmd/maestro/environments/framework.go | 28 +- cmd/maestro/servecmd/cmd.go | 16 +- cmd/maestro/server/controllers.go | 14 +- cmd/maestro/server/grpc_broker.go | 522 +++++++++++++++++++++++++ cmd/maestro/server/grpc_server.go | 22 +- cmd/maestro/server/pulse_server.go | 220 +++++++---- pkg/config/grpc_server.go | 6 +- pkg/config/message_broker.go | 2 +- templates/agent-template.yml | 25 +- templates/service-template-aro-hcp.yml | 4 +- templates/service-template.yml | 54 ++- test/e2e/pkg/resources_test.go | 23 +- test/e2e/pkg/sourceclient_test.go | 6 +- test/e2e/pkg/spec_resync_test.go | 88 ++++- test/e2e/pkg/status_resync_test.go | 2 +- test/e2e/setup/e2e_setup.sh | 3 +- test/helper.go | 27 +- 19 files changed, 911 insertions(+), 188 deletions(-) create mode 100644 cmd/maestro/server/grpc_broker.go diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index ea50e77f..2345a420 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -30,6 +30,7 @@ jobs: make e2e-test env: container_tool: docker + SERVER_REPLICAS: 2 e2e-broadcast-subscription: runs-on: ubuntu-latest steps: @@ -39,10 +40,6 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - # - name: Setup kind - # uses: engineerd/setup-kind@v0.5.0 - # with: - # version: v0.17.0 - name: install ginkgo run: go install github.com/onsi/ginkgo/v2/ginkgo@v2.15.0 - name: Test E2E @@ -50,4 +47,22 @@ jobs: make e2e-test env: container_tool: docker + SERVER_REPLICAS: 2 ENABLE_BROADCAST_SUBSCRIPTION: true + e2e-grpc-broker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + - name: install ginkgo + run: go install github.com/onsi/ginkgo/v2/ginkgo@v2.15.0 + - name: Test E2E + run: | + make e2e-test + env: + container_tool: docker + MESSAGE_DRIVER_TYPE: grpc diff --git a/Makefile b/Makefile index 776faf6f..91a64d29 100755 --- a/Makefile +++ b/Makefile @@ -76,10 +76,13 @@ CLIENT_SECRET ?= maestro ENABLE_JWT ?= true ENABLE_AUTHZ ?= true ENABLE_OCM_MOCK ?= false -ENABLE_GRPC ?= false +ENABLE_GRPC_SERVER ?= false + +# message driver type, mqtt or grpc, default is mqtt. +MESSAGE_DRIVER_TYPE ?= mqtt # default replicas for maestro server -REPLICAS ?= 1 +SERVER_REPLICAS ?= 1 # Enable set images POSTGRES_IMAGE ?= docker.io/library/postgres:14.2 @@ -267,7 +270,7 @@ cmds: --ignore-unknown-parameters="true" \ --param="ENVIRONMENT=$(OCM_ENV)" \ --param="GLOG_V=$(glog_v)" \ - --param="REPLICAS=$(REPLICAS)" \ + --param="SERVER_REPLICAS=$(SERVER_REPLICAS)" \ --param="DATABASE_HOST=$(db_host)" \ --param="DATABASE_NAME=$(db_name)" \ --param="DATABASE_PASSWORD=$(db_password)" \ @@ -303,7 +306,8 @@ cmds: --param="EXTERNAL_APPS_DOMAIN=${external_apps_domain}" \ --param="CONSUMER_NAME=$(consumer_name)" \ --param="ENABLE_OCM_MOCK=$(ENABLE_OCM_MOCK)" \ - --param="ENABLE_GRPC=$(ENABLE_GRPC)" \ + --param="ENABLE_GRPC_SERVER=$(ENABLE_GRPC_SERVER)" \ + --param="MESSAGE_DRIVER_TYPE"=$(MESSAGE_DRIVER_TYPE) \ > "templates/$*-template.json" @@ -413,7 +417,7 @@ e2e-test/teardown: .PHONY: e2e-test/teardown e2e-test: e2e-test/teardown e2e-test/setup - ginkgo --output-dir="${PWD}/test/e2e/report" --json-report=report.json --junit-report=report.xml \ + ginkgo -v --output-dir="${PWD}/test/e2e/report" --json-report=report.json --junit-report=report.xml \ ${PWD}/test/e2e/pkg -- \ -api-server=https://$(shell cat ${PWD}/test/e2e/.external_host_ip):30080 \ -grpc-server=$(shell cat ${PWD}/test/e2e/.external_host_ip):30090 \ diff --git a/cmd/maestro/environments/framework.go b/cmd/maestro/environments/framework.go index 4a158f06..8ee757ab 100755 --- a/cmd/maestro/environments/framework.go +++ b/cmd/maestro/environments/framework.go @@ -173,21 +173,21 @@ func (e *Env) LoadClients() error { glog.Infof("Using Mock CloudEvents Source Client") e.Clients.CloudEventsSource = cloudevents.NewSourceClientMock(e.Services.Resources()) } else { + // For gRPC message broker type, Maestro server does not require the source client to publish resources or subscribe to resource status. + if e.Config.MessageBroker.MessageBrokerType != "grpc" { + _, config, err := generic.NewConfigLoader(e.Config.MessageBroker.MessageBrokerType, e.Config.MessageBroker.MessageBrokerConfig). + LoadConfig() + if err != nil { + glog.Errorf("Unable to load configuration: %s", err.Error()) + return err + } - _, config, err := generic.NewConfigLoader(e.Config.MessageBroker.MessageBrokerType, e.Config.MessageBroker.MessageBrokerConfig). - LoadConfig() - if err != nil { - glog.Errorf("Unable to load configuration: %s", err.Error()) - return err - } - - cloudEventsSourceOptions, err := generic.BuildCloudEventsSourceOptions(config, - e.Config.MessageBroker.ClientID, e.Config.MessageBroker.SourceID) - if err != nil { - glog.Errorf("Unable to build cloudevent source options: %s", err.Error()) - return err - } - if cloudEventsSourceOptions != nil { + cloudEventsSourceOptions, err := generic.BuildCloudEventsSourceOptions(config, + e.Config.MessageBroker.ClientID, e.Config.MessageBroker.SourceID) + if err != nil { + glog.Errorf("Unable to build cloudevent source options: %s", err.Error()) + return err + } e.Clients.CloudEventsSource, err = cloudevents.NewSourceClient(cloudEventsSourceOptions, e.Services.Resources()) if err != nil { glog.Errorf("Unable to create CloudEvents Source client: %s", err.Error()) diff --git a/cmd/maestro/servecmd/cmd.go b/cmd/maestro/servecmd/cmd.go index 3b2f51ed..e73c5728 100755 --- a/cmd/maestro/servecmd/cmd.go +++ b/cmd/maestro/servecmd/cmd.go @@ -38,12 +38,22 @@ func runServer(cmd *cobra.Command, args []string) { // Create event broadcaster to broadcast resource status update events to subscribers eventBroadcaster := event.NewEventBroadcaster() + // Create the event server based on the message broker type: + // For gRPC, create a gRPC broker to handle resource spec and status events. + // For MQTT, create a Pulse server to handle resource spec and status events. + var eventServer server.EventServer + if environments.Environment().Config.MessageBroker.MessageBrokerType == "grpc" { + glog.Info("Setting up grpc broker") + eventServer = server.NewGRPCBroker(eventBroadcaster) + } else { + glog.Info("Setting up pulse server") + eventServer = server.NewPulseServer(eventBroadcaster) + } // Create the servers apiserver := server.NewAPIServer(eventBroadcaster) metricsServer := server.NewMetricsServer() healthcheckServer := server.NewHealthCheckServer() - pulseServer := server.NewPulseServer(eventBroadcaster) - controllersServer := server.NewControllersServer(pulseServer) + controllersServer := server.NewControllersServer(eventServer) ctx, cancel := context.WithCancel(context.Background()) @@ -73,7 +83,7 @@ func runServer(cmd *cobra.Command, args []string) { go apiserver.Start() go metricsServer.Start() go healthcheckServer.Start() - go pulseServer.Start(ctx) + go eventServer.Start(ctx) go controllersServer.Start(ctx) <-ctx.Done() diff --git a/cmd/maestro/server/controllers.go b/cmd/maestro/server/controllers.go index 724113c3..d7d9cb68 100755 --- a/cmd/maestro/server/controllers.go +++ b/cmd/maestro/server/controllers.go @@ -10,8 +10,7 @@ import ( "github.com/openshift-online/maestro/pkg/logger" ) -func NewControllersServer(pulseServer *PulseServer) *ControllersServer { - +func NewControllersServer(eventServer EventServer) *ControllersServer { s := &ControllersServer{ KindControllerManager: controllers.NewKindControllerManager( db.NewAdvisoryLockFactory(env().Database.SessionFactory), @@ -22,19 +21,18 @@ func NewControllersServer(pulseServer *PulseServer) *ControllersServer { ), } - sourceClient := env().Clients.CloudEventsSource s.KindControllerManager.Add(&controllers.ControllerConfig{ Source: "Resources", Handlers: map[api.EventType][]controllers.ControllerHandlerFunc{ - api.CreateEventType: {sourceClient.OnCreate}, - api.UpdateEventType: {sourceClient.OnUpdate}, - api.DeleteEventType: {sourceClient.OnDelete}, + api.CreateEventType: {eventServer.OnCreate}, + api.UpdateEventType: {eventServer.OnUpdate}, + api.DeleteEventType: {eventServer.OnDelete}, }, }) s.StatusController.Add(map[api.StatusEventType][]controllers.StatusHandlerFunc{ - api.StatusUpdateEventType: {pulseServer.OnStatusUpdate}, - api.StatusDeleteEventType: {pulseServer.OnStatusUpdate}, + api.StatusUpdateEventType: {eventServer.OnStatusUpdate}, + api.StatusDeleteEventType: {eventServer.OnStatusUpdate}, }) return s diff --git a/cmd/maestro/server/grpc_broker.go b/cmd/maestro/server/grpc_broker.go new file mode 100644 index 00000000..3b9b232e --- /dev/null +++ b/cmd/maestro/server/grpc_broker.go @@ -0,0 +1,522 @@ +package server + +import ( + "context" + "fmt" + "net" + "strconv" + "sync" + "time" + + ce "github.com/cloudevents/sdk-go/v2" + "github.com/cloudevents/sdk-go/v2/binding" + cetypes "github.com/cloudevents/sdk-go/v2/types" + "github.com/golang/glog" + "github.com/google/uuid" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/keepalive" + "google.golang.org/protobuf/types/known/emptypb" + "k8s.io/klog/v2" + pbv1 "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protobuf/v1" + grpcprotocol "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protocol" + "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/payload" + "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" + workpayload "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" + + "github.com/openshift-online/maestro/pkg/api" + "github.com/openshift-online/maestro/pkg/dao" + "github.com/openshift-online/maestro/pkg/event" + "github.com/openshift-online/maestro/pkg/logger" + "github.com/openshift-online/maestro/pkg/services" +) + +type resourceHandler func(res *api.Resource) error + +// subscriber defines a subscriber that can receive and handle resource spec. +type subscriber struct { + clusterName string + handler resourceHandler + errChan chan<- error +} + +var _ EventServer = &GRPCBroker{} + +// GRPCBroker is a gRPC broker that implements the CloudEventServiceServer interface. +// It broadcasts resource spec to Maestro agents and listens for resource status updates from them. +// TODO: Add support for multiple gRPC broker instances. When there are multiple instances of the Maestro server, +// the work agent may be load-balanced across any instance. Each instance needs to handle the resource spec to +// ensure all work agents receive all the resource spec. +type GRPCBroker struct { + pbv1.UnimplementedCloudEventServiceServer + grpcServer *grpc.Server + instanceID string + eventInstanceDao dao.EventInstanceDao + resourceService services.ResourceService + statusEventService services.StatusEventService + bindAddress string + subscribers map[string]*subscriber // registered subscribers + eventBroadcaster *event.EventBroadcaster // event broadcaster to broadcast resource status update events to subscribers + mu sync.RWMutex +} + +// NewGRPCBroker creates a new gRPC broker with the given configuration. +func NewGRPCBroker(eventBroadcaster *event.EventBroadcaster) EventServer { + config := *env().Config.GRPCServer + grpcServerOptions := make([]grpc.ServerOption, 0) + grpcServerOptions = append(grpcServerOptions, grpc.MaxRecvMsgSize(config.MaxReceiveMessageSize)) + grpcServerOptions = append(grpcServerOptions, grpc.MaxSendMsgSize(config.MaxSendMessageSize)) + grpcServerOptions = append(grpcServerOptions, grpc.MaxConcurrentStreams(config.MaxConcurrentStreams)) + grpcServerOptions = append(grpcServerOptions, grpc.ConnectionTimeout(config.ConnectionTimeout)) + grpcServerOptions = append(grpcServerOptions, grpc.WriteBufferSize(config.WriteBufferSize)) + grpcServerOptions = append(grpcServerOptions, grpc.ReadBufferSize(config.ReadBufferSize)) + grpcServerOptions = append(grpcServerOptions, grpc.KeepaliveParams(keepalive.ServerParameters{ + MaxConnectionAge: config.MaxConnectionAge, + })) + + if config.EnableTLS { + // Check tls cert and key path path + if config.TLSCertFile == "" || config.TLSKeyFile == "" { + check( + fmt.Errorf("unspecified required --grpc-tls-cert-file, --grpc-tls-key-file"), + "Can't start gRPC broker", + ) + } + + // Serve with TLS + creds, err := credentials.NewServerTLSFromFile(config.TLSCertFile, config.TLSKeyFile) + if err != nil { + glog.Fatalf("Failed to generate credentials %v", err) + } + grpcServerOptions = append(grpcServerOptions, grpc.Creds(creds)) + glog.Infof("Serving gRPC broker with TLS at %s", config.BrokerBindPort) + } else { + glog.Infof("Serving gRPC broker without TLS at %s", config.BrokerBindPort) + } + + sessionFactory := env().Database.SessionFactory + return &GRPCBroker{ + grpcServer: grpc.NewServer(grpcServerOptions...), + instanceID: env().Config.MessageBroker.ClientID, + eventInstanceDao: dao.NewEventInstanceDao(&sessionFactory), + resourceService: env().Services.Resources(), + statusEventService: env().Services.StatusEvents(), + bindAddress: env().Config.HTTPServer.Hostname + ":" + config.BrokerBindPort, + subscribers: make(map[string]*subscriber), + eventBroadcaster: eventBroadcaster, + } +} + +// Start starts the gRPC broker +func (bkr *GRPCBroker) Start(ctx context.Context) { + lis, err := net.Listen("tcp", bkr.bindAddress) + if err != nil { + glog.Fatalf("failed to listen: %v", err) + } + pbv1.RegisterCloudEventServiceServer(bkr.grpcServer, bkr) + go func() { + if err := bkr.grpcServer.Serve(lis); err != nil { + glog.Fatalf("failed to start gRPC broker: %v", err) + } + }() + + // wait until context is canceled + <-ctx.Done() + log.Infof("Shutting down gRPC broker") +} + +// Publish in stub implementation for maestro agent publish resource status back to maestro server. +func (bkr *GRPCBroker) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) (*emptypb.Empty, error) { + // WARNING: don't use "evt, err := pb.FromProto(pubReq.Event)" to convert protobuf to cloudevent + evt, err := binding.ToEvent(ctx, grpcprotocol.NewMessage(pubReq.Event)) + if err != nil { + return nil, fmt.Errorf("failed to convert protobuf to cloudevent: %v", err) + } + + eventType, err := types.ParseCloudEventsType(evt.Type()) + if err != nil { + return nil, fmt.Errorf("failed to parse cloud event type %s, %v", evt.Type(), err) + } + + glog.V(4).Infof("receive the event with grpc broker, %s", evt) + + // handler resync request + if eventType.Action == types.ResyncRequestAction { + err := bkr.respondResyncSpecRequest(ctx, eventType.CloudEventsDataType, evt) + if err != nil { + return nil, fmt.Errorf("failed to respond resync spec request: %v", err) + } + return &emptypb.Empty{}, nil + } + + // decode the cloudevent data as resource with status + resource, err := decodeResourceStatus(eventType.CloudEventsDataType, evt) + if err != nil { + return nil, fmt.Errorf("failed to decode cloudevent: %v", err) + } + + // handle the resource status update according status update type + if err := handleStatusUpdate(ctx, resource, bkr.resourceService, bkr.statusEventService); err != nil { + return nil, fmt.Errorf("failed to handle resource status update %s: %s", resource.ID, err.Error()) + } + + return &emptypb.Empty{}, nil +} + +// register registers a subscriber and return client id and error channel. +func (bkr *GRPCBroker) register(clusterName string, handler resourceHandler) (string, <-chan error) { + bkr.mu.Lock() + defer bkr.mu.Unlock() + + id := uuid.NewString() + errChan := make(chan error) + bkr.subscribers[id] = &subscriber{ + clusterName: clusterName, + handler: handler, + errChan: errChan, + } + + glog.V(4).Infof("register a subscriber %s (cluster name = %s)", id, clusterName) + + return id, errChan +} + +// unregister unregisters a subscriber by id +func (bkr *GRPCBroker) unregister(id string) { + bkr.mu.Lock() + defer bkr.mu.Unlock() + + glog.V(10).Infof("unregister subscriber %s", id) + close(bkr.subscribers[id].errChan) + delete(bkr.subscribers, id) +} + +// Subscribe in stub implementation for maestro agent subscribe resource spec from maestro server. +// Note: It's unnecessary to send a status resync request to Maestro agent subscribers. +// The work agent will continuously attempt to send status updates to the gRPC broker. +// If the broker is down or disconnected, the agent will resend the status once the broker is back up or reconnected. +func (bkr *GRPCBroker) Subscribe(subReq *pbv1.SubscriptionRequest, subServer pbv1.CloudEventService_SubscribeServer) error { + if len(subReq.ClusterName) == 0 { + return fmt.Errorf("invalid subscription request: missing cluster name") + } + // register the cluster for subscription to the resource spec + subscriberID, errChan := bkr.register(subReq.ClusterName, func(res *api.Resource) error { + evt, err := encodeResourceSpec(res) + if err != nil { + return fmt.Errorf("failed to encode resource %s to cloudevent: %v", res.ID, err) + } + + glog.V(4).Infof("send the event to spec subscribers, %s", evt) + + // WARNING: don't use "pbEvt, err := pb.ToProto(evt)" to convert cloudevent to protobuf + pbEvt := &pbv1.CloudEvent{} + if err = grpcprotocol.WritePBMessage(context.TODO(), binding.ToMessage(evt), pbEvt); err != nil { + return fmt.Errorf("failed to convert cloudevent to protobuf: %v", err) + } + + // send the cloudevent to the subscriber + // TODO: error handling to address errors beyond network issues. + if err := subServer.Send(pbEvt); err != nil { + klog.Errorf("failed to send grpc event, %v", err) + } + + return nil + }) + + select { + case err := <-errChan: + glog.Errorf("unregister subscriber %s, error= %v", subscriberID, err) + bkr.unregister(subscriberID) + return err + case <-subServer.Context().Done(): + bkr.unregister(subscriberID) + return nil + } +} + +// decodeResourceStatus translates a CloudEvent into a resource containing the status JSON map. +func decodeResourceStatus(eventDataType types.CloudEventsDataType, evt *ce.Event) (*api.Resource, error) { + evtExtensions := evt.Context.GetExtensions() + + clusterName, err := cetypes.ToString(evtExtensions[types.ExtensionClusterName]) + if err != nil { + return nil, fmt.Errorf("failed to get clustername extension: %v", err) + } + + resourceID, err := cetypes.ToString(evtExtensions[types.ExtensionResourceID]) + if err != nil { + return nil, fmt.Errorf("failed to get resourceid extension: %v", err) + } + + resourceVersion, err := cetypes.ToInteger(evtExtensions[types.ExtensionResourceVersion]) + if err != nil { + return nil, fmt.Errorf("failed to get resourceversion extension: %v", err) + } + + status, err := api.CloudEventToJSONMap(evt) + if err != nil { + return nil, fmt.Errorf("failed to convert cloudevent to resource status: %v", err) + } + + resource := &api.Resource{ + Source: evt.Source(), + ConsumerName: clusterName, + Version: resourceVersion, + Meta: api.Meta{ + ID: resourceID, + }, + Status: status, + } + + switch eventDataType { + case workpayload.ManifestEventDataType: + resource.Type = api.ResourceTypeSingle + case workpayload.ManifestBundleEventDataType: + resource.Type = api.ResourceTypeBundle + default: + return nil, fmt.Errorf("unsupported cloudevents data type %s", eventDataType) + } + + return resource, nil +} + +// encodeResourceSpec translates a resource spec JSON map into a CloudEvent. +func encodeResourceSpec(resource *api.Resource) (*ce.Event, error) { + evt, err := api.JSONMAPToCloudEvent(resource.Payload) + if err != nil { + return nil, fmt.Errorf("failed to convert resource payload to cloudevent: %v", err) + } + + eventType := types.CloudEventsType{ + CloudEventsDataType: workpayload.ManifestEventDataType, + SubResource: types.SubResourceSpec, + Action: types.EventAction("create_request"), + } + if resource.Type == api.ResourceTypeBundle { + eventType.CloudEventsDataType = workpayload.ManifestBundleEventDataType + } + evt.SetType(eventType.String()) + evt.SetSource("maestro") + // TODO set resource.Source with a new extension attribute if the agent needs + evt.SetExtension(types.ExtensionResourceID, resource.ID) + evt.SetExtension(types.ExtensionResourceVersion, int64(resource.Version)) + evt.SetExtension(types.ExtensionClusterName, resource.ConsumerName) + + if !resource.GetDeletionTimestamp().IsZero() { + evt.SetExtension(types.ExtensionDeletionTimestamp, resource.GetDeletionTimestamp().Time) + } + + return evt, nil +} + +// Upon receiving the spec resync event, the source responds by sending resource status events to the broker as follows: +// - If the request event message is empty, the source returns all resources associated with the work agent. +// - If the request event message contains resource IDs and versions, the source retrieves the resource with the +// specified ID and compares the versions. +// - If the requested resource version matches the source's current maintained resource version, the source does not +// resend the resource. +// - If the requested resource version is older than the source's current maintained resource version, the source +// sends the resource. +func (bkr *GRPCBroker) respondResyncSpecRequest(ctx context.Context, eventDataType types.CloudEventsDataType, evt *ce.Event) error { + log := logger.NewOCMLogger(ctx) + + resyncType := api.ResourceTypeSingle + if eventDataType == workpayload.ManifestBundleEventDataType { + resyncType = api.ResourceTypeBundle + } + + resourceVersions, err := payload.DecodeSpecResyncRequest(*evt) + if err != nil { + return err + } + + clusterNameValue, err := evt.Context.GetExtension(types.ExtensionClusterName) + if err != nil { + return err + } + clusterName := fmt.Sprintf("%s", clusterNameValue) + + objs, err := bkr.resourceService.List(types.ListOptions{ClusterName: clusterName}) + if err != nil { + return err + } + + if len(objs) == 0 { + log.V(4).Infof("there are is no objs from the list, do nothing") + return nil + } + + for _, obj := range objs { + // only respond with the resource of the resync type + if obj.Type != resyncType { + continue + } + // respond with the deleting resource regardless of the resource version + if !obj.GetDeletionTimestamp().IsZero() { + bkr.handleRes(obj) + continue + } + + lastResourceVersion := findResourceVersion(string(obj.GetUID()), resourceVersions.Versions) + currentResourceVersion, err := strconv.ParseInt(obj.GetResourceVersion(), 10, 64) + if err != nil { + log.V(4).Infof("ignore the obj %v since it has a invalid resourceVersion, %v", obj, err) + continue + } + + // the version of the work is not maintained on source or the source's work is newer than agent, send + // the newer work to agent + if currentResourceVersion == 0 || currentResourceVersion > lastResourceVersion { + bkr.handleRes(obj) + } + } + + // the resources do not exist on the source, but exist on the agent, delete them + for _, rv := range resourceVersions.Versions { + _, exists := getObj(rv.ResourceID, objs) + if exists { + continue + } + + obj := &api.Resource{ + Meta: api.Meta{ + ID: rv.ResourceID, + }, + Version: int32(rv.ResourceVersion), + ConsumerName: clusterName, + Type: resyncType, + } + // mark the resource as deleting + obj.Meta.DeletedAt.Time = time.Now() + + // send a delete event for the current resource + bkr.handleRes(obj) + } + + return nil +} + +// handleRes publish the resource to the correct subscriber. +func (bkr *GRPCBroker) handleRes(resource *api.Resource) { + bkr.mu.RLock() + defer bkr.mu.RUnlock() + for _, subscriber := range bkr.subscribers { + if subscriber.clusterName == resource.ConsumerName { + if err := subscriber.handler(resource); err != nil { + subscriber.errChan <- err + } + } + } +} + +// OnCreate is called by the controller when a resource is created on the maestro server. +func (bkr *GRPCBroker) OnCreate(ctx context.Context, id string) error { + resource, err := bkr.resourceService.Get(ctx, id) + if err != nil { + return err + } + + bkr.handleRes(resource) + + return nil +} + +// OnUpdate is called by the controller when a resource is updated on the maestro server. +func (bkr *GRPCBroker) OnUpdate(ctx context.Context, id string) error { + resource, err := bkr.resourceService.Get(ctx, id) + if err != nil { + return err + } + + bkr.handleRes(resource) + + return nil +} + +// OnDelete is called by the controller when a resource is deleted from the maestro server. +func (bkr *GRPCBroker) OnDelete(ctx context.Context, id string) error { + resource, err := bkr.resourceService.Get(ctx, id) + if err != nil { + return err + } + + bkr.handleRes(resource) + + return nil +} + +// On StatusUpdate will be called on each new status event inserted into db. +// It does two things: +// 1. build the resource status and broadcast it to subscribers +// 2. add the event instance record to mark the event has been processed by the current instance +func (bkr *GRPCBroker) OnStatusUpdate(ctx context.Context, eventID, resourceID string) error { + statusEvent, sErr := bkr.statusEventService.Get(ctx, eventID) + if sErr != nil { + return fmt.Errorf("failed to get status event %s: %s", eventID, sErr.Error()) + } + + var resource *api.Resource + // check if the status event is delete event + if statusEvent.StatusEventType == api.StatusDeleteEventType { + // build resource with resource id and delete status + resource = &api.Resource{ + Meta: api.Meta{ + ID: resourceID, + }, + Source: statusEvent.ResourceSource, + Type: statusEvent.ResourceType, + Status: statusEvent.Status, + } + } else { + resource, sErr = bkr.resourceService.Get(ctx, resourceID) + if sErr != nil { + return fmt.Errorf("failed to get resource %s: %s", resourceID, sErr.Error()) + } + } + + // broadcast the resource status to subscribers + log.V(4).Infof("Broadcast the resource status %s", resource.ID) + bkr.eventBroadcaster.Broadcast(resource) + + // add the event instance record + _, err := bkr.eventInstanceDao.Create(ctx, &api.EventInstance{ + EventID: eventID, + InstanceID: bkr.instanceID, + }) + + return err +} + +// IsConsumerSubscribed returns true if the consumer is subscribed to the broker for resource spec. +func (bkr *GRPCBroker) IsConsumerSubscribed(consumerName string) bool { + bkr.mu.RLock() + defer bkr.mu.RUnlock() + for _, subscriber := range bkr.subscribers { + if subscriber.clusterName == consumerName { + return true + } + } + return false +} + +// findResourceVersion returns the resource version for the given ID from the list of resource versions. +func findResourceVersion(id string, versions []payload.ResourceVersion) int64 { + for _, version := range versions { + if id == version.ResourceID { + return version.ResourceVersion + } + } + + return 0 +} + +// getObj returns the object with the given ID from the list of resources. +func getObj(id string, objs []*api.Resource) (*api.Resource, bool) { + for _, obj := range objs { + if obj.ID == id { + return obj, true + } + } + + return nil, false +} diff --git a/cmd/maestro/server/grpc_server.go b/cmd/maestro/server/grpc_server.go index bb77d97c..e58ee348 100644 --- a/cmd/maestro/server/grpc_server.go +++ b/cmd/maestro/server/grpc_server.go @@ -68,16 +68,16 @@ func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *e glog.Fatalf("Failed to generate credentials %v", err) } grpcServerOptions = append(grpcServerOptions, grpc.Creds(creds)) - glog.Infof("Serving gRPC service with TLS at %s", config.BindPort) + glog.Infof("Serving gRPC service with TLS at %s", config.ServerBindPort) } else { - glog.Infof("Serving gRPC service without TLS at %s", config.BindPort) + glog.Infof("Serving gRPC service without TLS at %s", config.ServerBindPort) } return &GRPCServer{ grpcServer: grpc.NewServer(grpcServerOptions...), eventBroadcaster: eventBroadcaster, resourceService: resourceService, - bindAddress: env().Config.HTTPServer.Hostname + ":" + config.BindPort, + bindAddress: env().Config.HTTPServer.Hostname + ":" + config.ServerBindPort, } } @@ -110,7 +110,7 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return nil, fmt.Errorf("failed to parse cloud event type %s, %v", evt.Type(), err) } - glog.V(4).Infof("receive the event with grpc, %s", evt) + glog.V(4).Infof("receive the event with grpc server, %s", evt) // handler resync request if eventType.Action == types.ResyncRequestAction { @@ -121,7 +121,7 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return &emptypb.Empty{}, nil } - res, err := decode(eventType.CloudEventsDataType, evt) + res, err := decodeResourceSpec(eventType.CloudEventsDataType, evt) if err != nil { return nil, fmt.Errorf("failed to decode cloudevent: %v", err) } @@ -164,12 +164,12 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) // Subscribe implements the Subscribe method of the CloudEventServiceServer interface func (svr *GRPCServer) Subscribe(subReq *pbv1.SubscriptionRequest, subServer pbv1.CloudEventService_SubscribeServer) error { clientID, errChan := svr.eventBroadcaster.Register(subReq.Source, func(res *api.Resource) error { - evt, err := encode(res) + evt, err := encodeResourceStatus(res) if err != nil { return fmt.Errorf("failed to encode resource %s to cloudevent: %v", res.ID, err) } - glog.V(4).Infof("send the event with grpc, %s", evt) + glog.V(4).Infof("send the event to status subscribers, %s", evt) // WARNING: don't use "pbEvt, err := pb.ToProto(evt)" to convert cloudevent to protobuf pbEvt := &pbv1.CloudEvent{} @@ -198,8 +198,8 @@ func (svr *GRPCServer) Subscribe(subReq *pbv1.SubscriptionRequest, subServer pbv } } -// decode translates a cloudevent to a resource -func decode(eventDataType types.CloudEventsDataType, evt *ce.Event) (*api.Resource, error) { +// decodeResourceSpec translates a CloudEvent into a resource containing the spec JSON map. +func decodeResourceSpec(eventDataType types.CloudEventsDataType, evt *ce.Event) (*api.Resource, error) { evtExtensions := evt.Context.GetExtensions() clusterName, err := cetypes.ToString(evtExtensions[types.ExtensionClusterName]) @@ -252,8 +252,8 @@ func decode(eventDataType types.CloudEventsDataType, evt *ce.Event) (*api.Resour return resource, nil } -// encode translates a resource to a cloudevent -func encode(resource *api.Resource) (*ce.Event, error) { +// encodeResourceStatus translates a resource status JSON map into a CloudEvent. +func encodeResourceStatus(resource *api.Resource) (*ce.Event, error) { if resource.Type == api.ResourceTypeSingle { // single resource, return the status directly return api.JSONMAPToCloudEvent(resource.Status) diff --git a/cmd/maestro/server/pulse_server.go b/cmd/maestro/server/pulse_server.go index b215aa2a..d606e2fa 100644 --- a/cmd/maestro/server/pulse_server.go +++ b/cmd/maestro/server/pulse_server.go @@ -25,23 +25,46 @@ import ( var log = logger.NewOCMLogger(context.Background()) -// PulseServer represents a server responsible for periodic heartbeat updates and -// checking the liveness of Maestro instances, triggering status resync based on -// instances' status and other conditions. +// EventServer handles resource-related events: +// 1. Resource spec events (create, update and delete) from the resource controller. +// 2. Resource status update events from the agent. +type EventServer interface { + // Start initiates the EventServer. + Start(ctx context.Context) + + // OnCreate handles the creation of a resource. + OnCreate(ctx context.Context, resourceID string) error + + // OnUpdate handles updates to a resource. + OnUpdate(ctx context.Context, resourceID string) error + + // OnDelete handles the deletion of a resource. + OnDelete(ctx context.Context, resourceID string) error + + // OnStatusUpdate handles status update events for a resource. + OnStatusUpdate(ctx context.Context, eventID, resourceID string) error +} + +var _ EventServer = &PulseServer{} + +// PulseServer represents a server responsible for publish resource spec events from +// resource controller and handle resource status update events from the maestro agent. +// It also periodic heartbeat updates and checking the liveness of Maestro instances, +// triggering status resync based on instances' status and other conditions. type PulseServer struct { instanceID string pulseInterval int64 instanceDao dao.InstanceDao eventInstanceDao dao.EventInstanceDao lockFactory db.LockFactory - eventBroadcaster *event.EventBroadcaster + eventBroadcaster *event.EventBroadcaster // event broadcaster to broadcast resource status update events to subscribers resourceService services.ResourceService statusEventService services.StatusEventService sourceClient cloudevents.SourceClient statusDispatcher dispatcher.Dispatcher } -func NewPulseServer(eventBroadcaster *event.EventBroadcaster) *PulseServer { +func NewPulseServer(eventBroadcaster *event.EventBroadcaster) EventServer { var statusDispatcher dispatcher.Dispatcher switch config.SubscriptionType(env().Config.PulseServer.SubscriptionType) { case config.SharedSubscriptionType: @@ -157,89 +180,15 @@ func (s *PulseServer) startSubscription(ctx context.Context) { switch action { case types.StatusModified: - found, svcErr := s.resourceService.Get(ctx, resource.ID) - if svcErr != nil { - if svcErr.Is404() { - log.Warning(fmt.Sprintf("skipping resource %s as it is not found", resource.ID)) - return nil - } - - return fmt.Errorf("failed to get resource %s, %s", resource.ID, svcErr.Error()) - } - - if found.ConsumerName != resource.ConsumerName { - return fmt.Errorf("unmatched consumer name %s for resource %s", resource.ConsumerName, resource.ID) - } - - // set the resource source and type back for broadcast - resource.Source = found.Source - resource.Type = found.Type - if !s.statusDispatcher.Dispatch(resource.ConsumerName) { // the resource is not owned by the current instance, skip log.V(4).Infof("skipping resource status update %s as it is not owned by the current instance", resource.ID) return nil } - specEvent, err := api.JSONMAPToCloudEvent(found.Payload) - if err != nil { - return fmt.Errorf("failed to convert resource spec to cloudevent: %v", err) - } - - // convert the resource status to cloudevent - statusEvent, err := api.JSONMAPToCloudEvent(resource.Status) - if err != nil { - return fmt.Errorf("failed to convert resource status to cloudevent: %v", err) - } - - // set work meta from spec event to status event - if workMeta, ok := specEvent.Extensions()[codec.ExtensionWorkMeta]; ok { - statusEvent.SetExtension(codec.ExtensionWorkMeta, workMeta) - } - - resource.Status, err = api.CloudEventToJSONMap(statusEvent) - if err != nil { - return fmt.Errorf("failed to convert resource status cloudevent to json: %v", err) - } - - // decode the cloudevent data as manifest status - statusPayload := &workpayload.ManifestStatus{} - if err := statusEvent.DataAs(statusPayload); err != nil { - return fmt.Errorf("failed to decode cloudevent data as resource status: %v", err) - } - - // if the resource has been deleted from agent, create status event and delete it from maestro - if meta.IsStatusConditionTrue(statusPayload.Conditions, common.ManifestsDeleted) { - _, sErr := s.statusEventService.Create(ctx, &api.StatusEvent{ - ResourceID: resource.ID, - ResourceSource: resource.Source, - ResourceType: resource.Type, - Status: resource.Status, - StatusEventType: api.StatusDeleteEventType, - }) - if sErr != nil { - return fmt.Errorf("failed to create status event for resource status delete %s: %s", resource.ID, sErr.Error()) - } - if svcErr := s.resourceService.Delete(ctx, resource.ID); svcErr != nil { - return fmt.Errorf("failed to delete resource %s: %s", resource.ID, svcErr.Error()) - } - } else { - // update the resource status - _, updated, svcErr := s.resourceService.UpdateStatus(ctx, resource) - if svcErr != nil { - return fmt.Errorf("failed to update resource status %s: %s", resource.ID, svcErr.Error()) - } - - // create the status event only when the resource is updated - if updated { - _, sErr := s.statusEventService.Create(ctx, &api.StatusEvent{ - ResourceID: resource.ID, - StatusEventType: api.StatusUpdateEventType, - }) - if sErr != nil { - return fmt.Errorf("failed to create status event for resource status update %s: %s", resource.ID, sErr.Error()) - } - } + // handle the resource status update according status update type + if err := handleStatusUpdate(ctx, resource, s.resourceService, s.statusEventService); err != nil { + return fmt.Errorf("failed to handle resource status update %s: %s", resource.ID, err.Error()) } default: return fmt.Errorf("unsupported action %s", action) @@ -249,6 +198,21 @@ func (s *PulseServer) startSubscription(ctx context.Context) { }) } +// OnCreate will be called on each new resource creation event inserted into db. +func (s *PulseServer) OnCreate(ctx context.Context, resourceID string) error { + return s.sourceClient.OnCreate(ctx, resourceID) +} + +// OnUpdate will be called on each new resource update event inserted into db. +func (s *PulseServer) OnUpdate(ctx context.Context, resourceID string) error { + return s.sourceClient.OnUpdate(ctx, resourceID) +} + +// OnDelete will be called on each new resource deletion event inserted into db. +func (s *PulseServer) OnDelete(ctx context.Context, resourceID string) error { + return s.sourceClient.OnDelete(ctx, resourceID) +} + // On StatusUpdate will be called on each new status event inserted into db. // It does two things: // 1. build the resource status and broadcast it to subscribers @@ -290,3 +254,95 @@ func (s *PulseServer) OnStatusUpdate(ctx context.Context, eventID, resourceID st return err } + +// handleStatusUpdate processes the resource status update from the agent. +// The resource argument contains the updated status. +// The function performs the following steps: +// 1. Verifies if the resource is still in the Maestro server and checks if the consumer name matches. +// 2. Retrieves the resource from Maestro and fills back the work metadata from the spec event to the status event. +// 3. Checks if the resource has been deleted from the agent. If so, creates a status event and deletes the resource from Maestro; +// otherwise, updates the resource status and creates a status event. +func handleStatusUpdate(ctx context.Context, resource *api.Resource, resourceService services.ResourceService, statusEventService services.StatusEventService) error { + found, svcErr := resourceService.Get(ctx, resource.ID) + if svcErr != nil { + if svcErr.Is404() { + log.Warning(fmt.Sprintf("skipping resource %s as it is not found", resource.ID)) + return nil + } + + return fmt.Errorf("failed to get resource %s, %s", resource.ID, svcErr.Error()) + } + + if found.ConsumerName != resource.ConsumerName { + return fmt.Errorf("unmatched consumer name %s for resource %s", resource.ConsumerName, resource.ID) + } + + // set the resource source and type back for broadcast + resource.Source = found.Source + resource.Type = found.Type + + // convert the resource status to cloudevent + statusEvent, err := api.JSONMAPToCloudEvent(resource.Status) + if err != nil { + return fmt.Errorf("failed to convert resource status to cloudevent: %v", err) + } + + // convert the resource spec to cloudevent + specEvent, err := api.JSONMAPToCloudEvent(found.Payload) + if err != nil { + return fmt.Errorf("failed to convert resource spec to cloudevent: %v", err) + } + + // set work meta from spec event to status event + if workMeta, ok := specEvent.Extensions()[codec.ExtensionWorkMeta]; ok { + statusEvent.SetExtension(codec.ExtensionWorkMeta, workMeta) + } + + // convert the resource status cloudevent back to resource status jsonmap + resource.Status, err = api.CloudEventToJSONMap(statusEvent) + if err != nil { + return fmt.Errorf("failed to convert resource status cloudevent to json: %v", err) + } + + // decode the cloudevent data as manifest status + statusPayload := &workpayload.ManifestStatus{} + if err := statusEvent.DataAs(statusPayload); err != nil { + return fmt.Errorf("failed to decode cloudevent data as resource status: %v", err) + } + + // if the resource has been deleted from agent, create status event and delete it from maestro + if meta.IsStatusConditionTrue(statusPayload.Conditions, common.ManifestsDeleted) { + _, sErr := statusEventService.Create(ctx, &api.StatusEvent{ + ResourceID: resource.ID, + ResourceSource: resource.Source, + ResourceType: resource.Type, + Status: resource.Status, + StatusEventType: api.StatusDeleteEventType, + }) + if sErr != nil { + return fmt.Errorf("failed to create status event for resource status delete %s: %s", resource.ID, sErr.Error()) + } + if svcErr := resourceService.Delete(ctx, resource.ID); svcErr != nil { + return fmt.Errorf("failed to delete resource %s: %s", resource.ID, svcErr.Error()) + } + } else { + // update the resource status + _, updated, svcErr := resourceService.UpdateStatus(ctx, resource) + if svcErr != nil { + return fmt.Errorf("failed to update resource status %s: %s", resource.ID, svcErr.Error()) + } + + // create the status event only when the resource is updated + if updated { + _, sErr := statusEventService.Create(ctx, &api.StatusEvent{ + ResourceID: resource.ID, + StatusEventType: api.StatusUpdateEventType, + }) + if sErr != nil { + return fmt.Errorf("failed to create status event for resource status update %s: %s", resource.ID, sErr.Error()) + } + } + } + + return nil +} diff --git a/pkg/config/grpc_server.go b/pkg/config/grpc_server.go index 13abd326..592bbd94 100755 --- a/pkg/config/grpc_server.go +++ b/pkg/config/grpc_server.go @@ -12,7 +12,8 @@ type GRPCServerConfig struct { TLSCertFile string `json:"grpc_tls_cert_file"` TLSKeyFile string `json:"grpc_tls_key_file"` EnableTLS bool `json:"enable_grpc_tls"` - BindPort string `json:"bind_port"` + ServerBindPort string `json:"server_bind_port"` + BrokerBindPort string `json:"broker_bind_port"` MaxConcurrentStreams uint32 `json:"max_concurrent_steams"` MaxReceiveMessageSize int `json:"max_receive_message_size"` MaxSendMessageSize int `json:"max_send_message_size"` @@ -28,7 +29,8 @@ func NewGRPCServerConfig() *GRPCServerConfig { func (s *GRPCServerConfig) AddFlags(fs *pflag.FlagSet) { fs.BoolVar(&s.EnableGRPCServer, "enable-grpc-server", false, "Enable gRPC server") - fs.StringVar(&s.BindPort, "grpc-server-bindport", "8090", "gPRC server bind port") + fs.StringVar(&s.ServerBindPort, "grpc-server-bindport", "8090", "gPRC server bind port") + fs.StringVar(&s.BrokerBindPort, "grpc-broker-bindport", "8091", "gPRC broker bind port") fs.Uint32Var(&s.MaxConcurrentStreams, "grpc-max-concurrent-streams", math.MaxUint32, "gPRC max concurrent streams") fs.IntVar(&s.MaxReceiveMessageSize, "grpc-max-receive-message-size", 1024*1024*4, "gPRC max receive message size") fs.IntVar(&s.MaxSendMessageSize, "grpc-max-send-message-size", math.MaxInt32, "gPRC max send message size") diff --git a/pkg/config/message_broker.go b/pkg/config/message_broker.go index e2479bd2..6da942c7 100644 --- a/pkg/config/message_broker.go +++ b/pkg/config/message_broker.go @@ -28,6 +28,6 @@ func (c *MessageBrokerConfig) AddFlags(fs *pflag.FlagSet) { fs.BoolVar(&c.EnableMock, "enable-message-broker-mock", c.EnableMock, "Enable message broker mock") fs.StringVar(&c.SourceID, "source-id", c.SourceID, "Source ID") fs.StringVar(&c.ClientID, "client-id", c.ClientID, "Client ID") - fs.StringVar(&c.MessageBrokerType, "message-broker-type", c.MessageBrokerType, "Message broker type (default: mqtt)") + fs.StringVar(&c.MessageBrokerType, "message-broker-type", c.MessageBrokerType, "Message broker type ('grpc' or 'mqtt'). Default is 'mqtt'.") fs.StringVar(&c.MessageBrokerConfig, "message-broker-config-file", c.MessageBrokerConfig, "The config file path of message broker") } diff --git a/templates/agent-template.yml b/templates/agent-template.yml index aebe5118..d4f79a5b 100644 --- a/templates/agent-template.yml +++ b/templates/agent-template.yml @@ -33,6 +33,11 @@ parameters: displayName: Image tag value: latest +- name: MESSAGE_DRIVER_TYPE + displayName: Message Driver Type + description: Message driver type, mqtt or grpc. + value: mqtt + - name: MQTT_HOST description: Hostname for the mqtt broker. @@ -289,16 +294,24 @@ objects: - /usr/local/bin/maestro - agent - --consumer-name=${CONSUMER_NAME} - - --workload-source-driver=mqtt - - --workload-source-config=/secrets/mqtt/config.yaml + - --workload-source-driver=${MESSAGE_DRIVER_TYPE} + - --workload-source-config=/secrets/${MESSAGE_DRIVER_TYPE}/config.yaml - --cloudevents-client-id=${CONSUMER_NAME}-work-agent volumeMounts: - - name: mqtt - mountPath: /secrets/mqtt + - name: ${MESSAGE_DRIVER_TYPE} + mountPath: /secrets/${MESSAGE_DRIVER_TYPE} volumes: - - name: mqtt + - name: ${MESSAGE_DRIVER_TYPE} secret: - secretName: maestro-agent-mqtt + secretName: maestro-agent-${MESSAGE_DRIVER_TYPE} + +- apiVersion: v1 + kind: Secret + metadata: + name: maestro-agent-grpc + stringData: + config.yaml: | + url: maestro-grpc-broker.maestro:8091 - apiVersion: v1 kind: Secret diff --git a/templates/service-template-aro-hcp.yml b/templates/service-template-aro-hcp.yml index c59fd522..6a4ec2aa 100755 --- a/templates/service-template-aro-hcp.yml +++ b/templates/service-template-aro-hcp.yml @@ -65,7 +65,7 @@ parameters: description: Debug mode for OCM API client value: "false" -- name: REPLICAS +- name: SERVER_REPLICAS description: Number of replicas of the service to run. value: "1" @@ -174,7 +174,7 @@ objects: selector: matchLabels: app: maestro - replicas: ${{REPLICAS}} + replicas: ${{SERVER_REPLICAS}} strategy: rollingUpdate: maxSurge: 25% diff --git a/templates/service-template.yml b/templates/service-template.yml index 5f7ca150..08abd0f9 100755 --- a/templates/service-template.yml +++ b/templates/service-template.yml @@ -80,7 +80,7 @@ parameters: description: Debug mode for OCM API client value: "false" -- name: REPLICAS +- name: SERVER_REPLICAS description: Number of replicas of the service to run. value: "1" @@ -99,8 +99,8 @@ parameters: description: HTTP server bind port value: "8000" -- name: ENABLE_GRPC - displayName: Enable gRPC +- name: ENABLE_GRPC_SERVER + displayName: Enable gRPC server description: Enable gRPC server value: "false" @@ -109,6 +109,16 @@ parameters: description: gRPC server bind port value: "8090" +- name: GRPC_BROKER_BINDPORT + displayName: gRPC Broker Bindport + description: gRPC broker bind port + value: "8091" + +- name: MESSAGE_DRIVER_TYPE + displayName: Message Driver Type + description: Message driver type, mqtt or grpc. + value: mqtt + - name: METRICS_SERVER_BINDPORT displayName: Metrics Server Bindport description: Metrics server bind port @@ -209,7 +219,7 @@ objects: selector: matchLabels: app: maestro - replicas: ${{REPLICAS}} + replicas: ${{SERVER_REPLICAS}} strategy: rollingUpdate: maxSurge: 25% @@ -231,7 +241,7 @@ objects: - name: rds secret: secretName: maestro-rds - - name: mqtt + - name: ${MESSAGE_DRIVER_TYPE} secret: secretName: maestro-mqtt - name: authentication @@ -269,8 +279,8 @@ objects: mountPath: /secrets/service - name: rds mountPath: /secrets/rds - - name: mqtt - mountPath: /secrets/mqtt + - name: ${MESSAGE_DRIVER_TYPE} + mountPath: /secrets/${MESSAGE_DRIVER_TYPE} - name: authentication mountPath: /configs/authentication env: @@ -291,7 +301,8 @@ objects: - --db-name-file=/secrets/rds/db.name - --db-rootcert=/secrets/rds/db.ca_cert - --db-sslmode=${DB_SSLMODE} - - --message-broker-config-file=/secrets/mqtt/config.yaml + - --message-broker-type=${MESSAGE_DRIVER_TYPE} + - --message-broker-config-file=/secrets/${MESSAGE_DRIVER_TYPE}/config.yaml - --enable-ocm-mock=${ENABLE_OCM_MOCK} - --ocm-client-id-file=/secrets/service/ocm-service.clientId - --ocm-client-secret-file=/secrets/service/ocm-service.clientSecret @@ -299,7 +310,7 @@ objects: - --ocm-debug=${OCM_DEBUG} - --https-cert-file=/secrets/tls/tls.crt - --https-key-file=/secrets/tls/tls.key - - --enable-grpc-server=${ENABLE_GRPC} + - --enable-grpc-server=${ENABLE_GRPC_SERVER} - --grpc-tls-cert-file=/secrets/tls/tls.crt - --grpc-tls-key-file=/secrets/tls/tls.key - --acl-file=/configs/authentication/acl.yml @@ -310,6 +321,7 @@ objects: - --server-hostname=${HTTP_SERVER_HOSTNAME} - --http-server-bindport=${HTTP_SERVER_BINDPORT} - --grpc-server-bindport=${GRPC_SERVER_BINDPORT} + - --grpc-broker-bindport=${GRPC_BROKER_BINDPORT} - --health-check-server-bindport=${HEALTH_CHECK_SERVER_BINDPORT} - --enable-health-check-https=${ENABLE_HTTPS} - --db-max-open-connections=${DB_MAX_OPEN_CONNS} @@ -395,19 +407,37 @@ objects: metadata: name: maestro-grpc labels: - app: maestro-grpc + app: maestro port: grpc annotations: description: Exposes and load balances the maestro pods grpc endpoint - service.alpha.openshift.io/serving-cert-secret-name: maestro-tls spec: selector: app: maestro ports: - - port: 8090 + - name: grpc + port: 8090 targetPort: 8090 protocol: TCP + - kind: Service + apiVersion: v1 + metadata: + name: maestro-grpc-broker + labels: + app: maestro + port: grpc-broker + annotations: + description: Exposes and load balances the maestro pods grpc broker endpoint + spec: + selector: + app: maestro + ports: + - name: grpc-broker + port: 8091 + targetPort: 8091 + protocol: TCP + - apiVersion: v1 kind: Service metadata: diff --git a/test/e2e/pkg/resources_test.go b/test/e2e/pkg/resources_test.go index 918087b8..876e8a95 100644 --- a/test/e2e/pkg/resources_test.go +++ b/test/e2e/pkg/resources_test.go @@ -12,7 +12,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/rand" workv1 "open-cluster-management.io/api/work/v1" @@ -297,20 +296,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("post the resource bundle via gRPC client", func() { - obj := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": map[string]interface{}{ - "namespace": "default", - "name": "auth", - }, - }, - } - objectStr, _ := obj.MarshalJSON() - manifest := workv1.Manifest{} - manifest.Raw = objectStr - _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, &workv1.ManifestWork{ + work := &workv1.ManifestWork{ ObjectMeta: metav1.ObjectMeta{ Name: workName, }, @@ -348,8 +334,11 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }, }, }, - }, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) + } + Eventually(func() error { + _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + return err + }, 5*time.Minute, 5*time.Second).ShouldNot(HaveOccurred()) }) It("get the resource via restful API", func() { diff --git a/test/e2e/pkg/sourceclient_test.go b/test/e2e/pkg/sourceclient_test.go index cd68abaf..6993a0b0 100644 --- a/test/e2e/pkg/sourceclient_test.go +++ b/test/e2e/pkg/sourceclient_test.go @@ -32,8 +32,10 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { BeforeEach(func() { workName = "work-" + rand.String(5) work := NewManifestWork(workName) - _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) + Eventually(func() error { + _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + return err + }, 5*time.Minute, 5*time.Second).ShouldNot(HaveOccurred()) // wait for few seconds to ensure the creation is finished <-time.After(5 * time.Second) diff --git a/test/e2e/pkg/spec_resync_test.go b/test/e2e/pkg/spec_resync_test.go index a4c0fe30..5891b20c 100644 --- a/test/e2e/pkg/spec_resync_test.go +++ b/test/e2e/pkg/spec_resync_test.go @@ -17,7 +17,7 @@ import ( var _ = Describe("Spec resync", Ordered, Label("e2e-tests-spec-resync"), func() { var resource1, resource2, resource3 *openapi.Resource - var mqttReplicas, maestroAgentReplicas int + var mqttReplicas, maestroServerReplicas, maestroAgentReplicas int Context("Resource resync resource spec after maestro agent restarts", func() { It("post the nginx-1 resource to the maestro api", func() { @@ -298,12 +298,71 @@ var _ = Describe("Spec resync", Ordered, Label("e2e-tests-spec-resync"), func() }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) + It("delete the grpc-broker service for agent", func() { + err := consumer.ClientSet.CoreV1().Services("maestro").Delete(ctx, "maestro-grpc-broker", metav1.DeleteOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + }) + It("delete the mqtt-broker service for agent", func() { err := consumer.ClientSet.CoreV1().Services("maestro").Delete(ctx, "maestro-mqtt-agent", metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) - It("Rollout the mqtt-broker", func() { + It("rollout maestro server", func() { + deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Get(ctx, "maestro", metav1.GetOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + maestroServerReplicas = int(*deploy.Spec.Replicas) + deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ + FieldManager: "testconsumer.ClientSet", + }) + Expect(err).ShouldNot(HaveOccurred()) + Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) + + // ensure no running maestro server pods + Eventually(func() error { + pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ + LabelSelector: "app=maestro", + }) + if err != nil { + return err + } + if len(pods.Items) > 0 { + return fmt.Errorf("maestro server pods still running") + } + return nil + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + + // patch maestro server replicas to maestroServerReplicas + deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroServerReplicas)), metav1.PatchOptions{ + FieldManager: "testconsumer.ClientSet", + }) + Expect(err).ShouldNot(HaveOccurred()) + Expect(*deploy.Spec.Replicas).To(Equal(int32(maestroServerReplicas))) + + // ensure maestro server pod is up and running + Eventually(func() error { + pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ + LabelSelector: "app=maestro", + }) + if err != nil { + return err + } + if len(pods.Items) != maestroServerReplicas { + return fmt.Errorf("unexpected maestro server pod count, expected %d, got %d", maestroServerReplicas, len(pods.Items)) + } + for _, pod := range pods.Items { + if pod.Status.Phase != "Running" { + return fmt.Errorf("maestro server pod not in running state") + } + if pod.Status.ContainerStatuses[0].State.Running == nil { + return fmt.Errorf("maestro server container not in running state") + } + } + return nil + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }) + + It("rollout the mqtt-broker", func() { deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Get(ctx, "maestro-mqtt", metav1.GetOptions{}) Expect(err).ShouldNot(HaveOccurred()) mqttReplicas = int(*deploy.Spec.Replicas) @@ -455,6 +514,31 @@ var _ = Describe("Spec resync", Ordered, Label("e2e-tests-spec-resync"), func() Expect(err).ShouldNot(HaveOccurred()) }) + It("recreate the grpc-broker service for agent", func() { + grpcBrokerService := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "maestro-grpc-broker", + Namespace: "maestro", + }, + Spec: corev1.ServiceSpec{ + Selector: map[string]string{ + "app": "maestro", + }, + Ports: []corev1.ServicePort{ + { + Name: "grpc-broker", + Protocol: corev1.ProtocolTCP, + Port: 8091, + TargetPort: intstr.FromInt(8091), + }, + }, + Type: corev1.ServiceTypeClusterIP, + }, + } + _, err := consumer.ClientSet.CoreV1().Services("maestro").Create(ctx, grpcBrokerService, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + }) + It("ensure the nginx-1 resource is updated", func() { Eventually(func() error { deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) diff --git a/test/e2e/pkg/status_resync_test.go b/test/e2e/pkg/status_resync_test.go index 70bcf069..baa88525 100644 --- a/test/e2e/pkg/status_resync_test.go +++ b/test/e2e/pkg/status_resync_test.go @@ -152,7 +152,7 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun return fmt.Errorf("unexpected status, should not contain error looking up service account default/nginx, got %s", string(statusJSON)) } return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }, 3*time.Minute, 3*time.Second).ShouldNot(HaveOccurred()) }) It("delete the nginx resource", func() { diff --git a/test/e2e/setup/e2e_setup.sh b/test/e2e/setup/e2e_setup.sh index 3a18ce76..2c7a9d00 100755 --- a/test/e2e/setup/e2e_setup.sh +++ b/test/e2e/setup/e2e_setup.sh @@ -75,8 +75,7 @@ kubectl $1 apply -f ./test/e2e/setup/service-ca/ # 4. deploy maestro into maestro namespace export ENABLE_JWT=false export ENABLE_OCM_MOCK=true -export ENABLE_GRPC=true -export REPLICAS=2 +export ENABLE_GRPC_SERVER=true kubectl create namespace $namespace || true make template \ deploy-secrets \ diff --git a/test/helper.go b/test/helper.go index 8854e109..3955a940 100755 --- a/test/helper.go +++ b/test/helper.go @@ -77,7 +77,7 @@ type Helper struct { APIServer server.Server MetricsServer server.Server HealthCheckServer server.Server - PulseServer *server.PulseServer + EventServer server.EventServer ControllerManager *server.ControllersServer WorkAgentHolder *work.ClientHolder WorkAgentInformer workv1informers.ManifestWorkInformer @@ -138,7 +138,7 @@ func NewHelper(t *testing.T) *Helper { helper.startAPIServer() helper.startMetricsServer() helper.startHealthCheckServer() - helper.startPulseServer(helper.Ctx) + helper.startEventServer(helper.Ctx) }) helper.T = t return helper @@ -212,14 +212,14 @@ func (helper *Helper) sendShutdownSignal() error { return nil } -func (helper *Helper) startPulseServer(ctx context.Context) { +func (helper *Helper) startEventServer(ctx context.Context) { helper.Env().Config.PulseServer.PulseInterval = 1 helper.Env().Config.PulseServer.SubscriptionType = "broadcast" - helper.PulseServer = server.NewPulseServer(helper.EventBroadcaster) + helper.EventServer = server.NewPulseServer(helper.EventBroadcaster) go func() { - glog.V(10).Info("Test pulse server started") - helper.PulseServer.Start(ctx) - glog.V(10).Info("Test pulse server stopped") + glog.V(10).Info("Test event server started") + helper.EventServer.Start(ctx) + glog.V(10).Info("Test event server stopped") }() } @@ -232,7 +232,6 @@ func (helper *Helper) startEventBroadcaster() { } func (helper *Helper) StartControllerManager(ctx context.Context) { - sourceClient := helper.Env().Clients.CloudEventsSource helper.ControllerManager = &server.ControllersServer{ KindControllerManager: controllers.NewKindControllerManager( db.NewAdvisoryLockFactory(helper.Env().Database.SessionFactory), @@ -246,14 +245,14 @@ func (helper *Helper) StartControllerManager(ctx context.Context) { helper.ControllerManager.KindControllerManager.Add(&controllers.ControllerConfig{ Source: "Resources", Handlers: map[api.EventType][]controllers.ControllerHandlerFunc{ - api.CreateEventType: {sourceClient.OnCreate}, - api.UpdateEventType: {sourceClient.OnUpdate}, - api.DeleteEventType: {sourceClient.OnDelete}, + api.CreateEventType: {helper.EventServer.OnCreate}, + api.UpdateEventType: {helper.EventServer.OnUpdate}, + api.DeleteEventType: {helper.EventServer.OnDelete}, }, }) helper.ControllerManager.StatusController.Add(map[api.StatusEventType][]controllers.StatusHandlerFunc{ - api.StatusUpdateEventType: {helper.PulseServer.OnStatusUpdate}, - api.StatusDeleteEventType: {helper.PulseServer.OnStatusUpdate}, + api.StatusUpdateEventType: {helper.EventServer.OnStatusUpdate}, + api.StatusDeleteEventType: {helper.EventServer.OnStatusUpdate}, }) // start controller manager @@ -303,7 +302,7 @@ func (helper *Helper) StartWorkAgent(ctx context.Context, clusterName string, bu func (helper *Helper) StartGRPCResourceSourceClient() { store := NewStore() grpcOptions := grpcoptions.NewGRPCOptions() - grpcOptions.URL = fmt.Sprintf("%s:%s", helper.Env().Config.HTTPServer.Hostname, helper.Env().Config.GRPCServer.BindPort) + grpcOptions.URL = fmt.Sprintf("%s:%s", helper.Env().Config.HTTPServer.Hostname, helper.Env().Config.GRPCServer.ServerBindPort) sourceClient, err := generic.NewCloudEventSourceClient[*api.Resource]( helper.Ctx, grpcoptions.NewSourceOptions(grpcOptions, "maestro"), From 7b6ccda57eb76c7c60bcf3f11b72a90d46aae542 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Wed, 7 Aug 2024 16:44:08 +0800 Subject: [PATCH 10/67] remove work eviction test. (#170) Signed-off-by: morvencao --- test/e2e/pkg/work_eviction_test.go | 191 ----------------------------- 1 file changed, 191 deletions(-) delete mode 100644 test/e2e/pkg/work_eviction_test.go diff --git a/test/e2e/pkg/work_eviction_test.go b/test/e2e/pkg/work_eviction_test.go deleted file mode 100644 index 8f108738..00000000 --- a/test/e2e/pkg/work_eviction_test.go +++ /dev/null @@ -1,191 +0,0 @@ -package e2e_test - -import ( - "fmt" - "net/http" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - - "github.com/openshift-online/maestro/pkg/api/openapi" -) - -// go test -v ./test/e2e/pkg -args -api-server=$api_server -consumer-name=$consumer.Name -consumer-kubeconfig=$consumer_kubeconfig -ginkgo.focus "Applied Manifestwork Eviction" -var _ = Describe("Applied Manifestwork Eviction", Ordered, Label("e2e-tests-work-eviction"), func() { - var resource *openapi.Resource - var maestroServerReplicas int - - Context("Agent Appliedmanifestwork Eviction Grace Period Tests", func() { - It("post the nginx resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, 1) - var resp *http.Response - var err error - resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resource.Id).ShouldNot(BeEmpty()) - Expect(*resource.Version).To(Equal(int32(1))) - - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) - if err != nil { - return err - } - if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas, expected 1, got %d", *deploy.Spec.Replicas) - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("shut down maestro server", func() { - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Get(ctx, "maestro", metav1.GetOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - maestroServerReplicas = int(*deploy.Spec.Replicas) - - // patch maestro server replicas to 0 - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ - FieldManager: "testConsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) - - // ensure no running maestro server pods - Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ - LabelSelector: "app=maestro", - }) - if err != nil { - return err - } - if len(pods.Items) > 0 { - return fmt.Errorf("maestro server pods still running") - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("restart maestro agent", func() { - // patch maestro agent to restart it - restartPatchData := fmt.Sprintf(`{"spec": {"template": {"metadata": {"annotations": {"kubectl.kubernetes.io/restartedAt": "%s"}}}}}`, time.Now().Format("20060102150405")) - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro-agent").Patch(ctx, "maestro-agent", types.StrategicMergePatchType, []byte(restartPatchData), metav1.PatchOptions{ - FieldManager: "testconsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(1))) - - // ensure maestro agent is ready - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro-agent").Get(ctx, "maestro-agent", metav1.GetOptions{}) - if err != nil { - return err - } - if deploy != nil && deploy.Spec.Replicas != nil && *deploy.Spec.Replicas == deploy.Status.ReadyReplicas { - return nil - } - return fmt.Errorf("maestro agent deploy not ready") - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("ensure the nginx resource is evicted", func() { - Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) - if err != nil { - if errors.IsNotFound(err) { - return nil - } - return err - } - return fmt.Errorf("nginx deployment still exists") - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("start maestro server", func() { - // patch maestro server replicas to 1 - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroServerReplicas)), metav1.PatchOptions{ - FieldManager: "testConsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(maestroServerReplicas))) - - // ensure maestro server pod is up and running - Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ - LabelSelector: "app=maestro", - }) - if err != nil { - return err - } - if len(pods.Items) != maestroServerReplicas { - return fmt.Errorf("unexpected maestro server pod count, expected %d, got %d", maestroServerReplicas, len(pods.Items)) - } - for _, pod := range pods.Items { - if pod.Status.Phase != "Running" { - return fmt.Errorf("maestro server pod not in running state") - } - if pod.Status.ContainerStatuses[0].State.Running == nil { - return fmt.Errorf("maestro server container not in running state") - } - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("restart maestro agent again", func() { - // patch maestro agent to restart it - restartPatchData := fmt.Sprintf(`{"spec": {"template": {"metadata": {"annotations": {"kubectl.kubernetes.io/restartedAt": "%s"}}}}}`, time.Now().Format("20060102150405")) - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro-agent").Patch(ctx, "maestro-agent", types.StrategicMergePatchType, []byte(restartPatchData), metav1.PatchOptions{ - FieldManager: "testconsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(1))) - - // ensure maestro agent is ready - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro-agent").Get(ctx, "maestro-agent", metav1.GetOptions{}) - if err != nil { - return err - } - if deploy != nil && deploy.Spec.Replicas != nil && *deploy.Spec.Replicas == deploy.Status.ReadyReplicas { - return nil - } - return fmt.Errorf("maestro agent deploy not ready") - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("ensure the nginx resource is resynced", func() { - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) - if err != nil { - return err - } - if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas, expected 1, got %d", *deploy.Spec.Replicas) - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("delete the nginx resource", func() { - resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource.Id).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - - Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) - if err != nil { - if errors.IsNotFound(err) { - return nil - } - return err - } - return fmt.Errorf("nginx deployment still exists") - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - }) -}) - From b9e2822bf68c2f6300312c9b5188336ef0f4eb59 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 11:45:48 +0800 Subject: [PATCH 11/67] chore(deps): update docker.io/library/postgres docker tag to v16.4 (#175) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/integration-test.yaml | 2 +- .tekton/unit-test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.tekton/integration-test.yaml b/.tekton/integration-test.yaml index ef5e8f1e..ddd61cd3 100644 --- a/.tekton/integration-test.yaml +++ b/.tekton/integration-test.yaml @@ -110,7 +110,7 @@ spec: ) echo -n "$TEST_OUTPUT" | tee $(results.TEST_OUTPUT.path) sidecars: - - image: docker.io/library/postgres:16.3 + - image: docker.io/library/postgres:16.4 name: database-test env: - name: PGDATA diff --git a/.tekton/unit-test.yaml b/.tekton/unit-test.yaml index 5d5e84bc..23236283 100644 --- a/.tekton/unit-test.yaml +++ b/.tekton/unit-test.yaml @@ -110,7 +110,7 @@ spec: ) echo -n "$TEST_OUTPUT" | tee $(results.TEST_OUTPUT.path) sidecars: - - image: docker.io/library/postgres:16.3 + - image: docker.io/library/postgres:16.4 name: database-test env: - name: PGDATA From 34c1aa28e299e14a481d3140e9890e2d0e5d633b Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:47:40 +0800 Subject: [PATCH 12/67] chore(deps): update konflux references (#172) * chore(deps): update konflux references Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> * migrate from 0.1 to 0.2 --------- Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: Chunlin Yang --- .tekton/maestro-pull-request.yaml | 26 +++++++++++--------------- .tekton/maestro-push.yaml | 26 +++++++++++--------------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index 1715b6dd..957681de 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -41,7 +41,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:3ea2255c6ad2dd1074de45227deab51b69dba57901f44dbca80fe1c57646b107 + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8e0f8cad75e6f674d72a874385b69c4651afc0c9dcc59feffe0d85844687d852 - name: kind value: task resolver: bundles @@ -153,7 +153,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:61f1202766cd66242c8472b16aa7fa1a20f8d9a5d674cbad27ffd4b3d067e936 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:596b7c11572bb94eb67d9ffb4375068426e2a8249ff2792ce04ad2a4bc593a63 - name: kind value: task resolver: bundles @@ -170,7 +170,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:e1f7a275d722bc3147a65fcd772b16b54ccb6ce81c76939bc1052b2438dd2ccf + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:9e6c4db5a666ea0e1e747e03d63f46e5617a6b9852c26871f9d50891d778dfa2 - name: kind value: task resolver: bundles @@ -195,7 +195,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:fc03e91c047948f1e4906a82a7ad43c3ca35e66c9468c180f405e08affa73bbf + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:492db3ca0bf5c44b67a38ba937de645a5282be2cb447dc30d0227424ca3c736f - name: kind value: task resolver: bundles @@ -230,7 +230,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:2e49aeca14ec287ff5f57834532e6f5637300b2a88c2cb9bcc7c9286ca87760c + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:2b05d0463033cfab93dfa35691afb66ff09f2be39e96b856adee70baa970fab5 - name: kind value: task resolver: bundles @@ -246,8 +246,6 @@ spec: params: - name: BINARY_IMAGE value: $(params.output-image) - - name: BASE_IMAGES - value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) runAfter: - build-container taskRef: @@ -255,7 +253,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:b1e5a49fed40f9736242f5601d2accb6dba26669dfa1470d6c8d691b3ac46e81 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:929bf55a5e364c957a5f907a5516fb8f8893c389ae5985767de7311736eb904a - name: kind value: task resolver: bundles @@ -273,8 +271,6 @@ spec: workspace: workspace - name: deprecated-base-image-check params: - - name: BASE_IMAGES_DIGESTS - value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) - name: IMAGE_URL value: $(tasks.build-container.results.IMAGE_URL) - name: IMAGE_DIGEST @@ -286,7 +282,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:3f956e0cd9b0a183e4fd95e010aa668a788ef564d3af1f7aecaaf6e2ccc2ce93 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:6c389c2f670975cc0dfdd07dcb33142b1668bbfd46f6af520dd0ab736c56e7e9 - name: kind value: task resolver: bundles @@ -308,7 +304,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:3d9d05162d5807cde4431e80f0f126f4c19994c0c1633629a62ece9a43b966cd + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:fb1aa363b56f9e9bdb1b30a46ddace9035add63fdfb5e39d01b27ae84cc7e425 - name: kind value: task resolver: bundles @@ -325,7 +321,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:e6acf744313561b376b44724e81188f354b84cf3b0b3875e75efe7e0209637a2 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:1ef6a3ab9c4ba9e735c6924008714ef2a873597837be9d4d927522d5d733bd07 - name: kind value: task resolver: bundles @@ -350,7 +346,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:559d281b58584386a6faaf0e6641c814f9d877432d1a13bd03076745fffffaf1 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:cda1e319c81a32356d900b2f78483e072fac29684ad81c73aa2314a7f3a389e0 - name: kind value: task resolver: bundles @@ -372,7 +368,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:d34362be8843715b1bcdaf55fcbf1be315094e0dc840562c5cec22716a37a1fe + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:501181e78ec76a0a9083ffc275f5307ba5653a762259412bcffaeb314f13f8ec - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index d58bdc80..d754285b 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -38,7 +38,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:3ea2255c6ad2dd1074de45227deab51b69dba57901f44dbca80fe1c57646b107 + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8e0f8cad75e6f674d72a874385b69c4651afc0c9dcc59feffe0d85844687d852 - name: kind value: task resolver: bundles @@ -150,7 +150,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:61f1202766cd66242c8472b16aa7fa1a20f8d9a5d674cbad27ffd4b3d067e936 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:596b7c11572bb94eb67d9ffb4375068426e2a8249ff2792ce04ad2a4bc593a63 - name: kind value: task resolver: bundles @@ -167,7 +167,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:e1f7a275d722bc3147a65fcd772b16b54ccb6ce81c76939bc1052b2438dd2ccf + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:9e6c4db5a666ea0e1e747e03d63f46e5617a6b9852c26871f9d50891d778dfa2 - name: kind value: task resolver: bundles @@ -192,7 +192,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:fc03e91c047948f1e4906a82a7ad43c3ca35e66c9468c180f405e08affa73bbf + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:492db3ca0bf5c44b67a38ba937de645a5282be2cb447dc30d0227424ca3c736f - name: kind value: task resolver: bundles @@ -227,7 +227,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:2e49aeca14ec287ff5f57834532e6f5637300b2a88c2cb9bcc7c9286ca87760c + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:2b05d0463033cfab93dfa35691afb66ff09f2be39e96b856adee70baa970fab5 - name: kind value: task resolver: bundles @@ -243,8 +243,6 @@ spec: params: - name: BINARY_IMAGE value: $(params.output-image) - - name: BASE_IMAGES - value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) runAfter: - build-container taskRef: @@ -252,7 +250,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:b1e5a49fed40f9736242f5601d2accb6dba26669dfa1470d6c8d691b3ac46e81 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:929bf55a5e364c957a5f907a5516fb8f8893c389ae5985767de7311736eb904a - name: kind value: task resolver: bundles @@ -270,8 +268,6 @@ spec: workspace: workspace - name: deprecated-base-image-check params: - - name: BASE_IMAGES_DIGESTS - value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) - name: IMAGE_URL value: $(tasks.build-container.results.IMAGE_URL) - name: IMAGE_DIGEST @@ -283,7 +279,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:3f956e0cd9b0a183e4fd95e010aa668a788ef564d3af1f7aecaaf6e2ccc2ce93 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:6c389c2f670975cc0dfdd07dcb33142b1668bbfd46f6af520dd0ab736c56e7e9 - name: kind value: task resolver: bundles @@ -305,7 +301,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:3d9d05162d5807cde4431e80f0f126f4c19994c0c1633629a62ece9a43b966cd + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:fb1aa363b56f9e9bdb1b30a46ddace9035add63fdfb5e39d01b27ae84cc7e425 - name: kind value: task resolver: bundles @@ -322,7 +318,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:e6acf744313561b376b44724e81188f354b84cf3b0b3875e75efe7e0209637a2 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:1ef6a3ab9c4ba9e735c6924008714ef2a873597837be9d4d927522d5d733bd07 - name: kind value: task resolver: bundles @@ -347,7 +343,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:559d281b58584386a6faaf0e6641c814f9d877432d1a13bd03076745fffffaf1 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:cda1e319c81a32356d900b2f78483e072fac29684ad81c73aa2314a7f3a389e0 - name: kind value: task resolver: bundles @@ -369,7 +365,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:d34362be8843715b1bcdaf55fcbf1be315094e0dc840562c5cec22716a37a1fe + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:501181e78ec76a0a9083ffc275f5307ba5653a762259412bcffaeb314f13f8ec - name: kind value: task resolver: bundles From 835c653cf656e1b12549ddce07636bd9b8b99be1 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Wed, 14 Aug 2024 14:02:26 +0800 Subject: [PATCH 13/67] avoid do full list on the client part (#167) Signed-off-by: Wei Liu --- examples/manifestworkclient/README.md | 44 ++++- go.mod | 2 +- go.sum | 2 + .../cloudevents/grpcsource/mock/maestro.go | 94 ++++++++++ pkg/client/cloudevents/grpcsource/pager.go | 104 +++++++++++ .../cloudevents/grpcsource/pager_test.go | 169 ++++++++++++++++++ .../cloudevents/grpcsource/watcherstore.go | 53 ++---- 7 files changed, 430 insertions(+), 38 deletions(-) create mode 100644 pkg/client/cloudevents/grpcsource/mock/maestro.go create mode 100644 pkg/client/cloudevents/grpcsource/pager.go create mode 100644 pkg/client/cloudevents/grpcsource/pager_test.go diff --git a/examples/manifestworkclient/README.md b/examples/manifestworkclient/README.md index 25b1ecf0..957833a9 100644 --- a/examples/manifestworkclient/README.md +++ b/examples/manifestworkclient/README.md @@ -1,6 +1,6 @@ # gRPC Source ManifestWork Client -This example shows how to build a source ManifestWork client with Maestro gRPC service and watch/create/get/update/delete works by this client. +This example shows how to build a source ManifestWork client with Maestro gRPC service and watch/get/list/create/patch/delete works by this client. ## Build the client @@ -18,7 +18,47 @@ if err != nil { log.Fatal(err) } -// watch/create/patch/get/delete/list by workClient +// watch/get/list/create/patch/delete by workClient +``` + +## List works + +The `List` of the gRPC source ManifestWork client supports to paging list works, this will help to list the works when there are a lot of works in the maestro sever, e.g. + +```golang + +workClient, err := ... + +// There are 2500 works in the maestro, we will list these works with paging + +// First list: this will return 1000 (this is controlled by `ListOptions.Limit`) works and +// with a next page (2) in the `workList.ListMeta.Continue` +workList, err := workClient.ManifestWorks(metav1.NamespaceAll).List(ctx, metav1.ListOptions{ + Limit: 1000 +}) +if err != nil { + log.Fatal(err) +} + +// Second list: we list works with last returned `ListMeta.Continue`, this will also return +// 1000 works and with a next page (3) in the `workList.ListMeta.Continue` +workList, err = workClient.ManifestWorks(metav1.NamespaceAll).List(ctx, metav1.ListOptions{ + Limit: 1000, + Continue: workList.ListMeta.Continue, +}) +if err != nil { + log.Fatal(err) +} + +// Third list: we also list works with last returned `ListMeta.Continue`, this will return +// all remaining works (500) and the `workList.ListMeta.Continue` will be empty +workList, err = workClient.ManifestWorks(metav1.NamespaceAll).List(ctx, metav1.ListOptions{ + Limit: 1000, + Continue: workList.ListMeta.Continue, +}) +if err != nil { + log.Fatal(err) +} ``` diff --git a/go.mod b/go.mod index 5f926076..3d6bd08b 100755 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( k8s.io/klog/v2 v2.120.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 - open-cluster-management.io/sdk-go v0.14.1-0.20240717021054-955108a181ee + open-cluster-management.io/sdk-go v0.14.1-0.20240806021439-bf354ff3847f ) require ( diff --git a/go.sum b/go.sum index 1d700872..23a78743 100755 --- a/go.sum +++ b/go.sum @@ -827,6 +827,8 @@ open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 h1:7uPjyn1x open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33/go.mod h1:KzUwhPZAg6Wq+4xRu10fVVpqNADyz5CtRW4ziqIC2z4= open-cluster-management.io/sdk-go v0.14.1-0.20240717021054-955108a181ee h1:aQ4AoR8SKz/byOyZbbYC9Tbp4VCtRHje8uHbn438o84= open-cluster-management.io/sdk-go v0.14.1-0.20240717021054-955108a181ee/go.mod h1:xFmN3Db5nN68oLGnstmIRv4us8HJCdXFnBNMXVp0jWY= +open-cluster-management.io/sdk-go v0.14.1-0.20240806021439-bf354ff3847f h1:8yQ8uFemyM/dI4nMo8pVOmEiIn156SkN9qpnLf8UOcI= +open-cluster-management.io/sdk-go v0.14.1-0.20240806021439-bf354ff3847f/go.mod h1:xFmN3Db5nN68oLGnstmIRv4us8HJCdXFnBNMXVp0jWY= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= diff --git a/pkg/client/cloudevents/grpcsource/mock/maestro.go b/pkg/client/cloudevents/grpcsource/mock/maestro.go new file mode 100644 index 00000000..41c097c2 --- /dev/null +++ b/pkg/client/cloudevents/grpcsource/mock/maestro.go @@ -0,0 +1,94 @@ +package mock + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "strconv" + "time" + + "github.com/openshift-online/maestro/pkg/api/openapi" +) + +type ResourceBundlesStore struct { + items []openapi.ResourceBundle +} + +func (g *ResourceBundlesStore) Get() []openapi.ResourceBundle { + return g.items +} + +func (g *ResourceBundlesStore) Set(items []openapi.ResourceBundle) { + g.items = items +} + +type MaestroMockServer struct { + server *httptest.Server +} + +func NewMaestroMockServer(store *ResourceBundlesStore) *MaestroMockServer { + mockServer := &MaestroMockServer{} + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + list := &openapi.ResourceBundleList{} + page, _ := strconv.Atoi(r.URL.Query().Get("page")) + size, _ := strconv.Atoi(r.URL.Query().Get("size")) + + items := store.Get() + index := ((page - 1) * size) + for i := 0; i < size; i++ { + if index >= len(items) { + break + } + list.Items = append(list.Items, items[index]) + index = index + 1 + } + + list.Page = int32(page) + list.Total = int32(len(items)) + list.Size = int32(len(list.Items)) + data, _ := json.Marshal(list) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write(data) + default: + w.WriteHeader(http.StatusNotImplemented) + } + }) + + mockServer.server = httptest.NewUnstartedServer(handler) + return mockServer +} + +func (m *MaestroMockServer) URL() string { + return m.server.URL +} + +func (m *MaestroMockServer) Start() { + m.server.Start() +} + +func (m *MaestroMockServer) Stop() { + m.server.Close() +} + +func NewMaestroAPIClient(maestroServerAddress string) *openapi.APIClient { + cfg := &openapi.Configuration{ + DefaultHeader: make(map[string]string), + UserAgent: "OpenAPI-Generator/1.0.0/go", + Debug: false, + Servers: openapi.ServerConfigurations{ + { + URL: maestroServerAddress, + Description: "current domain", + }, + }, + OperationServers: map[string]openapi.ServerConfigurations{}, + HTTPClient: &http.Client{ + Timeout: 10 * time.Second, + }, + } + return openapi.NewAPIClient(cfg) +} diff --git a/pkg/client/cloudevents/grpcsource/pager.go b/pkg/client/cloudevents/grpcsource/pager.go new file mode 100644 index 00000000..015d1b4a --- /dev/null +++ b/pkg/client/cloudevents/grpcsource/pager.go @@ -0,0 +1,104 @@ +package grpcsource + +import ( + "context" + "fmt" + "strconv" + + "github.com/openshift-online/maestro/pkg/api/openapi" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" +) + +// MaxListPageSize is the maximum size of one page, default is 400. +// NOTE: This should be reset carefully, when increasing this value, both maestro server's memory limit +// and the page size of resources need to be considered, if a bigger value is used, it might lead to +// maestro server OOM. +var MaxListPageSize int32 = 400 + +// pageList assists client code in breaking large list queries into multiple smaller chunks of PageSize or smaller. +func pageList(client *openapi.APIClient, search string, opts metav1.ListOptions) (*openapi.ResourceBundleList, string, error) { + items := []openapi.ResourceBundle{} + + page, err := page(opts) + if err != nil { + return nil, "", err + } + + limit := opts.Limit + if limit < 0 { + return nil, "", fmt.Errorf("limit cannot be less than 0") + } + + var total int32 = 0 + nextPage := "" + pageSize := pageSize(int32(limit)) + offset := (page - 1) * pageSize + for { + klog.V(4).Infof("list works with search=%s, page=%d, size=%d", search, page, pageSize) + rbs, _, err := client.DefaultApi.ApiMaestroV1ResourceBundlesGet(context.Background()). + Search(search). + Page(page). + Size(pageSize). + Execute() + if err != nil { + return nil, "", err + } + klog.V(4).Infof("listed works total=%d, page=%d, size=%d", rbs.Total, rbs.Page, rbs.Size) + + items = append(items, rbs.Items...) + total = rbs.Size + total + page = page + 1 + + if rbs.Size < pageSize { + // reaches the last page, stop list + break + } + + if limit == 0 { + // no limit, continue to list the rest of items + continue + } + + if total == int32(limit) { + // reaches the limit, stop list + if (total + offset) < rbs.Total { + // the listed items reach the limit size, but there are still items left + nextPage = fmt.Sprintf("%d", page) + } + + break + } + } + + return &openapi.ResourceBundleList{Items: items}, nextPage, nil +} + +func page(opts metav1.ListOptions) (int32, error) { + if len(opts.Continue) == 0 { + return 1, nil + } + + page, err := strconv.Atoi(opts.Continue) + if err != nil { + return 0, fmt.Errorf("a page number is required, %v", err) + } + + if page < 0 { + return 0, fmt.Errorf("an invalid page number %d", page) + } + + return int32(page), nil +} + +func pageSize(limit int32) int32 { + if limit > MaxListPageSize { + return MaxListPageSize + } + + if limit == 0 { + return MaxListPageSize + } + + return limit +} diff --git a/pkg/client/cloudevents/grpcsource/pager_test.go b/pkg/client/cloudevents/grpcsource/pager_test.go new file mode 100644 index 00000000..b3c630d4 --- /dev/null +++ b/pkg/client/cloudevents/grpcsource/pager_test.go @@ -0,0 +1,169 @@ +package grpcsource + +import ( + "testing" + + "github.com/openshift-online/maestro/pkg/api/openapi" + "github.com/openshift-online/maestro/pkg/client/cloudevents/grpcsource/mock" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestPageList(t *testing.T) { + getter := &mock.ResourceBundlesStore{} + maestroServer := mock.NewMaestroMockServer(getter) + maestroServer.Start() + defer maestroServer.Stop() + + client := mock.NewMaestroAPIClient(maestroServer.URL()) + cases := []struct { + name string + resourceBundles []openapi.ResourceBundle + listOpts metav1.ListOptions + expectedItemsLen int + expectedNext string + }{ + { + name: "no items", + resourceBundles: resourceBundles(0), + listOpts: metav1.ListOptions{}, + expectedItemsLen: 0, + expectedNext: "", + }, + { + name: "list all items (items < MaxListPageSize)", + resourceBundles: resourceBundles(200), + listOpts: metav1.ListOptions{}, + expectedItemsLen: 200, + expectedNext: "", + }, + { + name: "list all items (items = MaxListPageSize)", + resourceBundles: resourceBundles(400), + listOpts: metav1.ListOptions{}, + expectedItemsLen: 400, + expectedNext: "", + }, + { + name: "list all items (items > MaxListPageSize)", + resourceBundles: resourceBundles(429), + listOpts: metav1.ListOptions{}, + expectedItemsLen: 429, + expectedNext: "", + }, + { + name: "list items (limit > total items)", + resourceBundles: resourceBundles(429), + listOpts: metav1.ListOptions{ + Limit: 500, + }, + expectedItemsLen: 429, + expectedNext: "", + }, + { + name: "list items (limit < total items)", + resourceBundles: resourceBundles(429), + listOpts: metav1.ListOptions{ + Limit: 400, + }, + expectedItemsLen: 400, + expectedNext: "2", + }, + { + name: "list items (limit < total items)", + resourceBundles: resourceBundles(429), + listOpts: metav1.ListOptions{ + Limit: 40, + }, + expectedItemsLen: 40, + expectedNext: "2", + }, + { + name: "list items with continue (from last page - 1)", + resourceBundles: resourceBundles(429), + listOpts: metav1.ListOptions{ + Limit: 100, + Continue: "4", + }, + expectedItemsLen: 100, + expectedNext: "5", + }, + { + name: "list items with continue (from page last page)", + resourceBundles: resourceBundles(429), + listOpts: metav1.ListOptions{ + Limit: 100, + Continue: "5", + }, + expectedItemsLen: 29, + expectedNext: "", + }, + { + name: "list items with continue (from page last page + 1)", + resourceBundles: resourceBundles(429), + listOpts: metav1.ListOptions{ + Limit: 100, + Continue: "6", + }, + expectedItemsLen: 0, + expectedNext: "", + }, + { + name: "list items with continue and max limit", + resourceBundles: resourceBundles(1229), + listOpts: metav1.ListOptions{ + Limit: 400, + Continue: "3", + }, + expectedItemsLen: 400, + expectedNext: "4", + }, + { + name: "list items with continue and max limit", + resourceBundles: resourceBundles(1229), + listOpts: metav1.ListOptions{ + Limit: 400, + Continue: "4", + }, + expectedItemsLen: 29, + expectedNext: "", + }, + { + name: "list items with continue and max limit", + resourceBundles: resourceBundles(1229), + listOpts: metav1.ListOptions{ + Limit: 400, + Continue: "5", + }, + expectedItemsLen: 0, + expectedNext: "", + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + getter.Set(c.resourceBundles) + + list, next, err := pageList(client, "", c.listOpts) + if err != nil { + t.Errorf("unexpected error %v", err) + } + + if len(list.Items) != c.expectedItemsLen { + t.Errorf("expected items length %v, but got %v", c.expectedItemsLen, len(list.Items)) + } + + if next != c.expectedNext { + t.Errorf("expected next %v, but got %v", c.expectedNext, next) + } + }) + + } +} + +func resourceBundles(total int) []openapi.ResourceBundle { + items := []openapi.ResourceBundle{} + for i := 0; i < total; i++ { + items = append(items, openapi.ResourceBundle{}) + } + return items +} diff --git a/pkg/client/cloudevents/grpcsource/watcherstore.go b/pkg/client/cloudevents/grpcsource/watcherstore.go index aa5bd77b..aaaf1f37 100644 --- a/pkg/client/cloudevents/grpcsource/watcherstore.go +++ b/pkg/client/cloudevents/grpcsource/watcherstore.go @@ -82,11 +82,8 @@ func (m *RESTFulAPIWatcherStore) GetWatcher(namespace string, opts metav1.ListOp searches = append(searches, labelSearch) } - rbs, _, err := m.apiClient.DefaultApi.ApiMaestroV1ResourceBundlesGet(context.Background()). - Search(strings.Join(searches, " and ")). - Page(1). - Size(-1). - Execute() + // for watch, we need list all works with the search condition from maestro server + rbs, _, err := pageList(m.apiClient, strings.Join(searches, " and "), metav1.ListOptions{}) if err != nil { return nil, err } @@ -145,17 +142,9 @@ func (m *RESTFulAPIWatcherStore) Get(namespace, name string) (*workv1.ManifestWo } // List works from maestro server with a specified namespace and list options. -// Using `metav1.NamespaceAll` to specify all namespace -func (m *RESTFulAPIWatcherStore) List(namespace string, opts metav1.ListOptions) ([]*workv1.ManifestWork, error) { - works := []*workv1.ManifestWork{} - - // TODO consider how to support configuring page - var page int32 = 1 - - var size int32 = -1 - if opts.Limit > 0 { - size = int32(opts.Limit) - } +// Using `metav1.NamespaceAll` to specify all namespace. +func (m *RESTFulAPIWatcherStore) List(namespace string, opts metav1.ListOptions) (*workv1.ManifestWorkList, error) { + works := []workv1.ManifestWork{} _, labelSearch, selectable, err := ToLabelSearch(opts) if err != nil { @@ -171,14 +160,7 @@ func (m *RESTFulAPIWatcherStore) List(namespace string, opts metav1.ListOptions) searches = append(searches, labelSearch) } - search := strings.Join(searches, " and ") - klog.V(4).Infof("list works with search=%s", search) - - rbs, _, err := m.apiClient.DefaultApi.ApiMaestroV1ResourceBundlesGet(context.Background()). - Search(search). - Page(page). - Size(size). - Execute() + rbs, nextPage, err := pageList(m.apiClient, strings.Join(searches, " and "), opts) if err != nil { return nil, err } @@ -189,28 +171,32 @@ func (m *RESTFulAPIWatcherStore) List(namespace string, opts metav1.ListOptions) return nil, err } - works = append(works, work) + works = append(works, *work) } - return works, nil + return &workv1.ManifestWorkList{ + ListMeta: metav1.ListMeta{Continue: nextPage}, + Items: works, + }, nil } func (m *RESTFulAPIWatcherStore) ListAll() ([]*workv1.ManifestWork, error) { - return m.List(metav1.NamespaceAll, metav1.ListOptions{}) + // for RESTFulAPIWatcherStore, this will not be called by manifestwork client, do nothing + return nil, nil } func (m *RESTFulAPIWatcherStore) Add(work *workv1.ManifestWork) error { - // do nothing + // for RESTFulAPIWatcherStore, this will not be called by manifestwork client, do nothing return nil } func (m *RESTFulAPIWatcherStore) Update(work *workv1.ManifestWork) error { - // do nothing + // for RESTFulAPIWatcherStore, this will not be called by manifestwork client, do nothing return nil } func (m *RESTFulAPIWatcherStore) Delete(work *workv1.ManifestWork) error { - // do nothing + // for RESTFulAPIWatcherStore, this will not be called by manifestwork client, do nothing return nil } @@ -243,11 +229,8 @@ func (m *RESTFulAPIWatcherStore) Sync() error { search = append(search, namespaces...) } - rbs, _, err := m.apiClient.DefaultApi.ApiMaestroV1ResourceBundlesGet(context.Background()). - Search(strings.Join(search, " or ")). - Page(1). - Size(-1). - Execute() + // for sync, we need list all works with the search condition from maestro server + rbs, _, err := pageList(m.apiClient, strings.Join(search, " or "), metav1.ListOptions{}) if err != nil { return err } From 39b68cb01f7e2019a08e07a32d8114b849f291dd Mon Sep 17 00:00:00 2001 From: Camilo Cota <1499184+ccronca@users.noreply.github.com> Date: Wed, 14 Aug 2024 08:13:03 +0200 Subject: [PATCH 14/67] fix(KONFLUX-3663): format PipelineRun files and upload SAST results (#177) * fix(KONFLUX-3663): format Tekton PipelineRun files Format PipelineRun files with yq for consistent indentation and format Signed-off-by: ccronca * fix(KONFLUX-3663): upload SAST results to quay.io Configure the SAST task to upload SARIF results to quay.io for long-term storage Signed-off-by: ccronca --------- Signed-off-by: ccronca --- .tekton/maestro-pull-request.yaml | 19 ++++++++++--------- .tekton/maestro-push.yaml | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index 957681de..04c8d40a 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -7,8 +7,7 @@ metadata: build.appstudio.redhat.com/pull_request_number: '{{pull_request_number}}' build.appstudio.redhat.com/target_branch: '{{target_branch}}' pipelinesascode.tekton.dev/max-keep-runs: "3" - pipelinesascode.tekton.dev/on-cel-expression: event == "pull_request" && target_branch - == "main" + pipelinesascode.tekton.dev/on-cel-expression: event == "pull_request" && target_branch == "main" creationTimestamp: null labels: appstudio.openshift.io/application: maestro @@ -76,13 +75,11 @@ spec: name: output-image type: string - default: . - description: Path to the source code of an application's component from where - to build image. + description: Path to the source code of an application's component from where to build image. name: path-context type: string - default: Dockerfile - description: Path to the Dockerfile inside the context specified by parameter - path-context + description: Path to the Dockerfile inside the context specified by parameter path-context name: dockerfile type: string - default: "false" @@ -110,8 +107,7 @@ spec: name: java type: string - default: "" - description: Image tag expiration time, time values could be something like - 1h, 2d, 3w for hours, days, and weeks, respectively. + description: Image tag expiration time, time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively. name: image-expires-after - default: "false" description: Build a source image. @@ -315,7 +311,7 @@ spec: - "false" - name: sast-snyk-check runAfter: - - clone-repository + - build-container taskRef: params: - name: name @@ -333,6 +329,11 @@ spec: workspaces: - name: workspace workspace: workspace + params: + - name: image-digest + value: $(tasks.build-container.results.IMAGE_DIGEST) + - name: image-url + value: $(tasks.build-container.results.IMAGE_URL) - name: clamav-scan params: - name: image-digest diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index d754285b..1b47f03a 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -6,8 +6,7 @@ metadata: build.appstudio.redhat.com/commit_sha: '{{revision}}' build.appstudio.redhat.com/target_branch: '{{target_branch}}' pipelinesascode.tekton.dev/max-keep-runs: "3" - pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch - == "main" + pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch == "main" creationTimestamp: null labels: appstudio.openshift.io/application: maestro @@ -73,13 +72,11 @@ spec: name: output-image type: string - default: . - description: Path to the source code of an application's component from where - to build image. + description: Path to the source code of an application's component from where to build image. name: path-context type: string - default: Dockerfile - description: Path to the Dockerfile inside the context specified by parameter - path-context + description: Path to the Dockerfile inside the context specified by parameter path-context name: dockerfile type: string - default: "false" @@ -107,8 +104,7 @@ spec: name: java type: string - default: "" - description: Image tag expiration time, time values could be something like - 1h, 2d, 3w for hours, days, and weeks, respectively. + description: Image tag expiration time, time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively. name: image-expires-after - default: "false" description: Build a source image. @@ -312,7 +308,7 @@ spec: - "false" - name: sast-snyk-check runAfter: - - clone-repository + - build-container taskRef: params: - name: name @@ -330,6 +326,11 @@ spec: workspaces: - name: workspace workspace: workspace + params: + - name: image-digest + value: $(tasks.build-container.results.IMAGE_DIGEST) + - name: image-url + value: $(tasks.build-container.results.IMAGE_URL) - name: clamav-scan params: - name: image-digest From 87773f16871b855c84f8d3d4f536917b839cdce5 Mon Sep 17 00:00:00 2001 From: Chunlin Yang Date: Wed, 14 Aug 2024 16:28:53 +0800 Subject: [PATCH 15/67] Fix integration issues (#174) Signed-off-by: clyang82 --- Makefile | 2 +- test/factories.go | 1 + test/integration/consumers_test.go | 3 +- test/integration/controller_test.go | 26 ++++---- test/integration/pulse_server_test.go | 31 +++------ test/integration/resource_test.go | 93 +++++++++++---------------- 6 files changed, 63 insertions(+), 93 deletions(-) diff --git a/Makefile b/Makefile index 91a64d29..5126a8d0 100755 --- a/Makefile +++ b/Makefile @@ -117,7 +117,7 @@ help: # Encourage consistent tool versions OPENAPI_GENERATOR_VERSION:=5.4.0 -GO_VERSION:=go1.21. +GO_VERSION:=go1.22. ### Constants: version:=$(shell date +%s) diff --git a/test/factories.go b/test/factories.go index 20d9e1ea..d9331a20 100755 --- a/test/factories.go +++ b/test/factories.go @@ -220,6 +220,7 @@ func (helper *Helper) CreateResource(consumerName string, replicas int) *api.Res func (helper *Helper) CreateResourceList(consumerName string, count int) (resources []*api.Resource) { for i := 1; i <= count; i++ { resources = append(resources, helper.CreateResource(consumerName, 1)) + time.Sleep(10 * time.Millisecond) } return resources } diff --git a/test/integration/consumers_test.go b/test/integration/consumers_test.go index 87cfdbe3..bbb75bbc 100644 --- a/test/integration/consumers_test.go +++ b/test/integration/consumers_test.go @@ -9,6 +9,7 @@ import ( . "github.com/onsi/gomega" "gopkg.in/resty.v1" + "k8s.io/apimachinery/pkg/util/rand" "github.com/openshift-online/maestro/pkg/api/openapi" "github.com/openshift-online/maestro/test" @@ -29,7 +30,7 @@ func TestConsumerGet(t *testing.T) { Expect(err).To(HaveOccurred(), "Expected 404") Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) - consumer := h.CreateConsumerWithLabels("cluster1", map[string]string{"foo": "bar"}) + consumer := h.CreateConsumerWithLabels("cluster-"+rand.String(5), map[string]string{"foo": "bar"}) found, resp, err := client.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, consumer.ID).Execute() Expect(err).NotTo(HaveOccurred()) diff --git a/test/integration/controller_test.go b/test/integration/controller_test.go index 8b365c9f..74c6c51b 100755 --- a/test/integration/controller_test.go +++ b/test/integration/controller_test.go @@ -13,6 +13,7 @@ import ( "github.com/openshift-online/maestro/pkg/dao" "github.com/openshift-online/maestro/pkg/db" "github.com/openshift-online/maestro/test" + "k8s.io/apimachinery/pkg/util/rand" ) func TestControllerRacing(t *testing.T) { @@ -20,6 +21,9 @@ func TestControllerRacing(t *testing.T) { account := h.NewRandAccount() ctx, cancel := context.WithCancel(h.NewAuthenticatedContext(account)) + defer func() { + cancel() + }() eventDao := dao.NewEventDao(&h.Env().Database.SessionFactory) statusEventDao := dao.NewStatusEventDao(&h.Env().Database.SessionFactory) @@ -33,7 +37,6 @@ func TestControllerRacing(t *testing.T) { if err != nil { return err } - for _, evt := range events { if evt.SourceID != id { continue @@ -89,31 +92,30 @@ func TestControllerRacing(t *testing.T) { Source: "Resources", Handlers: map[api.EventType][]controllers.ControllerHandlerFunc{ api.CreateEventType: {onUpsert}, - api.UpdateEventType: {onUpsert}, }, }) s.StatusController.Add(map[api.StatusEventType][]controllers.StatusHandlerFunc{ api.StatusUpdateEventType: {onStatusUpdate}, - api.StatusDeleteEventType: {onStatusUpdate}, }) s.Start(ctx) }() } + // wait for controller service starts + time.Sleep(3 * time.Second) - consumer := h.CreateConsumer("cluster1") - h.StartWorkAgent(ctx, consumer.Name, false) + consumer := h.CreateConsumer("cluster-" + rand.String(5)) resources := h.CreateResourceList(consumer.Name, 50) // This is to check only 50 create events are processed. It waits for 5 seconds to ensure all events have been // processed by the controllers. Eventually(func() error { if len(proccessedEvent) != 50 { - return fmt.Errorf("should have only 50 create events but got %d", len(proccessedEvent)) + return fmt.Errorf("should have 50 create events but got %d", len(proccessedEvent)) } return nil - }, 5*time.Second, 1*time.Second).Should(Succeed()) + }, 10*time.Second, 1*time.Second).Should(Succeed()) // create 50 update status events for _, resource := range resources { @@ -124,19 +126,17 @@ func TestControllerRacing(t *testing.T) { if sErr != nil { t.Fatalf("failed to create status event: %v", sErr) } + time.Sleep(10 * time.Millisecond) } - // This is to check 150 status update events are processed. It waits for 5 seconds to ensure all status events have been + // This is to check 150 status update events are processed. It waits for 10 seconds to ensure all status events have been // processed by the controllers. Eventually(func() error { if len(processedStatusEvent) != threads*50 { return fmt.Errorf("should have 150 update status events but got %d", len(processedStatusEvent)) } return nil - }, 5*time.Second, 1*time.Second).Should(Succeed()) - - // cancel the context to stop the controller manager - cancel() + }, 10*time.Second, 1*time.Second).Should(Succeed()) } func TestControllerReconcile(t *testing.T) { @@ -201,7 +201,7 @@ func TestControllerReconcile(t *testing.T) { // wait for the listener to start time.Sleep(100 * time.Millisecond) - consumer := h.CreateConsumer("cluster1") + consumer := h.CreateConsumer("cluster-" + rand.String(5)) resource := h.CreateResource(consumer.Name, 1) // Eventually, the event will be processed by the controller. diff --git a/test/integration/pulse_server_test.go b/test/integration/pulse_server_test.go index 88947c1b..d838b47a 100644 --- a/test/integration/pulse_server_test.go +++ b/test/integration/pulse_server_test.go @@ -8,7 +8,6 @@ import ( . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" workv1 "open-cluster-management.io/api/work/v1" "github.com/openshift-online/maestro/pkg/api" @@ -19,22 +18,18 @@ import ( func TestPulseServer(t *testing.T) { h, _ := test.RegisterIntegration(t) ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + defer func() { + cancel() + }() instanceDao := dao.NewInstanceDao(&h.Env().Database.SessionFactory) - // insert two existing instances + // insert one existing instances _, err := instanceDao.UpSert(ctx, &api.ServerInstance{ Meta: api.Meta{ ID: "instance1", }, }) Expect(err).NotTo(HaveOccurred()) - _, err = instanceDao.UpSert(ctx, &api.ServerInstance{ - Meta: api.Meta{ - ID: "instance2", - }, - }) - Expect(err).NotTo(HaveOccurred()) instanceID := &h.Env().Config.MessageBroker.ClientID Eventually(func() error { @@ -59,16 +54,19 @@ func TestPulseServer(t *testing.T) { return nil }, 10*time.Second, 1*time.Second).Should(Succeed()) + // the cluster1 name cannot be changed, because consistent hash makes it allocate to different instance. + // the case here we want to the new consumer allocate to new instance(cluster1) which is a fake instance. + // after 3*pulseInterval (3s), it will relocate to maestro instance. clusterName := "cluster1" consumer := h.CreateConsumer(clusterName) - // insert a new instance with the same name to consumer name "cluster1" + // insert a new instance with the same name to consumer name // to make sure the consumer is hashed to the new instance firstly. // after the new instance is stale after 3*pulseInterval (3s), the current // instance will take over the consumer and resync the resource status. _, err = instanceDao.UpSert(ctx, &api.ServerInstance{ Meta: api.Meta{ - ID: "cluster1", + ID: clusterName, }, }) Expect(err).NotTo(HaveOccurred()) @@ -78,22 +76,11 @@ func TestPulseServer(t *testing.T) { h.StartWorkAgent(ctx, consumer.Name, false) clientHolder := h.WorkAgentHolder informer := h.WorkAgentInformer - lister := informer.Lister().ManifestWorks(consumer.Name) agentWorkClient := clientHolder.ManifestWorks(consumer.Name) resourceService := h.Env().Services.Resources() var work *workv1.ManifestWork Eventually(func() error { - list, err := lister.List(labels.Everything()) - if err != nil { - return err - } - - // ensure there is only one work was synced on the cluster - if len(list) != 1 { - return fmt.Errorf("unexpected work list %v", list) - } - // ensure the work can be get by work client work, err = agentWorkClient.Get(ctx, res.ID, metav1.GetOptions{}) if err != nil { diff --git a/test/integration/resource_test.go b/test/integration/resource_test.go index e11436bb..aa306068 100755 --- a/test/integration/resource_test.go +++ b/test/integration/resource_test.go @@ -14,7 +14,7 @@ import ( "gopkg.in/resty.v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/rand" workv1 "open-cluster-management.io/api/work/v1" "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" "open-cluster-management.io/sdk-go/pkg/cloudevents/work/common" @@ -42,7 +42,7 @@ func TestResourceGet(t *testing.T) { Expect(err).To(HaveOccurred(), "Expected 404") Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) - consumer := h.CreateConsumer("cluster1") + consumer := h.CreateConsumer("cluster-" + rand.String(5)) resource := h.CreateResource(consumer.Name, 1) res, resp, err := client.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, resource.ID).Execute() @@ -61,17 +61,18 @@ func TestResourcePost(t *testing.T) { h, client := test.RegisterIntegration(t) account := h.NewRandAccount() ctx, cancel := context.WithCancel(h.NewAuthenticatedContext(account)) + defer func() { + cancel() + }() - clusterName := "cluster1" + clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) res := h.NewAPIResource(consumer.Name, 1) h.StartControllerManager(ctx) h.StartWorkAgent(ctx, consumer.Name, false) clientHolder := h.WorkAgentHolder informer := h.WorkAgentInformer - lister := informer.Lister().ManifestWorks(consumer.Name) agentWorkClient := clientHolder.ManifestWorks(consumer.Name) - resourceService := h.Env().Services.Resources() sourceClient := h.Env().Clients.CloudEventsSource // POST responses per openapi spec: 201, 400, 409, 500 @@ -97,16 +98,6 @@ func TestResourcePost(t *testing.T) { var work *workv1.ManifestWork Eventually(func() error { - list, err := lister.List(labels.Everything()) - if err != nil { - return err - } - - // ensure there is only one work was synced on the cluster - if len(list) != 1 { - return fmt.Errorf("unexpected work list %v", list) - } - // ensure the work can be get by work client work, err = agentWorkClient.Get(ctx, *resource.Id, metav1.GetOptions{}) if err != nil { @@ -152,30 +143,28 @@ func TestResourcePost(t *testing.T) { // only update the status on the agent local part Expect(informer.Informer().GetStore().Update(newWork)).NotTo(HaveOccurred()) - // Resync the resource status ceSourceClient, ok := sourceClient.(*cloudevents.SourceClientImpl) Expect(ok).To(BeTrue()) Expect(ceSourceClient.CloudEventSourceClient.Resync(ctx, consumer.Name)).NotTo(HaveOccurred()) + var newRes *openapi.Resource Eventually(func() error { - newRes, err := resourceService.Get(ctx, *resource.Id) + newRes, _, err = client.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, *resource.Id).Execute() if err != nil { return err } - if newRes.Status == nil || len(newRes.Status) == 0 { + if newRes.Status == nil || len(newRes.Status) == 0 || + newRes.Status["ReconcileStatus"] == nil || newRes.Status["ContentStatus"] == nil { return fmt.Errorf("resource status is empty") } return nil }, 10*time.Second, 1*time.Second).Should(Succeed()) - newRes, err := resourceService.Get(ctx, *resource.Id) Expect(err).NotTo(HaveOccurred(), "Error getting resource: %v", err) - Expect(newRes.Version).To(Equal(*resource.Version)) - status, err := api.DecodeStatus(newRes.Status) - Expect(err).NotTo(HaveOccurred(), "Error decoding status: %v", err) - Expect(status["ReconcileStatus"]).NotTo(BeNil()) - reconcileStatus := status["ReconcileStatus"].(map[string]interface{}) + Expect(newRes.Version).To(Equal(resource.Version)) + Expect(newRes.Status["ReconcileStatus"]).NotTo(BeNil()) + reconcileStatus := newRes.Status["ReconcileStatus"].(map[string]interface{}) observedVersion, ok := reconcileStatus["ObservedVersion"].(float64) Expect(ok).To(BeTrue()) Expect(int32(observedVersion)).To(Equal(*resource.Version)) @@ -185,14 +174,11 @@ func TestResourcePost(t *testing.T) { Expect(condition["type"]).To(Equal("Applied")) Expect(condition["status"]).To(Equal("True")) - contentStatus := status["ContentStatus"].(map[string]interface{}) + contentStatus := newRes.Status["ContentStatus"].(map[string]interface{}) Expect(contentStatus["replicas"]).To(Equal(float64(1))) Expect(contentStatus["availableReplicas"]).To(Equal(float64(1))) Expect(contentStatus["readyReplicas"]).To(Equal(float64(1))) Expect(contentStatus["updatedReplicas"]).To(Equal(float64(1))) - - // make sure controller manager and work agent are stopped - cancel() } func TestResourcePostWithoutName(t *testing.T) { @@ -200,7 +186,7 @@ func TestResourcePostWithoutName(t *testing.T) { account := h.NewRandAccount() ctx, cancel := context.WithCancel(h.NewAuthenticatedContext(account)) - clusterName := "cluster1" + clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) res := h.NewAPIResource(consumer.Name, 1) h.StartControllerManager(ctx) @@ -241,7 +227,7 @@ func TestResourcePostWithName(t *testing.T) { account := h.NewRandAccount() ctx, cancel := context.WithCancel(h.NewAuthenticatedContext(account)) - clusterName := "cluster1" + clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) res := h.NewAPIResource(consumer.Name, 1) h.StartControllerManager(ctx) @@ -268,15 +254,15 @@ func TestResourcePatch(t *testing.T) { h, client := test.RegisterIntegration(t) account := h.NewRandAccount() ctx, cancel := context.WithCancel(h.NewAuthenticatedContext(account)) - + defer func() { + cancel() + }() // use the consumer id as the consumer name consumer := h.CreateConsumer("") h.StartControllerManager(ctx) h.StartWorkAgent(ctx, consumer.ID, false) clientHolder := h.WorkAgentHolder - informer := h.WorkAgentInformer - lister := informer.Lister().ManifestWorks(consumer.ID) agentWorkClient := clientHolder.ManifestWorks(consumer.ID) res := h.CreateResource(consumer.ID, 1) @@ -320,16 +306,6 @@ func TestResourcePatch(t *testing.T) { var work *workv1.ManifestWork Eventually(func() error { - list, err := lister.List(labels.Everything()) - if err != nil { - return err - } - - // ensure there is only one work was synced on the cluster - if len(list) != 1 { - return fmt.Errorf("unexpected work list %v", list) - } - // ensure the work can be get by work client work, err = agentWorkClient.Get(ctx, *resource.Id, metav1.GetOptions{}) if err != nil { @@ -350,9 +326,6 @@ func TestResourcePatch(t *testing.T) { manifest := map[string]interface{}{} Expect(json.Unmarshal(work.Spec.Workload.Manifests[0].Raw, &manifest)).NotTo(HaveOccurred(), "Error unmarshalling manifest: %v", err) Expect(manifest).To(Equal(newRes.Manifest)) - - // make sure controller manager and work agent are stopped - cancel() } func contains(et api.EventType, events api.EventList) bool { @@ -371,7 +344,7 @@ func TestResourcePaging(t *testing.T) { ctx := h.NewAuthenticatedContext(account) // Paging - consumer := h.CreateConsumer("cluster1") + consumer := h.CreateConsumer("cluster-" + rand.String(5)) _ = h.CreateResourceList(consumer.Name, 20) _ = h.CreateResourceBundleList(consumer.Name, 20) @@ -398,7 +371,7 @@ func TestResourceListSearch(t *testing.T) { account := h.NewRandAccount() ctx := h.NewAuthenticatedContext(account) - consumer := h.CreateConsumer("cluster1") + consumer := h.CreateConsumer("cluster-" + rand.String(5)) resources := h.CreateResourceList(consumer.Name, 20) search := fmt.Sprintf("id in ('%s')", resources[0].ID) @@ -425,7 +398,7 @@ func TestResourceBundleGet(t *testing.T) { Expect(err).To(HaveOccurred(), "Expected 404") Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) - consumer := h.CreateConsumer("cluster1") + consumer := h.CreateConsumer("cluster-" + rand.String(5)) resourceBundle := h.CreateResourceBundle("resource1", consumer.Name, 1) resBundle, resp, err := client.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(ctx, resourceBundle.ID).Execute() @@ -447,7 +420,7 @@ func TestResourceBundleListSearch(t *testing.T) { account := h.NewRandAccount() ctx := h.NewAuthenticatedContext(account) - consumer := h.CreateConsumer("cluster1") + consumer := h.CreateConsumer("cluster-" + rand.String(5)) resourceBundles := h.CreateResourceBundleList(consumer.Name, 20) _ = h.CreateResourceList(consumer.Name, 20) @@ -474,7 +447,7 @@ func TestUpdateResourceWithRacingRequests(t *testing.T) { account := h.NewRandAccount() ctx := h.NewAuthenticatedContext(account) - consumer := h.CreateConsumer("cluster1") + consumer := h.CreateConsumer("cluster-" + rand.String(5)) res := h.CreateResource(consumer.Name, 1) newRes := h.NewAPIResource(consumer.Name, 2) @@ -527,16 +500,20 @@ func TestUpdateResourceWithRacingRequests(t *testing.T) { return fmt.Errorf("there are %d unreleased advisory lock", count) } return nil - }, 10*time.Second, 1*time.Second).Should(Succeed()) + }, 20*time.Second, 1*time.Second).Should(Succeed()) } func TestResourceFromGRPC(t *testing.T) { h, client := test.RegisterIntegration(t) account := h.NewRandAccount() ctx, cancel := context.WithCancel(h.NewAuthenticatedContext(account)) - defer cancel() + defer func() { + cancel() + // give one second to terminate the work agent + time.Sleep(1 * time.Second) + }() // create a mock resource - clusterName := "cluster1" + clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) res := h.NewResource(consumer.Name, 1) res.ID = uuid.NewString() @@ -742,9 +719,11 @@ func TestResourceBundleFromGRPC(t *testing.T) { h, client := test.RegisterIntegration(t) account := h.NewRandAccount() ctx, cancel := context.WithCancel(h.NewAuthenticatedContext(account)) - defer cancel() + defer func() { + cancel() + }() // create a mock resource - clusterName := "cluster1" + clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) res := h.NewResource(consumer.Name, 1) res.ID = uuid.NewString() @@ -757,6 +736,8 @@ func TestResourceBundleFromGRPC(t *testing.T) { // use grpc client to create resource bundle h.StartGRPCResourceSourceClient() + time.Sleep(1 * time.Second) + err := h.GRPCSourceClient.Publish(ctx, types.CloudEventsType{ CloudEventsDataType: payload.ManifestBundleEventDataType, SubResource: types.SubResourceSpec, From 4448bbab91988aedf385744bdb1c38c74b80017b Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Thu, 29 Aug 2024 16:17:50 +0800 Subject: [PATCH 16/67] prevent resource update durating deletion. (#180) Signed-off-by: morvencao --- pkg/services/resource.go | 13 +++++++++++ test/integration/resource_test.go | 36 ++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/pkg/services/resource.go b/pkg/services/resource.go index 24723365..63295c35 100755 --- a/pkg/services/resource.go +++ b/pkg/services/resource.go @@ -106,6 +106,10 @@ func (s *sqlResourceService) Update(ctx context.Context, resource *api.Resource) return nil, handleGetError("Resource", "id", resource.ID, err) } + if !found.DeletedAt.Time.IsZero() { + return nil, errors.Conflict("the resource is under deletion, id: %s", resource.ID) + } + // Make sure the requested resource version is consistent with its database version. if found.Version != resource.Version { return nil, errors.Conflict("the resource version is not the latest, the latest version: %d", found.Version) @@ -221,6 +225,15 @@ func (s *sqlResourceService) UpdateStatus(ctx context.Context, resource *api.Res // 4. Work-agent deletes resource, sends CloudEvent back to Maestro // 5. Maestro hard deletes resource from DB func (s *sqlResourceService) MarkAsDeleting(ctx context.Context, id string) *errors.ServiceError { + // If there are multiple requests to write the resource at the same time, it will cause the race conditions among these + // requests (read–modify–write), the advisory lock is used here to prevent the race conditions. + lockOwnerID, err := s.lockFactory.NewAdvisoryLock(ctx, id, db.Resources) + // Ensure that the transaction related to this lock always end. + defer s.lockFactory.Unlock(ctx, lockOwnerID) + if err != nil { + return errors.DatabaseAdvisoryLock(err) + } + if err := s.resourceDao.Delete(ctx, id, false); err != nil { return handleDeleteError("Resource", errors.GeneralError("Unable to delete resource: %s", err)) } diff --git a/test/integration/resource_test.go b/test/integration/resource_test.go index aa306068..50165557 100755 --- a/test/integration/resource_test.go +++ b/test/integration/resource_test.go @@ -14,6 +14,7 @@ import ( "gopkg.in/resty.v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + k8stypes "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/rand" workv1 "open-cluster-management.io/api/work/v1" "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" @@ -268,6 +269,30 @@ func TestResourcePatch(t *testing.T) { res := h.CreateResource(consumer.ID, 1) Expect(res.Version).To(Equal(int32(1))) + var work *workv1.ManifestWork + Eventually(func() error { + // ensure the work can be get by work client + var err error + work, err = agentWorkClient.Get(ctx, res.ID, metav1.GetOptions{}) + if err != nil { + return err + } + // add finalizer to the work + patchBytes, err := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "uid": work.GetUID(), + "resourceVersion": work.GetResourceVersion(), + "finalizers": []string{"work-test-finalizer"}, + }, + }) + if err != nil { + return err + } + + _, err = agentWorkClient.Patch(ctx, work.Name, k8stypes.MergePatchType, patchBytes, metav1.PatchOptions{}) + return err + }, 20*time.Second, 2*time.Second).Should(Succeed()) + // 200 OK newRes := h.NewAPIResource(consumer.ID, 2) resource, resp, err := client.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, res.ID).ResourcePatchRequest(openapi.ResourcePatchRequest{Version: &res.Version, Manifest: newRes.Manifest}).Execute() @@ -304,7 +329,6 @@ func TestResourcePatch(t *testing.T) { Expect(err).To(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusConflict)) - var work *workv1.ManifestWork Eventually(func() error { // ensure the work can be get by work client work, err = agentWorkClient.Get(ctx, *resource.Id, metav1.GetOptions{}) @@ -326,6 +350,16 @@ func TestResourcePatch(t *testing.T) { manifest := map[string]interface{}{} Expect(json.Unmarshal(work.Spec.Workload.Manifests[0].Raw, &manifest)).NotTo(HaveOccurred(), "Error unmarshalling manifest: %v", err) Expect(manifest).To(Equal(newRes.Manifest)) + + // initialize resource deletion + _, err = client.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, res.ID).Execute() + Expect(err).NotTo(HaveOccurred(), "Error deleting object: %v", err) + + // patch the deleting resource should return 409 conflict + _, resp, err = client.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, res.ID).ResourcePatchRequest( + openapi.ResourcePatchRequest{Version: &res.Version, Manifest: newRes.Manifest}).Execute() + Expect(err).To(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusConflict)) } func contains(et api.EventType, events api.EventList) bool { From 043cc462dd112b5e72fdbf08444938654d1ff8a5 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Thu, 29 Aug 2024 16:57:48 +0800 Subject: [PATCH 17/67] Support using outside context to request maestro RESTful api (#183) Signed-off-by: Wei Liu --- pkg/client/cloudevents/grpcsource/pager.go | 4 ++-- pkg/client/cloudevents/grpcsource/pager_test.go | 3 ++- pkg/client/cloudevents/grpcsource/watcherstore.go | 12 ++++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pkg/client/cloudevents/grpcsource/pager.go b/pkg/client/cloudevents/grpcsource/pager.go index 015d1b4a..45df6d7f 100644 --- a/pkg/client/cloudevents/grpcsource/pager.go +++ b/pkg/client/cloudevents/grpcsource/pager.go @@ -17,7 +17,7 @@ import ( var MaxListPageSize int32 = 400 // pageList assists client code in breaking large list queries into multiple smaller chunks of PageSize or smaller. -func pageList(client *openapi.APIClient, search string, opts metav1.ListOptions) (*openapi.ResourceBundleList, string, error) { +func pageList(ctx context.Context, client *openapi.APIClient, search string, opts metav1.ListOptions) (*openapi.ResourceBundleList, string, error) { items := []openapi.ResourceBundle{} page, err := page(opts) @@ -36,7 +36,7 @@ func pageList(client *openapi.APIClient, search string, opts metav1.ListOptions) offset := (page - 1) * pageSize for { klog.V(4).Infof("list works with search=%s, page=%d, size=%d", search, page, pageSize) - rbs, _, err := client.DefaultApi.ApiMaestroV1ResourceBundlesGet(context.Background()). + rbs, _, err := client.DefaultApi.ApiMaestroV1ResourceBundlesGet(ctx). Search(search). Page(page). Size(pageSize). diff --git a/pkg/client/cloudevents/grpcsource/pager_test.go b/pkg/client/cloudevents/grpcsource/pager_test.go index b3c630d4..e27550e8 100644 --- a/pkg/client/cloudevents/grpcsource/pager_test.go +++ b/pkg/client/cloudevents/grpcsource/pager_test.go @@ -1,6 +1,7 @@ package grpcsource import ( + "context" "testing" "github.com/openshift-online/maestro/pkg/api/openapi" @@ -143,7 +144,7 @@ func TestPageList(t *testing.T) { t.Run(c.name, func(t *testing.T) { getter.Set(c.resourceBundles) - list, next, err := pageList(client, "", c.listOpts) + list, next, err := pageList(context.Background(), client, "", c.listOpts) if err != nil { t.Errorf("unexpected error %v", err) } diff --git a/pkg/client/cloudevents/grpcsource/watcherstore.go b/pkg/client/cloudevents/grpcsource/watcherstore.go index aaaf1f37..892a1bed 100644 --- a/pkg/client/cloudevents/grpcsource/watcherstore.go +++ b/pkg/client/cloudevents/grpcsource/watcherstore.go @@ -33,6 +33,9 @@ import ( type RESTFulAPIWatcherStore struct { sync.RWMutex + // the context for RESTful API request, it is passed with RESTful API client together + ctx context.Context + sourceID string apiClient *openapi.APIClient @@ -44,6 +47,7 @@ var _ store.WorkClientWatcherStore = &RESTFulAPIWatcherStore{} func newRESTFulAPIWatcherStore(ctx context.Context, apiClient *openapi.APIClient, sourceID string) *RESTFulAPIWatcherStore { s := &RESTFulAPIWatcherStore{ + ctx: ctx, sourceID: sourceID, apiClient: apiClient, watchers: make(map[string]*workWatcher), @@ -83,7 +87,7 @@ func (m *RESTFulAPIWatcherStore) GetWatcher(namespace string, opts metav1.ListOp } // for watch, we need list all works with the search condition from maestro server - rbs, _, err := pageList(m.apiClient, strings.Join(searches, " and "), metav1.ListOptions{}) + rbs, _, err := pageList(m.ctx, m.apiClient, strings.Join(searches, " and "), metav1.ListOptions{}) if err != nil { return nil, err } @@ -124,7 +128,7 @@ func (m *RESTFulAPIWatcherStore) HandleReceivedWork(action types.ResourceAction, // Get a work from maestro server with its namespace and name func (m *RESTFulAPIWatcherStore) Get(namespace, name string) (*workv1.ManifestWork, bool, error) { id := utils.UID(m.sourceID, namespace, name) - rb, resp, err := m.apiClient.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(context.Background(), id).Execute() + rb, resp, err := m.apiClient.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(m.ctx, id).Execute() if err != nil { if resp != nil && resp.StatusCode == http.StatusNotFound { return nil, false, nil @@ -160,7 +164,7 @@ func (m *RESTFulAPIWatcherStore) List(namespace string, opts metav1.ListOptions) searches = append(searches, labelSearch) } - rbs, nextPage, err := pageList(m.apiClient, strings.Join(searches, " and "), opts) + rbs, nextPage, err := pageList(m.ctx, m.apiClient, strings.Join(searches, " and "), opts) if err != nil { return nil, err } @@ -230,7 +234,7 @@ func (m *RESTFulAPIWatcherStore) Sync() error { } // for sync, we need list all works with the search condition from maestro server - rbs, _, err := pageList(m.apiClient, strings.Join(search, " or "), metav1.ListOptions{}) + rbs, _, err := pageList(m.ctx, m.apiClient, strings.Join(search, " or "), metav1.ListOptions{}) if err != nil { return err } From 7ac1d749af9b116876504cc2aec0793a7f0c23d1 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Thu, 29 Aug 2024 17:05:29 +0800 Subject: [PATCH 18/67] fix e2e testing. (#184) Signed-off-by: morvencao --- Makefile | 3 +- go.mod | 4 +- go.sum | 11 +- test/e2e/pkg/consumer_test.go | 86 ++++---- test/e2e/pkg/grpc_test.go | 80 +++----- test/e2e/pkg/resources_test.go | 74 +++---- test/e2e/pkg/serverside_test.go | 9 +- test/e2e/pkg/sourceclient_test.go | 60 +++--- test/e2e/pkg/spec_resync_test.go | 236 +++++++++++----------- test/e2e/pkg/status_resync_test.go | 58 +++--- test/e2e/pkg/suite_test.go | 46 +++++ test/factories.go | 271 ++++++++++++-------------- test/integration/consumers_test.go | 6 +- test/integration/controller_test.go | 3 +- test/integration/pulse_server_test.go | 4 +- test/integration/resource_test.go | 35 ++-- 16 files changed, 513 insertions(+), 473 deletions(-) diff --git a/Makefile b/Makefile index 5126a8d0..4b9a1705 100755 --- a/Makefile +++ b/Makefile @@ -417,7 +417,8 @@ e2e-test/teardown: .PHONY: e2e-test/teardown e2e-test: e2e-test/teardown e2e-test/setup - ginkgo -v --output-dir="${PWD}/test/e2e/report" --json-report=report.json --junit-report=report.xml \ + ginkgo -v --fail-fast --label-filter="!(e2e-tests-spec-resync-reconnect||e2e-tests-status-resync-reconnect)" \ + --output-dir="${PWD}/test/e2e/report" --json-report=report.json --junit-report=report.xml \ ${PWD}/test/e2e/pkg -- \ -api-server=https://$(shell cat ${PWD}/test/e2e/.external_host_ip):30080 \ -grpc-server=$(shell cat ${PWD}/test/e2e/.external_host_ip):30090 \ diff --git a/go.mod b/go.mod index 3d6bd08b..c5fc151d 100755 --- a/go.mod +++ b/go.mod @@ -46,10 +46,12 @@ require ( k8s.io/klog/v2 v2.120.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 - open-cluster-management.io/sdk-go v0.14.1-0.20240806021439-bf354ff3847f + open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8 ) require ( + cloud.google.com/go/compute v1.23.3 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr/antlr4 v0.0.0-20200712162734-eb1adaa8a7a6 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect diff --git a/go.sum b/go.sum index 23a78743..1ab30f89 100755 --- a/go.sum +++ b/go.sum @@ -2,7 +2,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= -cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= @@ -539,8 +538,8 @@ go.mongodb.org/mongo-driver v1.0.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= @@ -825,10 +824,8 @@ open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c h1:gYfgkX/U open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 h1:7uPjyn1x25QZIzfZqeSFfZdNrzc2hlHm6t/JKYKu9fI= open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33/go.mod h1:KzUwhPZAg6Wq+4xRu10fVVpqNADyz5CtRW4ziqIC2z4= -open-cluster-management.io/sdk-go v0.14.1-0.20240717021054-955108a181ee h1:aQ4AoR8SKz/byOyZbbYC9Tbp4VCtRHje8uHbn438o84= -open-cluster-management.io/sdk-go v0.14.1-0.20240717021054-955108a181ee/go.mod h1:xFmN3Db5nN68oLGnstmIRv4us8HJCdXFnBNMXVp0jWY= -open-cluster-management.io/sdk-go v0.14.1-0.20240806021439-bf354ff3847f h1:8yQ8uFemyM/dI4nMo8pVOmEiIn156SkN9qpnLf8UOcI= -open-cluster-management.io/sdk-go v0.14.1-0.20240806021439-bf354ff3847f/go.mod h1:xFmN3Db5nN68oLGnstmIRv4us8HJCdXFnBNMXVp0jWY= +open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8 h1:2dOKe8kj2niAZMlc75NSI/CIkosNNt/Kqyau7ZH4DwM= +open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8/go.mod h1:mHGre2DnTfV5gLgCWr+byBqKqTuf5Yzx/EtSSJ2EiGE= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= diff --git a/test/e2e/pkg/consumer_test.go b/test/e2e/pkg/consumer_test.go index 96ed84fb..c0c5b732 100644 --- a/test/e2e/pkg/consumer_test.go +++ b/test/e2e/pkg/consumer_test.go @@ -1,44 +1,67 @@ package e2e_test import ( + "fmt" "net/http" "reflect" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/openshift-online/maestro/pkg/api/openapi" + "k8s.io/apimachinery/pkg/util/rand" ) -var _ = Describe("Consumer", Ordered, func() { - var consumer openapi.Consumer - var resourceConsumer openapi.Consumer - var resource openapi.Resource - BeforeAll(func() { - consumer = openapi.Consumer{Name: openapi.PtrString("linda")} - resourceConsumer = openapi.Consumer{Name: openapi.PtrString("susan")} - resource = helper.NewAPIResource(*resourceConsumer.Name, 1) - }) - +var _ = Describe("Consumers", Ordered, Label("e2e-tests-consumers"), func() { Context("Consumer CRUD Tests", func() { + consumerA := openapi.Consumer{Name: openapi.PtrString("consumer-a")} + consumerB := openapi.Consumer{Name: openapi.PtrString("consumer-b")} + resource := helper.NewAPIResource(*consumerB.Name, fmt.Sprintf("nginx-%s", rand.String(5)), 1) + + AfterAll(func() { + // delete the consumer + resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *consumerA.Id).Execute() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + + _, resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumerA.Id).Execute() + Expect(err.Error()).To(ContainSubstring("Not Found")) + Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) + + // delete the consumer associated with resource + resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *consumerB.Id).Execute() + Expect(err).To(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusForbidden)) // 403 forbid deletion + + // delete the resource on the consumer + resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource.Id).Execute() + Expect(err).To(Succeed()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + + // only if permanently delete the resource, the consumer can be deleted + resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *consumerB.Id).Execute() + Expect(err).To(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusForbidden)) // 403 forbid deletion + }) + It("create consumer", func() { // create a consumer without resource - created, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(consumer).Execute() + created, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(consumerA).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) Expect(*created.Id).NotTo(BeEmpty()) - consumer = *created + consumerA = *created - got, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumer.Id).Execute() + got, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumerA.Id).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) Expect(got).NotTo(BeNil()) // create a consumer with resource - created, resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(resourceConsumer).Execute() + created, resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersPost(ctx).Consumer(consumerB).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) Expect(*created.Id).NotTo(BeEmpty()) - resourceConsumer = *created + consumerB = *created res, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(resource).Execute() Expect(err).ShouldNot(HaveOccurred()) @@ -54,10 +77,11 @@ var _ = Describe("Consumer", Ordered, func() { Expect(resp.StatusCode).To(Equal(http.StatusOK)) Expect(consumerList).NotTo(BeNil()) Expect(len(consumerList.Items) > 0).To(BeTrue()) + fmt.Printf("consumer list: %v\n", consumerList.Items) got := false for _, c := range consumerList.Items { - if *c.Name == *consumer.Name { + if *c.Name == *consumerA.Name { got = true } } @@ -66,45 +90,19 @@ var _ = Describe("Consumer", Ordered, func() { It("patch consumer", func() { labels := &map[string]string{"hello": "world"} - patched, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdPatch(ctx, *consumer.Id). + patched, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdPatch(ctx, *consumerA.Id). ConsumerPatchRequest(openapi.ConsumerPatchRequest{Labels: labels}).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) _, ok := patched.GetLabelsOk() Expect(ok).To(BeTrue()) - got, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumer.Id).Execute() + got, resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumerA.Id).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) Expect(got).NotTo(BeNil()) eq := reflect.DeepEqual(*labels, *got.Labels) Expect(eq).To(BeTrue()) }) - - AfterAll(func() { - // delete the consumer - resp, err := apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *consumer.Id).Execute() - Expect(err).NotTo(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - - _, resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdGet(ctx, *consumer.Id).Execute() - Expect(err.Error()).To(ContainSubstring("Not Found")) - Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) - - // delete the consumer associated with resource - resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *resourceConsumer.Id).Execute() - Expect(err).To(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusForbidden)) // 403 forbid deletion - - // delete the resource on the consumer - resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource.Id).Execute() - Expect(err).To(Succeed()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - - // only if permanently delete the resource, the consumer can be deleted - resp, err = apiClient.DefaultApi.ApiMaestroV1ConsumersIdDelete(ctx, *resourceConsumer.Id).Execute() - Expect(err).To(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusForbidden)) // 403 forbid deletion - }) }) }) diff --git a/test/e2e/pkg/grpc_test.go b/test/e2e/pkg/grpc_test.go index e2342f3e..8d5c6386 100644 --- a/test/e2e/pkg/grpc_test.go +++ b/test/e2e/pkg/grpc_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "log" "net/http" "time" @@ -17,6 +16,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/rand" pbv1 "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protobuf/v1" grpcprotocol "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protocol" @@ -28,6 +28,7 @@ import ( var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { Context("GRPC Manifest Tests", func() { source := "grpc-e2e" + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) resourceID := uuid.NewString() resourceStatus := &api.ResourceStatus{ ReconcileStatus: &api.ReconcileStatus{}, @@ -95,14 +96,10 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec using grpc client", func() { - evt, err := helper.ManifestToEvent(1, source, "create_request", consumer.Name, resourceID, 1, false) - Expect(err).ShouldNot(HaveOccurred()) - + evt := helper.NewEvent(source, "create_request", consumer.Name, resourceID, deployName, 1, 1) pbEvt := &pbv1.CloudEvent{} - if err = grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt); err != nil { - log.Fatalf("failed to convert spec from cloudevent to protobuf: %v", err) - } - + err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) + Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") _, err = grpcClient.Publish(ctx, &pbv1.PublishRequest{Event: pbEvt}) Expect(err).ShouldNot(HaveOccurred()) }) @@ -136,7 +133,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -156,14 +153,10 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec with update request using grpc client", func() { - evt, err := helper.ManifestToEvent(2, source, "update_request", consumer.Name, resourceID, 1, false) - Expect(err).ShouldNot(HaveOccurred()) - + evt := helper.NewEvent(source, "update_request", consumer.Name, resourceID, deployName, 1, 2) pbEvt := &pbv1.CloudEvent{} - if err = grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt); err != nil { - log.Fatalf("failed to convert spec from cloudevent to protobuf: %v", err) - } - + err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) + Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") _, err = grpcClient.Publish(ctx, &pbv1.PublishRequest{Event: pbEvt}) Expect(err).ShouldNot(HaveOccurred()) }) @@ -197,7 +190,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -217,14 +210,10 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec with delete request using grpc client", func() { - evt, err := helper.ManifestToEvent(2, source, "delete_request", consumer.Name, resourceID, 1, true) - Expect(err).ShouldNot(HaveOccurred()) - + evt := helper.NewEvent(source, "delete_request", consumer.Name, resourceID, deployName, 2, 2) pbEvt := &pbv1.CloudEvent{} - if err = grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt); err != nil { - log.Fatalf("failed to convert spec from cloudevent to protobuf: %v", err) - } - + err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) + Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") _, err = grpcClient.Publish(ctx, &pbv1.PublishRequest{Event: pbEvt}) Expect(err).ShouldNot(HaveOccurred()) }) @@ -245,7 +234,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -258,13 +247,14 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the resource with the maestro api", func() { _, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, resourceID).Execute() - Expect(err).To(HaveOccurred(), "Expected 404") + Expect(err).To(HaveOccurred(), "Expected 404 error") Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) }) }) Context("GRPC Manifest Bundle Tests", func() { source := "grpc-e2e" + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) resourceID := uuid.NewString() resourceBundleStatus := &api.ResourceBundleStatus{ ManifestBundleStatus: &payload.ManifestBundleStatus{}, @@ -314,14 +304,10 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec using grpc client", func() { - evt, err := helper.ManifestsToBundleEvent(1, source, "create_request", consumer.Name, resourceID, 1, false) - Expect(err).ShouldNot(HaveOccurred()) - + evt := helper.NewBundleEvent(source, "create_request", consumer.Name, resourceID, deployName, 1, 1) pbEvt := &pbv1.CloudEvent{} - if err = grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt); err != nil { - log.Fatalf("failed to convert spec from cloudevent to protobuf: %v", err) - } - + err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) + Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") _, err = grpcClient.Publish(ctx, &pbv1.PublishRequest{Event: pbEvt}) Expect(err).ShouldNot(HaveOccurred()) }) @@ -370,7 +356,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -390,14 +376,10 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec with update request using grpc client", func() { - evt, err := helper.ManifestsToBundleEvent(2, source, "update_request", consumer.Name, resourceID, 1, false) - Expect(err).ShouldNot(HaveOccurred()) - + evt := helper.NewBundleEvent(source, "update_request", consumer.Name, resourceID, deployName, 1, 2) pbEvt := &pbv1.CloudEvent{} - if err = grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt); err != nil { - log.Fatalf("failed to convert spec from cloudevent to protobuf: %v", err) - } - + err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) + Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") _, err = grpcClient.Publish(ctx, &pbv1.PublishRequest{Event: pbEvt}) Expect(err).ShouldNot(HaveOccurred()) }) @@ -446,7 +428,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -466,14 +448,10 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec with delete request using grpc client", func() { - evt, err := helper.ManifestsToBundleEvent(2, source, "delete_request", consumer.Name, resourceID, 1, true) - Expect(err).ShouldNot(HaveOccurred()) - + evt := helper.NewBundleEvent(source, "delete_request", consumer.Name, resourceID, deployName, 2, 2) pbEvt := &pbv1.CloudEvent{} - if err = grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt); err != nil { - log.Fatalf("failed to convert spec from cloudevent to protobuf: %v", err) - } - + err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) + Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") _, err = grpcClient.Publish(ctx, &pbv1.PublishRequest{Event: pbEvt}) Expect(err).ShouldNot(HaveOccurred()) }) @@ -494,7 +472,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -507,7 +485,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the resource with the maestro api", func() { _, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(ctx, resourceID).Execute() - Expect(err).To(HaveOccurred(), "Expected 404") + Expect(err).To(HaveOccurred(), "Expected 404 error") Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) }) }) diff --git a/test/e2e/pkg/resources_test.go b/test/e2e/pkg/resources_test.go index 876e8a95..2ca7aef8 100644 --- a/test/e2e/pkg/resources_test.go +++ b/test/e2e/pkg/resources_test.go @@ -20,13 +20,12 @@ import ( "github.com/openshift-online/maestro/pkg/api/openapi" ) -// go test -v ./test/e2e/pkg -args -api-server=$api_server -consumer-name=$consumer.Name -consumer-kubeconfig=$consumer_kubeconfig -ginkgo.focus "Resources" var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { - var resource *openapi.Resource - Context("Resource CRUD Tests", func() { + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + var resource *openapi.Resource It("post the nginx resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, 1) + res := helper.NewAPIResource(consumer.Name, deployName, 1) var resp *http.Response var err error resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -36,7 +35,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(*resource.Version).To(Equal(int32(1))) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -56,7 +55,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("patch the nginx resource with the maestro api", func() { - newRes := helper.NewAPIResource(consumer.Name, 2) + newRes := helper.NewAPIResource(consumer.Name, deployName, 2) patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resource.Id). ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resource.Version, Manifest: newRes.Manifest}).Execute() Expect(err).ShouldNot(HaveOccurred()) @@ -64,7 +63,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(*patchedResource.Version).To(Equal(*resource.Version + 1)) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -81,7 +80,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -94,18 +93,20 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) Context("Resource Delete Option Tests", func() { - res := helper.NewAPIResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + var resource *openapi.Resource It("post the nginx resource to the maestro api", func() { + res := helper.NewAPIResource(consumer.Name, deployName, 1) + res.DeleteOption = map[string]interface{}{"propagationPolicy": "Orphan"} var resp *http.Response var err error - res.DeleteOption = map[string]interface{}{"propagationPolicy": "Orphan"} resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) Expect(*resource.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -123,7 +124,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { // ensure the "nginx" deployment in the "default" namespace is not deleted Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return fmt.Errorf("nginx deployment is deleted") @@ -134,11 +135,11 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("delete the nginx deployment", func() { - err := consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, "nginx", metav1.DeleteOptions{}) + err := consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, deployName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -151,18 +152,20 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) Context("Resource CreateOnly UpdateStrategy Tests", func() { + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + var resource *openapi.Resource It("post the nginx resource to the maestro api with createOnly updateStrategy", func() { - res := helper.NewAPIResource(consumer.Name, 1) + res := helper.NewAPIResource(consumer.Name, deployName, 1) + res.UpdateStrategy = map[string]interface{}{"type": "CreateOnly"} var resp *http.Response var err error - res.UpdateStrategy = map[string]interface{}{"type": "CreateOnly"} resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) Expect(*resource.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -174,15 +177,16 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("patch the nginx resource", func() { - newRes := helper.NewAPIResource(consumer.Name, 2) + newRes := helper.NewAPIResource(consumer.Name, deployName, 2) patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resource.Id). ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resource.Version, Manifest: newRes.Manifest}).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) Expect(*patchedResource.Version).To(Equal(*resource.Version + 1)) + // ensure the "nginx" deployment in the "default" namespace is not updated Consistently(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return nil } @@ -199,7 +203,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -212,16 +216,18 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) Context("Resource ReadOnly UpdateStrategy Tests via restful api", func() { - It("create a sample deployment in the target cluster", func() { + var resource *openapi.Resource + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + It("create a nginx deployment in the target cluster", func() { nginxDeploy := &appsv1.Deployment{} - err := json.Unmarshal(helper.GetTestNginxJSON(1), nginxDeploy) + err := json.Unmarshal([]byte(helper.NewResourceManifestJSON(deployName, 1)), nginxDeploy) Expect(err).ShouldNot(HaveOccurred()) _, err = consumer.ClientSet.AppsV1().Deployments("default").Create(ctx, nginxDeploy, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) It("post the resource to the maestro api with readonly updateStrategy", func() { - res := helper.NewReadOnlyAPIResource(consumer.Name) + res := helper.NewReadOnlyAPIResource(consumer.Name, deployName) var resp *http.Response var err error resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -254,6 +260,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { return nil } } + return fmt.Errorf("contentStatus should not be empty") }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) @@ -263,11 +270,11 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, "nginx", metav1.DeleteOptions{}) + err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, deployName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -281,8 +288,9 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Context("Resource ReadOnly UpdateStrategy Tests via gRPC", func() { workName := "work-readonly-" + rand.String(5) - secretName := "auth" - It("create a sample secret in the target cluster", func() { + secretName := "auth-" + rand.String(5) + manifest := fmt.Sprintf("{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"name\":\"%s\",\"namespace\":\"default\"}}", secretName) + It("create a secret in the target cluster", func() { _, err := consumer.ClientSet.CoreV1().Secrets("default").Create(ctx, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: secretName, @@ -305,7 +313,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Manifests: []workv1.Manifest{ { RawExtension: runtime.RawExtension{ - Raw: []byte("{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"name\":\"auth\",\"namespace\":\"default\"}}"), + Raw: []byte(manifest), }, }, }, @@ -364,16 +372,16 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { return fmt.Errorf("work creationTimestamp is empty") } - manifest := work.Status.ResourceStatus.Manifests - if len(manifest) > 0 && len(manifest[0].StatusFeedbacks.Values) != 0 { - feedback := manifest[0].StatusFeedbacks.Values + manifests := work.Status.ResourceStatus.Manifests + if len(manifests) > 0 && len(manifests[0].StatusFeedbacks.Values) != 0 { + feedback := manifests[0].StatusFeedbacks.Values if feedback[0].Name == "credential" && *feedback[0].Value.JsonRaw == "{\"token\":\"dG9rZW4=\"}" { return nil } - return fmt.Errorf("the result %v is not expected", feedback[0]) + return fmt.Errorf("the status feedback value %v is not expected", feedback[0]) } - return fmt.Errorf("manifest should be empty") + return fmt.Errorf("manifests are empty") }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) diff --git a/test/e2e/pkg/serverside_test.go b/test/e2e/pkg/serverside_test.go index e5d13a9f..ed07f6c6 100644 --- a/test/e2e/pkg/serverside_test.go +++ b/test/e2e/pkg/serverside_test.go @@ -13,6 +13,7 @@ import ( "github.com/openshift-online/maestro/pkg/api/openapi" "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/util/rand" workv1 "open-cluster-management.io/api/work/v1" ) @@ -22,7 +23,7 @@ const sleepJob = ` "apiVersion": "batch/v1", "kind": "Job", "metadata": { - "name": "sleep", + "name": "%s", "namespace": "default" }, "spec": { @@ -47,14 +48,16 @@ const sleepJob = ` } ` -var _ = Describe("Server Side Apply", func() { +var _ = Describe("Server Side Apply", Ordered, Label("e2e-tests-serverside-apply"), func() { It("Apply a job with maestro", func() { // The kube-apiserver will set a default selector and label on the Pod of Job if the job does not have // spec.Selector, these fields are immutable, if we use update strategy to apply Job, it will report // AppliedManifestFailed. The maestro uses the server side strategy to apply a resource with ManifestWork // by default, this will avoid this. manifest := map[string]interface{}{} - Expect(json.Unmarshal([]byte(sleepJob), &manifest)).ShouldNot(HaveOccurred()) + sleepJobName := fmt.Sprintf("sleep-%s", rand.String(5)) + err := json.Unmarshal([]byte(fmt.Sprintf(sleepJob, sleepJobName)), &manifest) + Expect(err).ShouldNot(HaveOccurred()) res := openapi.Resource{ Manifest: manifest, diff --git a/test/e2e/pkg/sourceclient_test.go b/test/e2e/pkg/sourceclient_test.go index 6993a0b0..ec6a0d20 100644 --- a/test/e2e/pkg/sourceclient_test.go +++ b/test/e2e/pkg/sourceclient_test.go @@ -25,7 +25,7 @@ import ( "open-cluster-management.io/sdk-go/pkg/cloudevents/work/common" ) -var _ = Describe("gRPC Source ManifestWork Client Test", func() { +var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source-work-client"), func() { Context("Update an obsolete work", func() { var workName string @@ -35,7 +35,7 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { Eventually(func() error { _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) return err - }, 5*time.Minute, 5*time.Second).ShouldNot(HaveOccurred()) + }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) // wait for few seconds to ensure the creation is finished <-time.After(5 * time.Second) @@ -47,7 +47,7 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { Eventually(func() error { return AssertWorkNotFound(workName) - }, 30*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) @@ -73,6 +73,9 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { _, err = workClient.ManifestWorks(consumer.Name).Patch(ctx, workName, types.MergePatchType, patchData, metav1.PatchOptions{}) Expect(err).Should(HaveOccurred()) Expect(strings.Contains(err.Error(), "the resource version is not the latest")).Should(BeTrue()) + + // wait for few seconds to ensure the update is finished + <-time.After(5 * time.Second) }) }) @@ -93,7 +96,7 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) - initWorkBName = "init-work-b" + rand.String(5) + initWorkBName = "init-work-b-" + rand.String(5) work = NewManifestWorkWithLabels(initWorkBName, map[string]string{"app": "test"}) _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) @@ -112,7 +115,7 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { } return AssertWorkNotFound(initWorkBName) - }, 30*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) watcherCancel() }) @@ -161,7 +164,7 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { Eventually(func() error { return AssertWatchResult(result) - }, 30*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) It("The watchers with different namespace", func() { @@ -202,7 +205,7 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { Eventually(func() error { return AssertWatchResult(allConsumerWatcherResult) - }, 30*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) Eventually(func() error { return AssertWatchResult(consumerWatcherResult) @@ -247,7 +250,7 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { Eventually(func() error { return AssertWatchResult(result) - }, 30*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) }) @@ -265,25 +268,28 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) - prodWorkName = "work-prod" + rand.String(5) - work = NewManifestWorkWithLabels(prodWorkName, map[string]string{"app": "nginx", "env": "prod"}) + prodWorkName = "work-production" + rand.String(5) + work = NewManifestWorkWithLabels(prodWorkName, map[string]string{"app": "test", "env": "production"}) _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) - testWorkAName = "work-test-a-" + rand.String(5) - work = NewManifestWorkWithLabels(testWorkAName, map[string]string{"app": "nginx", "env": "test", "val": "a"}) + testWorkAName = "work-integration-a-" + rand.String(5) + work = NewManifestWorkWithLabels(testWorkAName, map[string]string{"app": "test", "env": "integration", "val": "a"}) _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) - testWorkBName = "work-test-b-" + rand.String(5) - work = NewManifestWorkWithLabels(testWorkBName, map[string]string{"app": "nginx", "env": "test", "val": "b"}) + testWorkBName = "work-integration-b-" + rand.String(5) + work = NewManifestWorkWithLabels(testWorkBName, map[string]string{"app": "test", "env": "integration", "val": "b"}) _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) - testWorkCName = "work-test-c-" + rand.String(5) - work = NewManifestWorkWithLabels(testWorkCName, map[string]string{"app": "nginx", "env": "test", "val": "c"}) + testWorkCName = "work-integration-c-" + rand.String(5) + work = NewManifestWorkWithLabels(testWorkCName, map[string]string{"app": "test", "env": "integration", "val": "c"}) _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) + + // wait for few seconds to ensure the creation is finished + <-time.After(5 * time.Second) }) AfterEach(func() { @@ -320,7 +326,7 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { } return AssertWorkNotFound(testWorkCName) - }, 30*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) + }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) }) It("List works with options", func() { @@ -348,28 +354,28 @@ var _ = Describe("gRPC Source ManifestWork Client Test", func() { By("list works with app label") works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ - LabelSelector: "app=nginx", + LabelSelector: "app=test", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, prodWorkName, testWorkAName, testWorkBName, testWorkCName)).ShouldNot(HaveOccurred()) By("list works without test env") works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ - LabelSelector: "app=nginx,env!=test", + LabelSelector: "app=test,env!=integration", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, prodWorkName)).ShouldNot(HaveOccurred()) By("list works in prod and test env") works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ - LabelSelector: "env in (prod, test)", + LabelSelector: "env in (production, integration)", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, prodWorkName, testWorkAName, testWorkBName, testWorkCName)).ShouldNot(HaveOccurred()) By("list works in test env and val not in a and b") works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ - LabelSelector: "env=test,val notin (a,b)", + LabelSelector: "env=integration,val notin (a,b)", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, testWorkCName)).ShouldNot(HaveOccurred()) @@ -501,6 +507,12 @@ func AssertWorks(works []workv1.ManifestWork, expected ...string) error { return nil } +func NewManifestWorkWithLabels(name string, labels map[string]string) *workv1.ManifestWork { + work := NewManifestWork(name) + work.Labels = labels + return work +} + func NewManifestWork(name string) *workv1.ManifestWork { return &workv1.ManifestWork{ ObjectMeta: metav1.ObjectMeta{ @@ -516,12 +528,6 @@ func NewManifestWork(name string) *workv1.ManifestWork { } } -func NewManifestWorkWithLabels(name string, labels map[string]string) *workv1.ManifestWork { - work := NewManifestWork(name) - work.Labels = labels - return work -} - func NewManifest(name string) workv1.Manifest { obj := &unstructured.Unstructured{ Object: map[string]interface{}{ diff --git a/test/e2e/pkg/spec_resync_test.go b/test/e2e/pkg/spec_resync_test.go index 5891b20c..5d374a43 100644 --- a/test/e2e/pkg/spec_resync_test.go +++ b/test/e2e/pkg/spec_resync_test.go @@ -13,50 +13,53 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/rand" ) -var _ = Describe("Spec resync", Ordered, Label("e2e-tests-spec-resync"), func() { - var resource1, resource2, resource3 *openapi.Resource - var mqttReplicas, maestroServerReplicas, maestroAgentReplicas int - +var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-resync-restart"), func() { Context("Resource resync resource spec after maestro agent restarts", func() { - It("post the nginx-1 resource to the maestro api", func() { - res := helper.NewAPIResourceWithIndex(consumer.Name, 1, 1) + var maestroAgentReplicas int + var resourceA, resourceB, resourceC *openapi.Resource + deployA := fmt.Sprintf("nginx-%s", rand.String(5)) + deployB := fmt.Sprintf("nginx-%s", rand.String(5)) + deployC := fmt.Sprintf("nginx-%s", rand.String(5)) + It("post the nginx A resource to the maestro api", func() { + res := helper.NewAPIResource(consumer.Name, deployA, 1) var resp *http.Response var err error - resource1, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() + resourceA, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resource1.Id).ShouldNot(BeEmpty()) + Expect(*resourceA.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx-1 deployment, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 1, got %d", deployA, *deploy.Spec.Replicas) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("post the nginx-2 resource to the maestro api", func() { - res := helper.NewAPIResourceWithIndex(consumer.Name, 1, 2) + It("post the nginx B resource to the maestro api", func() { + res := helper.NewAPIResource(consumer.Name, deployB, 1) var resp *http.Response var err error - resource2, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() + resourceB, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resource2.Id).ShouldNot(BeEmpty()) + Expect(*resourceB.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-2", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx-2 deployment, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx B deployment %s, expected 1, got %d", deployB, *deploy.Spec.Replicas) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) @@ -89,71 +92,68 @@ var _ = Describe("Spec resync", Ordered, Label("e2e-tests-spec-resync"), func() }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("patch the nginx-1 resource", func() { - newRes := helper.NewAPIResourceWithIndex(consumer.Name, 2, 1) - patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resource1.Id). - ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resource1.Version, Manifest: newRes.Manifest}).Execute() + It("patch the nginx A resource", func() { + newRes := helper.NewAPIResource(consumer.Name, deployA, 2) + patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resourceA.Id). + ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resourceA.Version, Manifest: newRes.Manifest}).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) - Expect(*patchedResource.Version).To(Equal(*resource1.Version + 1)) + Expect(*patchedResource.Version).To(Equal(*resourceA.Version + 1)) }) - It("ensure the nginx-1 resource is not updated", func() { - // ensure the "nginx-1" deployment in the "default" namespace is not updated + It("ensure the nginx A resource is not updated", func() { Consistently(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return nil } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx-1 deployment, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 1, got %d", deployA, *deploy.Spec.Replicas) } return nil }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("delete the nginx-2 resource", func() { - resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource2.Id).Execute() + It("delete the nginx B resource", func() { + resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceB.Id).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) }) - It("ensure the nginx-2 resource is not deleted", func() { - // ensure the "nginx-2" deployment in the "default" namespace is not deleted + It("ensure the nginx B resource is not deleted", func() { Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-2", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { - return fmt.Errorf("nginx-2 deployment is deleted") + return fmt.Errorf("nginx B deployment %s is deleted", deployB) } } return nil }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("post the nginx-3 resource to the maestro api", func() { - res := helper.NewAPIResourceWithIndex(consumer.Name, 1, 3) + It("post the nginx C resource to the maestro api", func() { + res := helper.NewAPIResource(consumer.Name, deployC, 1) var resp *http.Response var err error - resource3, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() + resourceC, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resource3.Id).ShouldNot(BeEmpty()) + Expect(*resourceC.Id).ShouldNot(BeEmpty()) }) - It("ensure the nginx-3 resource is not created", func() { - // ensure the "nginx-3" deployment in the "default" namespace is not created + It("ensure the nginx C resource is not created", func() { Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-3", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err == nil { - return fmt.Errorf("nginx-3 deployment is created") + return fmt.Errorf("nginx C deployment %s is created", deployC) } return nil }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("start maestro agent", func() { - // patch maestro agent replicas to maestroAgentReplicas + It("restart maestro agent", func() { + // patch maestro agent replicas back deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro-agent").Patch(ctx, "maestro-agent", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroAgentReplicas)), metav1.PatchOptions{ FieldManager: "testconsumer.ClientSet", }) @@ -183,116 +183,123 @@ var _ = Describe("Spec resync", Ordered, Label("e2e-tests-spec-resync"), func() }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("ensure the nginx-1 resource is updated", func() { + It("ensure the nginx A resource is updated", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 2 { - return fmt.Errorf("unexpected replicas for nginx-1 deployment, expected 2, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 2, got %d", deployA, *deploy.Spec.Replicas) } return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }, 3*time.Minute, 3*time.Second).ShouldNot(HaveOccurred()) }) - It("ensure the nginx-2 resource is deleted", func() { + It("ensure the nginx B resource is deleted", func() { Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-2", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil } return err } - return fmt.Errorf("nginx-2 deployment still exists") + return fmt.Errorf("nginx B deployment %s still exists", deployB) }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("ensure the nginx-3 resource is created", func() { + It("ensure the nginx C resource is created", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-3", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx C deployment %s, expected 1, got %d", deployC, *deploy.Spec.Replicas) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("delete the nginx-1 and nginx-3 resource", func() { - resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource1.Id).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - - resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource3.Id).Execute() + It("delete the nginx A and nginx C resources", func() { + resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceA.Id).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil } return err } - return fmt.Errorf("nginx-1 deployment still exists") + return fmt.Errorf("nginx A deployment %s still exists", deployA) }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceC.Id).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-3", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil } return err } - return fmt.Errorf("nginx-3 deployment still exists") + return fmt.Errorf("nginx C deployment %s still exists", deployC) }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) }) +}) +var _ = Describe("Spec Resync After Reconnect", Ordered, Label("e2e-tests-spec-resync-reconnect"), func() { Context("Resource resync resource spec after maestro agent reconnects", func() { - It("post the nginx-1 resource to the maestro api", func() { - res := helper.NewAPIResourceWithIndex(consumer.Name, 1, 1) + var maestroServerReplicas, mqttReplicas int + var resourceA, resourceB, resourceC *openapi.Resource + deployA := fmt.Sprintf("nginx-%s", rand.String(5)) + deployB := fmt.Sprintf("nginx-%s", rand.String(5)) + deployC := fmt.Sprintf("nginx-%s", rand.String(5)) + It("post the nginx A resource to the maestro api", func() { + res := helper.NewAPIResource(consumer.Name, deployA, 1) var resp *http.Response var err error - resource1, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() + resourceA, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resource1.Id).ShouldNot(BeEmpty()) + Expect(*resourceA.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx-1 deployment, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 1, got %d", deployA, *deploy.Spec.Replicas) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("post the nginx-2 resource to the maestro api", func() { - res := helper.NewAPIResourceWithIndex(consumer.Name, 1, 2) + It("post the nginx B resource to the maestro api", func() { + res := helper.NewAPIResource(consumer.Name, deployB, 1) var resp *http.Response var err error - resource2, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() + resourceB, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resource2.Id).ShouldNot(BeEmpty()) + Expect(*resourceB.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-2", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx-2 deployment, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx B deployment %s, expected 1, got %d", deployB, *deploy.Spec.Replicas) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) @@ -416,73 +423,70 @@ var _ = Describe("Spec resync", Ordered, Label("e2e-tests-spec-resync"), func() }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("patch the nginx-1 resource", func() { - newRes := helper.NewAPIResourceWithIndex(consumer.Name, 2, 1) + It("patch the nginx A resource", func() { + newRes := helper.NewAPIResource(consumer.Name, deployA, 2) Eventually(func() error { - patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resource1.Id). - ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resource1.Version, Manifest: newRes.Manifest}).Execute() + patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resourceA.Id). + ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resourceA.Version, Manifest: newRes.Manifest}).Execute() if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("unexpected status code, expected 200, got %d", resp.StatusCode) } - if *patchedResource.Version != *resource1.Version+1 { - return fmt.Errorf("unexpected version, expected %d, got %d", *resource1.Version+1, *patchedResource.Version) + if *patchedResource.Version != *resourceA.Version+1 { + return fmt.Errorf("unexpected version, expected %d, got %d", *resourceA.Version+1, *patchedResource.Version) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("ensure the nginx-1 resource is not updated", func() { - // ensure the "nginx-1" deployment in the "default" namespace is not updated + It("ensure the nginx A resource is not updated", func() { Consistently(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return nil } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx-1 deployment, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 1, got %d", deployA, *deploy.Spec.Replicas) } return nil }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("delete the nginx-2 resource", func() { - resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource2.Id).Execute() + It("delete the nginx B resource", func() { + resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceB.Id).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) }) - It("ensure the nginx-2 resource is not deleted", func() { - // ensure the "nginx-2" deployment in the "default" namespace is not deleted + It("ensure the nginx B resource is not deleted", func() { Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-2", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { - return fmt.Errorf("nginx-2 deployment is deleted") + return fmt.Errorf("nginx B deployment %s is deleted", deployB) } } return nil }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("post the nginx-3 resource to the maestro api", func() { - res := helper.NewAPIResourceWithIndex(consumer.Name, 1, 3) + It("post the nginx C resource to the maestro api", func() { + res := helper.NewAPIResource(consumer.Name, deployC, 1) var resp *http.Response var err error - resource3, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() + resourceC, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resource3.Id).ShouldNot(BeEmpty()) + Expect(*resourceC.Id).ShouldNot(BeEmpty()) }) - It("ensure the nginx-3 resource is not created", func() { - // ensure the "nginx-3" deployment in the "default" namespace is not created + It("ensure the nginx C resource is not created", func() { Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-3", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err == nil { - return fmt.Errorf("nginx-3 deployment is created") + return fmt.Errorf("nginx C deployment %s is created", deployC) } return nil }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) @@ -539,74 +543,74 @@ var _ = Describe("Spec resync", Ordered, Label("e2e-tests-spec-resync"), func() Expect(err).ShouldNot(HaveOccurred()) }) - It("ensure the nginx-1 resource is updated", func() { + It("ensure the nginx A resource is updated", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 2 { - return fmt.Errorf("unexpected replicas for nginx-1 deployment, expected 2, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 2, got %d", deployA, *deploy.Spec.Replicas) } return nil }, 3*time.Minute, 3*time.Second).ShouldNot(HaveOccurred()) }) - It("ensure the nginx-2 resource is deleted", func() { + It("ensure the nginx B resource is deleted", func() { Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-2", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil } return err } - return fmt.Errorf("nginx-2 deployment still exists") + return fmt.Errorf("nginx B deployment %s still exists", deployB) }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("ensure the nginx-3 resource is created", func() { + It("ensure the nginx C resource is created", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-3", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx C deployment %s, expected 1, got %d", deployC, *deploy.Spec.Replicas) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("delete the nginx-1 and nginx-3 resource", func() { - resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource1.Id).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - - resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource3.Id).Execute() + It("delete the nginx A and nginx C resources", func() { + resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceA.Id).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-1", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil } return err } - return fmt.Errorf("nginx-1 deployment still exists") + return fmt.Errorf("nginx A deployment %s still exists", deployA) }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceC.Id).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx-3", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil } return err } - return fmt.Errorf("nginx-3 deployment still exists") + return fmt.Errorf("nginx C deployment %s still exists", deployC) }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) }) diff --git a/test/e2e/pkg/status_resync_test.go b/test/e2e/pkg/status_resync_test.go index baa88525..a2292333 100644 --- a/test/e2e/pkg/status_resync_test.go +++ b/test/e2e/pkg/status_resync_test.go @@ -15,15 +15,16 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/rand" ) -var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), func() { - var resource *openapi.Resource - var mqttReplicas, maestroServerReplicas int - +var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status-resync-restart"), func() { Context("Resource resync resource status after maestro server restarts", func() { + var maestroServerReplicas int + var resource *openapi.Resource + name := fmt.Sprintf("nginx-%s", rand.String(5)) It("post the nginx resource with non-default service account to the maestro api", func() { - res := helper.NewAPIResourceWithSA(consumer.Name, 1, "nginx") + res := helper.NewAPIResourceWithSA(consumer.Name, name, name, 1) var resp *http.Response var err error resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -32,12 +33,12 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun Expect(*resource.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx deployment %s, expected 1, got %d", name, *deploy.Spec.Replicas) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) @@ -61,7 +62,7 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun return fmt.Errorf("unexpected status, expected error looking up service account default/nginx, got %s", string(statusJSON)) } return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) }) It("shut down maestro server", func() { @@ -91,21 +92,21 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - It("create default/nginx serviceaccount", func() { + It("create serviceaccount for nginx deployment", func() { _, err := consumer.ClientSet.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ - Name: "nginx", + Name: name, }, }, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) // delete the nginx deployment to tigger recreating - err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, "nginx", metav1.DeleteOptions{}) + err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, name, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) - It("start maestro server", func() { - // patch maestro server replicas to 1 + It("restart maestro server", func() { + // patch maestro server replicas back deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroServerReplicas)), metav1.PatchOptions{ FieldManager: "testConsumer.ClientSet", }) @@ -161,7 +162,7 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -169,16 +170,21 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun return err } return fmt.Errorf("nginx deployment still exists") - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) - err = consumer.ClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, "nginx", metav1.DeleteOptions{}) + err = consumer.ClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, name, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) }) +}) +var _ = Describe("Status Resync After Reconnect", Ordered, Label("e2e-tests-status-resync-reconnect"), func() { Context("Resource resync resource status after maestro server reconnects", func() { + var mqttReplicas int + var resource *openapi.Resource + name := fmt.Sprintf("nginx-%s", rand.String(5)) It("post the nginx resource with non-default service account to the maestro api", func() { - res := helper.NewAPIResourceWithSA(consumer.Name, 1, "nginx") + res := helper.NewAPIResourceWithSA(consumer.Name, name, name, 1) var resp *http.Response var err error resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -187,12 +193,12 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun Expect(*resource.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas, expected 1, got %d", *deploy.Spec.Replicas) + return fmt.Errorf("unexpected replicas for nginx deployment %s, expected 1, got %d", name, *deploy.Spec.Replicas) } return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) @@ -216,7 +222,7 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun return fmt.Errorf("unexpected status, expected error looking up service account default/nginx, got %s", string(statusJSON)) } return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) }) It("delete the mqtt-broker service for server", func() { @@ -224,16 +230,16 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun Expect(err).ShouldNot(HaveOccurred()) }) - It("create default/nginx serviceaccount", func() { + It("create serviceaccount for nginx deployment", func() { _, err := consumer.ClientSet.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ - Name: "nginx", + Name: name, }, }, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) // delete the nginx deployment to tigger recreating - err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, "nginx", metav1.DeleteOptions{}) + err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, name, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) @@ -343,7 +349,7 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, "nginx", metav1.GetOptions{}) + _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -351,9 +357,9 @@ var _ = Describe("Status resync", Ordered, Label("e2e-tests-status-resync"), fun return err } return fmt.Errorf("nginx deployment still exists") - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) - err = consumer.ClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, "nginx", metav1.DeleteOptions{}) + err = consumer.ClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, name, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) }) diff --git a/test/e2e/pkg/suite_test.go b/test/e2e/pkg/suite_test.go index dc185781..39cf809c 100644 --- a/test/e2e/pkg/suite_test.go +++ b/test/e2e/pkg/suite_test.go @@ -1,9 +1,11 @@ package e2e_test import ( + "bytes" "context" "crypto/tls" "flag" + "fmt" "log" "net/http" "testing" @@ -11,6 +13,8 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + matav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" @@ -110,6 +114,8 @@ var _ = BeforeSuite(func() { }) var _ = AfterSuite(func() { + // dump debug info + dumpDebugInfo() grpcConn.Close() cancel() }) @@ -119,3 +125,43 @@ type ConsumerOptions struct { KubeConfig string ClientSet *kubernetes.Clientset } + +func dumpDebugInfo() { + // dump the maestro server logs + dumpPodLogs(ctx, consumer.ClientSet, "app=maestro", "maestro") + // dump the maestro agent ogs + dumpPodLogs(ctx, consumer.ClientSet, "app=maestro-agent", "maestro-agent") +} + +func dumpPodLogs(ctx context.Context, kubeClient kubernetes.Interface, podSelector, podNamespace string) error { + // get pods from podSelector + pods, err := kubeClient.CoreV1().Pods(podNamespace).List(ctx, matav1.ListOptions{LabelSelector: podSelector}) + if err != nil { + return fmt.Errorf("failed to list pods with pod selector (%s): %v", podSelector, err) + } + + for _, pod := range pods.Items { + logReq := kubeClient.CoreV1().Pods(podNamespace).GetLogs(pod.Name, &corev1.PodLogOptions{}) + logs, err := logReq.Stream(context.Background()) + if err != nil { + return fmt.Errorf("failed to open log stream: %v", err) + } + defer logs.Close() + + buf := new(bytes.Buffer) + _, err = buf.ReadFrom(logs) + if err != nil { + return fmt.Errorf("failed to read pod logs: %v", err) + } + + log.Printf("=========================================== POD LOGS START ===========================================") + log.Printf("Pod %s/%s phase: %s", pod.Name, podNamespace, string(pod.Status.Phase)) + for _, containerStatus := range pod.Status.ContainerStatuses { + log.Printf("Container %s status: %v", containerStatus.Name, containerStatus.State) + } + log.Printf("Pod %s/%s logs: \n%s", pod.Name, podNamespace, buf.String()) + log.Printf("=========================================== POD LOGS STOP ===========================================") + } + + return nil +} diff --git a/test/factories.go b/test/factories.go index d9331a20..bbfd07c3 100755 --- a/test/factories.go +++ b/test/factories.go @@ -13,6 +13,7 @@ import ( "gorm.io/datatypes" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/rand" workv1 "open-cluster-management.io/api/work/v1" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" @@ -24,42 +25,8 @@ var testManifestJSON = ` "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { - "name": "nginx", - "namespace": "default" - }, - "spec": { - "replicas": %d, - "selector": { - "matchLabels": { - "app": "nginx" - } - }, - "template": { - "metadata": { - "labels": { - "app": "nginx" - } - }, - "spec": { - "containers": [ - { - "image": "nginxinc/nginx-unprivileged", - "name": "nginx" - } - ] - } - } - } -} -` - -var testManifestJSONWithSA = ` -{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "name": "nginx", - "namespace": "default" + "name": "%s", + "namespace": "%s" }, "spec": { "replicas": %d, @@ -88,47 +55,13 @@ var testManifestJSONWithSA = ` } ` -var testManifestIndexJSON = ` -{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "name": "nginx-%d", - "namespace": "default" - }, - "spec": { - "replicas": %d, - "selector": { - "matchLabels": { - "app": "nginx" - } - }, - "template": { - "metadata": { - "labels": { - "app": "nginx" - } - }, - "spec": { - "containers": [ - { - "image": "nginxinc/nginx-unprivileged", - "name": "nginx" - } - ] - } - } - } -} -` - var testReadOnlyManifestJSON = ` { "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { - "name": "nginx", - "namespace": "default" + "name": "%s", + "namespace": "%s" }, "update_strategy": { "type": "ReadOnly" @@ -136,34 +69,21 @@ var testReadOnlyManifestJSON = ` } ` -func (helper *Helper) NewAPIResource(consumerName string, replicas int) openapi.Resource { - testManifest := map[string]interface{}{} - if err := json.Unmarshal([]byte(fmt.Sprintf(testManifestJSON, replicas)), &testManifest); err != nil { - helper.T.Errorf("error unmarshalling test manifest: %q", err) - } - - return openapi.Resource{ - Manifest: testManifest, - ConsumerName: &consumerName, - } -} - -func (helper *Helper) NewAPIResourceWithSA(consumerName string, replicas int, sa string) openapi.Resource { - testManifest := map[string]interface{}{} - if err := json.Unmarshal([]byte(fmt.Sprintf(testManifestJSONWithSA, replicas, sa)), &testManifest); err != nil { - helper.T.Errorf("error unmarshalling test manifest: %q", err) - } - - return openapi.Resource{ - Manifest: testManifest, - ConsumerName: &consumerName, - } +// NewAPIResource creates an API resource with the given consumer name, deploy name, and replicas. +// It generates a deployment for nginx using the testManifestJSON template, giving it a random deploy +// name to avoid testing conflicts. +func (helper *Helper) NewAPIResource(consumerName, deployName string, replicas int) openapi.Resource { + sa := "default" // default service account + return helper.NewAPIResourceWithSA(consumerName, deployName, sa, replicas) } -func (helper *Helper) NewAPIResourceWithIndex(consumerName string, replicas, index int) openapi.Resource { +// NewAPIResourceWithSA creates an API resource with the given consumer name, deploy name, service account, and replicas. +// It generates a nginx deployment using the testManifestJSON template, assigning a random deploy name to avoid testing conflicts. +func (helper *Helper) NewAPIResourceWithSA(consumerName, deployName, sa string, replicas int) openapi.Resource { + namespace := "default" // default namespace testManifest := map[string]interface{}{} - if err := json.Unmarshal([]byte(fmt.Sprintf(testManifestIndexJSON, index, replicas)), &testManifest); err != nil { - helper.T.Errorf("error unmarshalling test manifest: %q", err) + if err := json.Unmarshal([]byte(fmt.Sprintf(testManifestJSON, deployName, namespace, replicas, sa)), &testManifest); err != nil { + helper.T.Errorf("error unmarshalling manifest: %q", err) } return openapi.Resource{ @@ -172,13 +92,22 @@ func (helper *Helper) NewAPIResourceWithIndex(consumerName string, replicas, ind } } -func (helper *Helper) GetTestNginxJSON(replicas int) []byte { - return []byte(fmt.Sprintf(testManifestJSON, replicas)) +// NewResourceManifestJSON creates a resource manifest in JSON format with the given deploy name and replicas. +// It generates a deployment for nginx using the testManifestJSON template, assigning a random deploy name to avoid +// testing conflicts. +func (helper *Helper) NewResourceManifestJSON(deployName string, replicas int) string { + namespace := "default" // default namespace + sa := "default" // default service account + return fmt.Sprintf(testManifestJSON, deployName, namespace, replicas, sa) } -func (helper *Helper) NewReadOnlyAPIResource(consumerName string) openapi.Resource { +// NewReadOnlyAPIResource creates an API resource with the given consumer name and deploy name. +// It generates a read-only deployment manifests for nginx using the testReadOnlyManifestJSON template, +// giving it a random deploy name to avoid testing conflicts. +func (helper *Helper) NewReadOnlyAPIResource(consumerName, deployName string) openapi.Resource { + namespace := "default" // default namespace testManifest := map[string]interface{}{} - if err := json.Unmarshal([]byte(fmt.Sprint(testReadOnlyManifestJSON)), &testManifest); err != nil { + if err := json.Unmarshal([]byte(fmt.Sprintf(testReadOnlyManifestJSON, deployName, namespace)), &testManifest); err != nil { helper.T.Errorf("error unmarshalling test manifest: %q", err) } @@ -188,8 +117,10 @@ func (helper *Helper) NewReadOnlyAPIResource(consumerName string) openapi.Resour } } -func (helper *Helper) NewResource(consumerName string, replicas int) *api.Resource { - testResource := helper.NewAPIResource(consumerName, replicas) +// NewReadOnlyResourceManifestJSON creates a resource with the given consumer name, deploy name, replicas, and resource version. +// It generates a deployment for nginx using the testManifestJSON template, assigning a random deploy name to avoid testing conflicts. +func (helper *Helper) NewResource(consumerName, deployName string, replicas int, resourceVersion int32) *api.Resource { + testResource := helper.NewAPIResource(consumerName, deployName, replicas) testPayload, err := api.EncodeManifest(testResource.Manifest, testResource.DeleteOption, testResource.UpdateStrategy) if err != nil { helper.T.Errorf("error encoding manifest: %q", err) @@ -199,15 +130,17 @@ func (helper *Helper) NewResource(consumerName string, replicas int) *api.Resour ConsumerName: consumerName, Type: api.ResourceTypeSingle, Payload: testPayload, - Version: 1, + Version: resourceVersion, } return resource } -func (helper *Helper) CreateResource(consumerName string, replicas int) *api.Resource { +// CreateResource creates a resource with the given consumer name, deploy name, and replicas. +// It generates a deployment for nginx using the testManifestJSON template, assigning a random deploy name to avoid testing conflicts. +func (helper *Helper) CreateResource(consumerName, deployName string, replicas int) *api.Resource { + resource := helper.NewResource(consumerName, deployName, replicas, 1) resourceService := helper.Env().Services.Resources() - resource := helper.NewResource(consumerName, replicas) res, err := resourceService.Create(context.Background(), resource) if err != nil { @@ -217,30 +150,43 @@ func (helper *Helper) CreateResource(consumerName string, replicas int) *api.Res return res } +// CreateResourceList generates a list of resources with the specified consumer name and count. +// Each resource gets a randomly generated deploy name for nginx deployments to avoid testing conflicts. func (helper *Helper) CreateResourceList(consumerName string, count int) (resources []*api.Resource) { for i := 1; i <= count; i++ { - resources = append(resources, helper.CreateResource(consumerName, 1)) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + resources = append(resources, helper.CreateResource(consumerName, deployName, 1)) time.Sleep(10 * time.Millisecond) } + return resources } -// EncodeManifestBundle converts resource manifests into a CloudEvent JSONMap representation. -func (helper *Helper) EncodeManifestBundle(manifest map[string]interface{}) (datatypes.JSONMap, error) { - if len(manifest) == 0 { +// EncodeManifestBundle converts resource manifest JSON into a CloudEvent JSONMap representation. +func (helper *Helper) EncodeManifestBundle(manifestJSON, deployName, deployNamespace string) (datatypes.JSONMap, error) { + if len(manifestJSON) == 0 { return nil, nil } + // unmarshal manifest JSON + manifest := map[string]interface{}{} + if err := json.Unmarshal([]byte(manifestJSON), &manifest); err != nil { + return nil, fmt.Errorf("error unmarshalling manifest: %v", err) + } + + // default deletion option delOption := &workv1.DeleteOption{ PropagationPolicy: workv1.DeletePropagationPolicyTypeForeground, } + // default update strategy upStrategy := &workv1.UpdateStrategy{ Type: workv1.UpdateStrategyTypeServerSideApply, } + source := "maestro" // create a cloud event with the manifest as the data - evt := cetypes.NewEventBuilder("maestro", cetypes.CloudEventsType{}).NewEvent() + evt := cetypes.NewEventBuilder(source, cetypes.CloudEventsType{}).NewEvent() eventPayload := &workpayload.ManifestBundle{ Manifests: []workv1.Manifest{ { @@ -267,47 +213,51 @@ func (helper *Helper) EncodeManifestBundle(manifest map[string]interface{}) (dat ResourceIdentifier: workv1.ResourceIdentifier{ Group: "apps", Resource: "deployments", - Name: "nginx", - Namespace: "default", + Name: deployName, + Namespace: deployNamespace, }, }, }, } + // set the event data if err := evt.SetData(cloudevents.ApplicationJSON, eventPayload); err != nil { return nil, fmt.Errorf("failed to set cloud event data: %v", err) } // convert cloudevent to JSONMap - manifest, err := api.CloudEventToJSONMap(&evt) + manifestBundle, err := api.CloudEventToJSONMap(&evt) if err != nil { return nil, fmt.Errorf("failed to convert cloudevent to resource manifest: %v", err) } - return manifest, nil + return manifestBundle, nil } -func (helper *Helper) NewResourceBundle(name, consumerName string, replicas int) *api.Resource { - testResource := helper.NewAPIResource(consumerName, replicas) - testPayload, err := helper.EncodeManifestBundle(testResource.Manifest) +// NewResourceBundle creates a resource bundle with the given consumer name, deploy name, replicas, and resource version. +func (helper *Helper) NewResourceBundle(consumerName, deployName string, replicas int, resourceVersion int32) *api.Resource { + namespace := "default" // default namespace + manifestJSON := helper.NewResourceManifestJSON(deployName, replicas) + payload, err := helper.EncodeManifestBundle(manifestJSON, deployName, namespace) if err != nil { helper.T.Errorf("error encoding manifest bundle: %q", err) } resource := &api.Resource{ - Name: name, ConsumerName: consumerName, Type: api.ResourceTypeBundle, - Payload: testPayload, - Version: 1, + Payload: payload, + Version: resourceVersion, } return resource } -func (helper *Helper) CreateResourceBundle(name, consumerName string, replicas int) *api.Resource { +// CreateResourceBundle creates a resource bundle with the given consumer name, deploy name and replicas. +// It generates a deployment for nginx using the testManifestJSON template, assigning a random deploy name to avoid testing conflicts. +func (helper *Helper) CreateResourceBundle(consumerName, deployName string, replicas int) *api.Resource { + resourceBundle := helper.NewResourceBundle(consumerName, deployName, replicas, 1) resourceService := helper.Env().Services.Resources() - resourceBundle := helper.NewResourceBundle(name, consumerName, replicas) res, err := resourceService.Create(context.Background(), resourceBundle) if err != nil { @@ -317,11 +267,15 @@ func (helper *Helper) CreateResourceBundle(name, consumerName string, replicas i return res } -func (helper *Helper) CreateResourceBundleList(consumerName string, count int) (resources []*api.Resource) { +// CreateResourceBundleList generates a list of resource bundles with the specified consumer name and count. +// Each resource gets a randomly generated deploy name for nginx deployments to avoid testing conflicts. +func (helper *Helper) CreateResourceBundleList(consumerName string, count int) (resourceBundles []*api.Resource) { for i := 1; i <= count; i++ { - resources = append(resources, helper.CreateResourceBundle(fmt.Sprintf("resource%d", i), consumerName, 1)) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + resourceBundles = append(resourceBundles, helper.CreateResourceBundle(consumerName, deployName, 1)) } - return resources + + return resourceBundles } func (helper *Helper) CreateConsumer(name string) *api.Consumer { @@ -333,7 +287,7 @@ func (helper *Helper) CreateConsumerWithLabels(name string, labels map[string]st consumer, err := consumerService.Create(context.Background(), &api.Consumer{Name: name, Labels: db.EmptyMapToNilStringMap(&labels)}) if err != nil { - helper.T.Errorf("error creating resource: %q", err) + helper.T.Errorf("error creating consumer: %q", err) } return consumer } @@ -342,16 +296,19 @@ func (helper *Helper) CreateConsumerList(count int) (consumers []*api.Consumer) for i := 1; i <= count; i++ { consumers = append(consumers, helper.CreateConsumer(fmt.Sprintf("consumer-%d", i))) } + return consumers } -// ManifestToEvent converts a manifest into a CloudEvent representation with manifest data. -func (helper *Helper) ManifestToEvent(replicas int, source, action, consumerName, resourceID string, - resourceVersion int64, deleting bool) (*cloudevents.Event, error) { - +// NewEvent creates a CloudEvent with the given source, action, consumer name, resource ID, deploy name, resource version, and replicas. +// It generates a nginx deployment using the testManifestJSON template, assigning a random deploy name to avoid testing conflicts. +// If the action is "delete_request," the event includes a deletion timestamp. +func (helper *Helper) NewEvent(source, action, consumerName, resourceID, deployName string, resourceVersion int64, replicas int) *cloudevents.Event { + sa := "default" // default service account + deployNamespace := "default" // default namespace testManifest := map[string]interface{}{} - if err := json.Unmarshal([]byte(fmt.Sprintf(testManifestJSON, replicas)), &testManifest); err != nil { - return nil, fmt.Errorf("error unmarshalling test manifest: %v", err) + if err := json.Unmarshal([]byte(fmt.Sprintf(testManifestJSON, deployName, deployNamespace, replicas, sa)), &testManifest); err != nil { + helper.T.Errorf("error unmarshalling manifest: %q", err) } eventType := cetypes.CloudEventsType{ @@ -363,11 +320,20 @@ func (helper *Helper) ManifestToEvent(replicas int, source, action, consumerName WithClusterName(consumerName). WithResourceID(resourceID). WithResourceVersion(resourceVersion) - if deleting { + + // add deletion timestamp if action is delete_request + if action == "delete_request" { evtBuilder.WithDeletionTimestamp(time.Now()) } + evt := evtBuilder.NewEvent() + // if action is delete_request, no data is needed + if action == "delete_request" { + evt.SetData(cloudevents.ApplicationJSON, nil) + return &evt + } + eventPayload := &workpayload.Manifest{ Manifest: unstructured.Unstructured{Object: testManifest}, DeleteOption: &workv1.DeleteOption{ @@ -392,19 +358,21 @@ func (helper *Helper) ManifestToEvent(replicas int, source, action, consumerName } if err := evt.SetData(cloudevents.ApplicationJSON, eventPayload); err != nil { - return nil, fmt.Errorf("failed to set cloud event data: %v", err) + helper.T.Errorf("failed to set cloud event data: %q", err) } - return &evt, nil + return &evt } -// ManifestsToBundleEvent converts a list of manifests into a CloudEvent representation with manifest bundle data. -func (helper *Helper) ManifestsToBundleEvent(replicas int, source, action, consumerName, resourceID string, - resourceVersion int64, deleting bool) (*cloudevents.Event, error) { - +// NewBundleEvent creates a CloudEvent with the given source, action, consumer name, resource ID, resource version, and replicas. +// It generates a bundle of nginx deployments using the testManifestJSON template, assigning a random deploy name to avoid testing conflicts. +// If the action is "delete_request," the event includes a deletion timestamp. +func (helper *Helper) NewBundleEvent(source, action, consumerName, resourceID, deployName string, resourceVersion int64, replicas int) *cloudevents.Event { + sa := "default" // default service account + deployNamespace := "default" // default namespace testManifest := map[string]interface{}{} - if err := json.Unmarshal([]byte(fmt.Sprintf(testManifestJSON, replicas)), &testManifest); err != nil { - return nil, fmt.Errorf("error unmarshalling test manifest: %v", err) + if err := json.Unmarshal([]byte(fmt.Sprintf(testManifestJSON, deployName, deployNamespace, replicas, sa)), &testManifest); err != nil { + helper.T.Errorf("error unmarshalling manifest: %q", err) } eventType := cetypes.CloudEventsType{ @@ -418,11 +386,20 @@ func (helper *Helper) ManifestsToBundleEvent(replicas int, source, action, consu WithClusterName(consumerName). WithResourceID(resourceID). WithResourceVersion(resourceVersion) - if deleting { + + // add deletion timestamp if action is delete_request + if action == "delete_request" { evtBuilder.WithDeletionTimestamp(time.Now()) } + evt := evtBuilder.NewEvent() + // if action is delete_request, no data is needed + if action == "delete_request" { + evt.SetData(cloudevents.ApplicationJSON, nil) + return &evt + } + eventPayload := &workpayload.ManifestBundle{ Manifests: []workv1.Manifest{ { @@ -453,16 +430,16 @@ func (helper *Helper) ManifestsToBundleEvent(replicas int, source, action, consu ResourceIdentifier: workv1.ResourceIdentifier{ Group: "apps", Resource: "deployments", - Name: "nginx", - Namespace: "default", + Name: deployName, + Namespace: deployNamespace, }, }, }, } if err := evt.SetData(cloudevents.ApplicationJSON, eventPayload); err != nil { - return nil, fmt.Errorf("failed to set cloud event data: %v", err) + helper.T.Errorf("failed to set cloud event data: %q", err) } - return &evt, nil + return &evt } diff --git a/test/integration/consumers_test.go b/test/integration/consumers_test.go index bbb75bbc..284da9a1 100644 --- a/test/integration/consumers_test.go +++ b/test/integration/consumers_test.go @@ -188,7 +188,8 @@ func TestConsumerDeleteForbidden(t *testing.T) { Expect(*consumer.Id).NotTo(BeEmpty()) // attach resource to the consumer - res := h.NewAPIResource(*consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.NewAPIResource(*consumer.Name, deployName, 1) resource, resp, err := client.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).To(Succeed()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) @@ -245,7 +246,8 @@ func TestConsumerDeleting(t *testing.T) { go func(name, id string) { defer wg.Done() for i := 0; i < resourceNum; i++ { - res := h.NewAPIResource(name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.NewAPIResource(name, deployName, 1) resource, resp, err := client.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() resourceChan <- &Result{ resource: resource, diff --git a/test/integration/controller_test.go b/test/integration/controller_test.go index 74c6c51b..a6ce56cc 100755 --- a/test/integration/controller_test.go +++ b/test/integration/controller_test.go @@ -202,7 +202,8 @@ func TestControllerReconcile(t *testing.T) { time.Sleep(100 * time.Millisecond) consumer := h.CreateConsumer("cluster-" + rand.String(5)) - resource := h.CreateResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + resource := h.CreateResource(consumer.Name, deployName, 1) // Eventually, the event will be processed by the controller. Eventually(func() error { diff --git a/test/integration/pulse_server_test.go b/test/integration/pulse_server_test.go index d838b47a..9556f2bd 100644 --- a/test/integration/pulse_server_test.go +++ b/test/integration/pulse_server_test.go @@ -8,6 +8,7 @@ import ( . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/rand" workv1 "open-cluster-management.io/api/work/v1" "github.com/openshift-online/maestro/pkg/api" @@ -71,7 +72,8 @@ func TestPulseServer(t *testing.T) { }) Expect(err).NotTo(HaveOccurred()) - res := h.CreateResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.CreateResource(consumer.Name, deployName, 1) h.StartControllerManager(ctx) h.StartWorkAgent(ctx, consumer.Name, false) clientHolder := h.WorkAgentHolder diff --git a/test/integration/resource_test.go b/test/integration/resource_test.go index 50165557..5e9d86ce 100755 --- a/test/integration/resource_test.go +++ b/test/integration/resource_test.go @@ -44,7 +44,8 @@ func TestResourceGet(t *testing.T) { Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) consumer := h.CreateConsumer("cluster-" + rand.String(5)) - resource := h.CreateResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + resource := h.CreateResource(consumer.Name, deployName, 1) res, resp, err := client.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, resource.ID).Execute() Expect(err).NotTo(HaveOccurred()) @@ -68,7 +69,8 @@ func TestResourcePost(t *testing.T) { clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) - res := h.NewAPIResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.NewAPIResource(consumer.Name, deployName, 1) h.StartControllerManager(ctx) h.StartWorkAgent(ctx, consumer.Name, false) clientHolder := h.WorkAgentHolder @@ -189,7 +191,8 @@ func TestResourcePostWithoutName(t *testing.T) { clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) - res := h.NewAPIResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.NewAPIResource(consumer.Name, deployName, 1) h.StartControllerManager(ctx) resourceService := h.Env().Services.Resources() // POST responses per openapi spec: 201, 400, 409, 500 @@ -230,7 +233,8 @@ func TestResourcePostWithName(t *testing.T) { clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) - res := h.NewAPIResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.NewAPIResource(consumer.Name, deployName, 1) h.StartControllerManager(ctx) // POST responses per openapi spec: 201, 400, 409, 500 @@ -266,7 +270,8 @@ func TestResourcePatch(t *testing.T) { clientHolder := h.WorkAgentHolder agentWorkClient := clientHolder.ManifestWorks(consumer.ID) - res := h.CreateResource(consumer.ID, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.CreateResource(consumer.ID, deployName, 1) Expect(res.Version).To(Equal(int32(1))) var work *workv1.ManifestWork @@ -294,7 +299,7 @@ func TestResourcePatch(t *testing.T) { }, 20*time.Second, 2*time.Second).Should(Succeed()) // 200 OK - newRes := h.NewAPIResource(consumer.ID, 2) + newRes := h.NewAPIResource(consumer.Name, deployName, 2) resource, resp, err := client.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, res.ID).ResourcePatchRequest(openapi.ResourcePatchRequest{Version: &res.Version, Manifest: newRes.Manifest}).Execute() Expect(err).NotTo(HaveOccurred(), "Error posting object: %v", err) Expect(resp.StatusCode).To(Equal(http.StatusOK)) @@ -433,7 +438,8 @@ func TestResourceBundleGet(t *testing.T) { Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) consumer := h.CreateConsumer("cluster-" + rand.String(5)) - resourceBundle := h.CreateResourceBundle("resource1", consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + resourceBundle := h.CreateResourceBundle(consumer.Name, deployName, 1) resBundle, resp, err := client.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(ctx, resourceBundle.ID).Execute() Expect(err).NotTo(HaveOccurred()) @@ -482,8 +488,9 @@ func TestUpdateResourceWithRacingRequests(t *testing.T) { ctx := h.NewAuthenticatedContext(account) consumer := h.CreateConsumer("cluster-" + rand.String(5)) - res := h.CreateResource(consumer.Name, 1) - newRes := h.NewAPIResource(consumer.Name, 2) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.CreateResource(consumer.Name, deployName, 1) + newRes := h.NewAPIResource(consumer.Name, deployName, 2) // starts 20 threads to update this resource at the same time threads := 20 @@ -549,7 +556,8 @@ func TestResourceFromGRPC(t *testing.T) { // create a mock resource clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) - res := h.NewResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.NewResource(consumer.Name, deployName, 1, 1) res.ID = uuid.NewString() h.StartControllerManager(ctx) @@ -667,7 +675,7 @@ func TestResourceFromGRPC(t *testing.T) { return nil }, 10*time.Second, 1*time.Second).Should(Succeed()) - newRes := h.NewResource(consumer.Name, 2) + newRes := h.NewResource(consumer.Name, deployName, 2, 1) newRes.ID = *resource.Id newRes.Version = *resource.Version err = h.GRPCSourceClient.Publish(ctx, types.CloudEventsType{ @@ -759,7 +767,8 @@ func TestResourceBundleFromGRPC(t *testing.T) { // create a mock resource clusterName := "cluster-" + rand.String(5) consumer := h.CreateConsumer(clusterName) - res := h.NewResource(consumer.Name, 1) + deployName := fmt.Sprintf("nginx-%s", rand.String(5)) + res := h.NewResource(consumer.Name, deployName, 1, 1) res.ID = uuid.NewString() h.StartControllerManager(ctx) @@ -864,7 +873,7 @@ func TestResourceBundleFromGRPC(t *testing.T) { return nil }, 10*time.Second, 1*time.Second).Should(Succeed()) - newRes := h.NewResource(consumer.Name, 2) + newRes := h.NewResource(consumer.Name, deployName, 2, 1) newRes.ID = res.ID err = h.GRPCSourceClient.Publish(ctx, types.CloudEventsType{ CloudEventsDataType: payload.ManifestBundleEventDataType, From f4d9da7a0710f8d8dd4b4b9c45e1bd63ee7509f1 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 17:06:04 +0800 Subject: [PATCH 19/67] chore(deps): update openapitools/openapi-generator-cli docker tag to v7.8.0 (#181) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- Dockerfile.openapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.openapi b/Dockerfile.openapi index 28071923..6e07a7fa 100755 --- a/Dockerfile.openapi +++ b/Dockerfile.openapi @@ -1,4 +1,4 @@ -FROM openapitools/openapi-generator-cli:v7.7.0 +FROM openapitools/openapi-generator-cli:v7.8.0 RUN apt-get update RUN apt-get install -y make sudo git From e9b98cc00ede981eef44ca389e02fa3118cae87d Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:21:38 +0800 Subject: [PATCH 20/67] chore(deps): update konflux references (#178) * chore(deps): update konflux references Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> * Migration from 0.1 to 0.2 Signed-off-by: clyang82 --------- Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Signed-off-by: clyang82 Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: clyang82 --- .tekton/maestro-pull-request.yaml | 22 ------------------- .tekton/maestro-push.yaml | 36 ++++++------------------------- 2 files changed, 7 insertions(+), 51 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index 04c8d40a..4de37b77 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -356,28 +356,6 @@ spec: operator: in values: - "false" - - name: sbom-json-check - params: - - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - - name: IMAGE_DIGEST - value: $(tasks.build-container.results.IMAGE_DIGEST) - runAfter: - - build-container - taskRef: - params: - - name: name - value: sbom-json-check - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:501181e78ec76a0a9083ffc275f5307ba5653a762259412bcffaeb314f13f8ec - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" workspaces: - name: workspace - name: git-auth diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index 1b47f03a..5dfec77f 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -188,7 +188,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:492db3ca0bf5c44b67a38ba937de645a5282be2cb447dc30d0227424ca3c736f + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:1b75828f2b7193ec9c567b907fdc0b2c1bb08cca4ab2dfcecbe9ff84f836cfc8 - name: kind value: task resolver: bundles @@ -223,7 +223,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:2b05d0463033cfab93dfa35691afb66ff09f2be39e96b856adee70baa970fab5 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:d47b0b67109940b264cff6995941aa56c0517562b4939b85d6ac3ed750bf59f1 - name: kind value: task resolver: bundles @@ -246,7 +246,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:929bf55a5e364c957a5f907a5516fb8f8893c389ae5985767de7311736eb904a + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:14b91ad9124b722b44222685013faaf9af8ac5b66030d9abeb1c61da3c118cdd - name: kind value: task resolver: bundles @@ -275,7 +275,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:6c389c2f670975cc0dfdd07dcb33142b1668bbfd46f6af520dd0ab736c56e7e9 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:1f17ef7ab9859d6e2215ef2ed532ebc15e516ba09226b8cae77907a7a8b7cedd - name: kind value: task resolver: bundles @@ -297,7 +297,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:fb1aa363b56f9e9bdb1b30a46ddace9035add63fdfb5e39d01b27ae84cc7e425 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:b8c51079ea1110e1095c229e184e3c340120ba211a63a200e836706f5a35361c - name: kind value: task resolver: bundles @@ -314,7 +314,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:1ef6a3ab9c4ba9e735c6924008714ef2a873597837be9d4d927522d5d733bd07 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.2@sha256:479bd0d9aaa7b377ff5f8ad93168d44807455646f2161688637cb2e4e0b990d9 - name: kind value: task resolver: bundles @@ -344,29 +344,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:cda1e319c81a32356d900b2f78483e072fac29684ad81c73aa2314a7f3a389e0 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - - name: sbom-json-check - params: - - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - - name: IMAGE_DIGEST - value: $(tasks.build-container.results.IMAGE_DIGEST) - runAfter: - - build-container - taskRef: - params: - - name: name - value: sbom-json-check - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:501181e78ec76a0a9083ffc275f5307ba5653a762259412bcffaeb314f13f8ec + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:4c1a1cd74eecfcd93222903ea28319a8068f2d5c9678e4db14e2c605831ad90c - name: kind value: task resolver: bundles From 9e32ca8777c291a58c7eb0d5dd1509e49cee3e27 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:01:45 +0800 Subject: [PATCH 21/67] chore(deps): update konflux references (#187) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-pull-request.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index 4de37b77..a41d9e18 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -191,7 +191,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:492db3ca0bf5c44b67a38ba937de645a5282be2cb447dc30d0227424ca3c736f + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:1b75828f2b7193ec9c567b907fdc0b2c1bb08cca4ab2dfcecbe9ff84f836cfc8 - name: kind value: task resolver: bundles @@ -226,7 +226,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:2b05d0463033cfab93dfa35691afb66ff09f2be39e96b856adee70baa970fab5 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:d47b0b67109940b264cff6995941aa56c0517562b4939b85d6ac3ed750bf59f1 - name: kind value: task resolver: bundles @@ -249,7 +249,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:929bf55a5e364c957a5f907a5516fb8f8893c389ae5985767de7311736eb904a + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:14b91ad9124b722b44222685013faaf9af8ac5b66030d9abeb1c61da3c118cdd - name: kind value: task resolver: bundles @@ -278,7 +278,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:6c389c2f670975cc0dfdd07dcb33142b1668bbfd46f6af520dd0ab736c56e7e9 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:1f17ef7ab9859d6e2215ef2ed532ebc15e516ba09226b8cae77907a7a8b7cedd - name: kind value: task resolver: bundles @@ -300,7 +300,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:fb1aa363b56f9e9bdb1b30a46ddace9035add63fdfb5e39d01b27ae84cc7e425 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:b8c51079ea1110e1095c229e184e3c340120ba211a63a200e836706f5a35361c - name: kind value: task resolver: bundles @@ -317,7 +317,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:1ef6a3ab9c4ba9e735c6924008714ef2a873597837be9d4d927522d5d733bd07 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.2@sha256:479bd0d9aaa7b377ff5f8ad93168d44807455646f2161688637cb2e4e0b990d9 - name: kind value: task resolver: bundles @@ -347,7 +347,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:cda1e319c81a32356d900b2f78483e072fac29684ad81c73aa2314a7f3a389e0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:4c1a1cd74eecfcd93222903ea28319a8068f2d5c9678e4db14e2c605831ad90c - name: kind value: task resolver: bundles From 681b89518a589b4fe727de32fadcf83184cdde86 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Thu, 5 Sep 2024 11:26:14 +0800 Subject: [PATCH 22/67] list resources with their event data type (#185) Signed-off-by: Wei Liu --- cmd/maestro/server/grpc_broker.go | 2 +- pkg/dao/mocks/resource.go | 14 +++++++++ pkg/dao/resource.go | 10 ++++++ pkg/services/resource.go | 13 +++++++- pkg/services/resource_test.go | 52 ++++++++++++++++++++++++++++--- 5 files changed, 85 insertions(+), 6 deletions(-) diff --git a/cmd/maestro/server/grpc_broker.go b/cmd/maestro/server/grpc_broker.go index 3b9b232e..3707e087 100644 --- a/cmd/maestro/server/grpc_broker.go +++ b/cmd/maestro/server/grpc_broker.go @@ -336,7 +336,7 @@ func (bkr *GRPCBroker) respondResyncSpecRequest(ctx context.Context, eventDataTy } clusterName := fmt.Sprintf("%s", clusterNameValue) - objs, err := bkr.resourceService.List(types.ListOptions{ClusterName: clusterName}) + objs, err := bkr.resourceService.List(types.ListOptions{ClusterName: clusterName, CloudEventsDataType: eventDataType}) if err != nil { return err } diff --git a/pkg/dao/mocks/resource.go b/pkg/dao/mocks/resource.go index f75bd07d..d6d998e0 100755 --- a/pkg/dao/mocks/resource.go +++ b/pkg/dao/mocks/resource.go @@ -57,6 +57,20 @@ func (d *resourceDaoMock) FindByConsumerName(ctx context.Context, consumerID str return resources, nil } +func (d *resourceDaoMock) FindByConsumerNameAndResourceType(ctx context.Context, consumerName string, resourceType api.ResourceType) (api.ResourceList, error) { + var resources api.ResourceList + for _, resource := range d.resources { + if resource.ConsumerName != consumerName { + continue + } + if resource.Type != resourceType { + continue + } + resources = append(resources, resource) + } + return resources, nil +} + func (d *resourceDaoMock) FindBySource(ctx context.Context, source string) (api.ResourceList, error) { var resources api.ResourceList for _, resource := range d.resources { diff --git a/pkg/dao/resource.go b/pkg/dao/resource.go index 2ef1333e..0dd3dc21 100755 --- a/pkg/dao/resource.go +++ b/pkg/dao/resource.go @@ -17,6 +17,7 @@ type ResourceDao interface { FindByIDs(ctx context.Context, ids []string) (api.ResourceList, error) FindBySource(ctx context.Context, source string) (api.ResourceList, error) FindByConsumerName(ctx context.Context, consumerName string) (api.ResourceList, error) + FindByConsumerNameAndResourceType(ctx context.Context, consumerName string, resourceType api.ResourceType) (api.ResourceList, error) All(ctx context.Context) (api.ResourceList, error) FirstByConsumerName(ctx context.Context, name string, unscoped bool) (api.Resource, error) } @@ -98,6 +99,15 @@ func (d *sqlResourceDao) FindByConsumerName(ctx context.Context, consumerName st return resources, nil } +func (d *sqlResourceDao) FindByConsumerNameAndResourceType(ctx context.Context, consumerName string, resourceType api.ResourceType) (api.ResourceList, error) { + g2 := (*d.sessionFactory).New(ctx) + resources := api.ResourceList{} + if err := g2.Unscoped().Where("consumer_name = ? and type = ?", consumerName, resourceType).Find(&resources).Error; err != nil { + return nil, err + } + return resources, nil +} + func (d *sqlResourceDao) All(ctx context.Context) (api.ResourceList, error) { g2 := (*d.sessionFactory).New(ctx) resources := api.ResourceList{} diff --git a/pkg/services/resource.go b/pkg/services/resource.go index 63295c35..68d3d6dc 100755 --- a/pkg/services/resource.go +++ b/pkg/services/resource.go @@ -13,6 +13,7 @@ import ( cegeneric "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" + "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/errors" @@ -287,7 +288,17 @@ var _ cegeneric.Lister[*api.Resource] = &sqlResourceService{} // For more details, refer to the cegeneric.Lister interface: // https://github.com/open-cluster-management-io/sdk-go/blob/d3c47c228d7905ebb20f331f9b72bc5ff6a84789/pkg/cloudevents/generic/interface.go#L36-L39 func (s *sqlResourceService) List(listOpts cetypes.ListOptions) ([]*api.Resource, error) { - resourceList, err := s.resourceDao.FindByConsumerName(context.TODO(), listOpts.ClusterName) + var resourceType api.ResourceType + resourceEventDataType := listOpts.CloudEventsDataType + switch resourceEventDataType { + case payload.ManifestEventDataType: + resourceType = api.ResourceTypeSingle + case payload.ManifestBundleEventDataType: + resourceType = api.ResourceTypeBundle + default: + return nil, fmt.Errorf("unsupported resource event data type %v", resourceEventDataType) + } + resourceList, err := s.resourceDao.FindByConsumerNameAndResourceType(context.TODO(), listOpts.ClusterName, resourceType) if err != nil { return nil, err } diff --git a/pkg/services/resource_test.go b/pkg/services/resource_test.go index 69cca6b4..8d82b20f 100755 --- a/pkg/services/resource_test.go +++ b/pkg/services/resource_test.go @@ -5,12 +5,20 @@ import ( "testing" gm "github.com/onsi/gomega" + "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" + "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/dao/mocks" dbmocks "github.com/openshift-online/maestro/pkg/db/mocks" ) +const ( + Fukuisaurus = "b288a9da-8bfe-4c82-94cc-2b48e773fc46" + Seismosaurus = "e3eb7db1-b124-4a4d-8bb6-cc779c01b402" + Breviceratops = "c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4" +) + func TestResourceFindByConsumerID(t *testing.T) { gm.RegisterTestingT(t) @@ -19,10 +27,6 @@ func TestResourceFindByConsumerID(t *testing.T) { resourceService := NewResourceService(dbmocks.NewMockAdvisoryLockFactory(), resourceDAO, events, nil) - const Fukuisaurus = "b288a9da-8bfe-4c82-94cc-2b48e773fc46" - const Seismosaurus = "e3eb7db1-b124-4a4d-8bb6-cc779c01b402" - const Breviceratops = "c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4" - resources := api.ResourceList{ &api.Resource{ConsumerName: Fukuisaurus, Type: api.ResourceTypeSingle, Payload: newPayload(t, "{\"id\":\"75479c10-b537-4261-8058-ca2e36bac384\",\"time\":\"2024-03-07T03:29:03.194843266Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifests.spec.create_request\",\"source\":\"maestro\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}")}, &api.Resource{ConsumerName: Fukuisaurus, Type: api.ResourceTypeBundle, Payload: newPayload(t, "{\"id\":\"266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\",\"time\":\"2024-02-05T17:31:05Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\",\"source\":\"grpc\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"resourceid\":\"c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\",\"clustername\":\"b288a9da-8bfe-4c82-94cc-2b48e773fc46\",\"resourceversion\":1,\"data\":{\"manifests\":[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}},{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}],\"deleteOption\":{\"propagationPolicy\":\"Foreground\"},\"manifestConfigs\":[{\"updateStrategy\":{\"type\":\"ServerSideApply\"},\"resourceIdentifier\":{\"name\":\"nginx\",\"group\":\"apps\",\"resource\":\"deployments\",\"namespace\":\"default\"}}]}}")}, @@ -65,3 +69,43 @@ func TestCreateInvalidResource(t *testing.T) { gm.Expect(err).To(gm.BeNil()) gm.Expect(len(invalidations)).To(gm.Equal(0)) } + +func TestList(t *testing.T) { + gm.RegisterTestingT(t) + + resourceDAO := mocks.NewResourceDao() + events := NewEventService(mocks.NewEventDao()) + + resourceService := NewResourceService(dbmocks.NewMockAdvisoryLockFactory(), resourceDAO, events, nil) + resources := api.ResourceList{ + &api.Resource{ConsumerName: Fukuisaurus, Type: api.ResourceTypeSingle, Payload: newPayload(t, "{\"id\":\"75479c10-b537-4261-8058-ca2e36bac384\",\"time\":\"2024-03-07T03:29:03.194843266Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifests.spec.create_request\",\"source\":\"maestro\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}")}, + &api.Resource{ConsumerName: Fukuisaurus, Type: api.ResourceTypeSingle, Payload: newPayload(t, "{\"id\":\"75479c10-b537-4261-8058-ca2e36bac384\",\"time\":\"2024-03-07T03:29:03.194843266Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifests.spec.create_request\",\"source\":\"maestro\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}")}, + &api.Resource{ConsumerName: Fukuisaurus, Type: api.ResourceTypeBundle, Payload: newPayload(t, "{\"id\":\"266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\",\"time\":\"2024-02-05T17:31:05Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\",\"source\":\"grpc\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"resourceid\":\"c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\",\"clustername\":\"b288a9da-8bfe-4c82-94cc-2b48e773fc46\",\"resourceversion\":1,\"data\":{\"manifests\":[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}},{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}],\"deleteOption\":{\"propagationPolicy\":\"Foreground\"},\"manifestConfigs\":[{\"updateStrategy\":{\"type\":\"ServerSideApply\"},\"resourceIdentifier\":{\"name\":\"nginx\",\"group\":\"apps\",\"resource\":\"deployments\",\"namespace\":\"default\"}}]}}")}, + &api.Resource{ConsumerName: Seismosaurus, Type: api.ResourceTypeSingle, Payload: newPayload(t, "{\"id\":\"75479c10-b537-4261-8058-ca2e36bac384\",\"time\":\"2024-03-07T03:29:03.194843266Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifests.spec.create_request\",\"source\":\"maestro\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}")}, + } + for _, resource := range resources { + _, err := resourceService.Create(context.Background(), resource) + gm.Expect(err).To(gm.BeNil()) + } + + resoruces, err := resourceService.List(types.ListOptions{ + ClusterName: Fukuisaurus, + CloudEventsDataType: payload.ManifestEventDataType, + }) + gm.Expect(err).To(gm.BeNil()) + gm.Expect(len(resoruces)).To(gm.Equal(2)) + + resoruces, err = resourceService.List(types.ListOptions{ + ClusterName: Fukuisaurus, + CloudEventsDataType: payload.ManifestBundleEventDataType, + }) + gm.Expect(err).To(gm.BeNil()) + gm.Expect(len(resoruces)).To(gm.Equal(1)) + + resoruces, err = resourceService.List(types.ListOptions{ + ClusterName: Seismosaurus, + CloudEventsDataType: payload.ManifestEventDataType, + }) + gm.Expect(err).To(gm.BeNil()) + gm.Expect(len(resoruces)).To(gm.Equal(1)) +} From 908246a991c7c512603d7a0111cc4432827749be Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Thu, 5 Sep 2024 14:56:25 +0800 Subject: [PATCH 23/67] support grpc auth for grpc server. (#168) * support grpc auth. Signed-off-by: morvencao * address comments. Signed-off-by: morvencao --------- Signed-off-by: morvencao --- cmd/maestro/environments/framework.go | 29 ++++ cmd/maestro/environments/types.go | 2 + cmd/maestro/server/api_server.go | 3 +- cmd/maestro/server/auth_interceptor.go | 172 +++++++++++++++++++ cmd/maestro/server/grpc_broker.go | 27 +-- cmd/maestro/server/grpc_server.go | 104 +++++++++-- docs/grpc.md | 132 ++++++++++++-- go.mod | 2 +- pkg/client/grpcauthorizer/interface.go | 32 ++++ pkg/client/grpcauthorizer/kube_authorizer.go | 86 ++++++++++ pkg/client/grpcauthorizer/mock_authorizer.go | 23 +++ pkg/config/grpc_server.go | 10 +- templates/service-template.yml | 31 ++++ test/e2e/pkg/grpc_test.go | 18 +- test/e2e/pkg/suite_test.go | 54 ++++-- test/e2e/setup/e2e_setup.sh | 74 ++++++-- test/factories.go | 90 ++++++++++ test/helper.go | 1 + 18 files changed, 789 insertions(+), 101 deletions(-) create mode 100644 cmd/maestro/server/auth_interceptor.go create mode 100644 pkg/client/grpcauthorizer/interface.go create mode 100644 pkg/client/grpcauthorizer/kube_authorizer.go create mode 100644 pkg/client/grpcauthorizer/mock_authorizer.go diff --git a/cmd/maestro/environments/framework.go b/cmd/maestro/environments/framework.go index 8ee757ab..110c2d6d 100755 --- a/cmd/maestro/environments/framework.go +++ b/cmd/maestro/environments/framework.go @@ -8,10 +8,14 @@ import ( "github.com/getsentry/sentry-go" "github.com/golang/glog" "github.com/openshift-online/maestro/pkg/client/cloudevents" + "github.com/openshift-online/maestro/pkg/client/grpcauthorizer" "github.com/openshift-online/maestro/pkg/client/ocm" "github.com/openshift-online/maestro/pkg/config" "github.com/openshift-online/maestro/pkg/errors" "github.com/spf13/pflag" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" ) @@ -196,6 +200,31 @@ func (e *Env) LoadClients() error { } } + // Create GRPC authorizer based on configuration + if e.Config.GRPCServer.EnableGRPCServer { + if e.Config.GRPCServer.GRPCAuthNType == "mock" { + glog.Infof("Using Mock GRPC Authorizer") + e.Clients.GRPCAuthorizer = grpcauthorizer.NewMockGRPCAuthorizer() + } else { + kubeConfig, err := clientcmd.BuildConfigFromFlags("", e.Config.GRPCServer.GRPCAuthorizerConfig) + if err != nil { + glog.Warningf("Unable to create kube client config: %s", err.Error()) + // fallback to in-cluster config + kubeConfig, err = rest.InClusterConfig() + if err != nil { + glog.Errorf("Unable to create kube client config: %s", err.Error()) + return err + } + } + kubeClient, err := kubernetes.NewForConfig(kubeConfig) + if err != nil { + glog.Errorf("Unable to create kube client: %s", err.Error()) + return err + } + e.Clients.GRPCAuthorizer = grpcauthorizer.NewKubeGRPCAuthorizer(kubeClient) + } + } + return nil } diff --git a/cmd/maestro/environments/types.go b/cmd/maestro/environments/types.go index 52b54a6c..53fbf2ce 100755 --- a/cmd/maestro/environments/types.go +++ b/cmd/maestro/environments/types.go @@ -5,6 +5,7 @@ import ( "github.com/openshift-online/maestro/pkg/auth" "github.com/openshift-online/maestro/pkg/client/cloudevents" + "github.com/openshift-online/maestro/pkg/client/grpcauthorizer" "github.com/openshift-online/maestro/pkg/client/ocm" "github.com/openshift-online/maestro/pkg/config" "github.com/openshift-online/maestro/pkg/db" @@ -57,6 +58,7 @@ type Services struct { type Clients struct { OCM *ocm.Client + GRPCAuthorizer grpcauthorizer.GRPCAuthorizer CloudEventsSource cloudevents.SourceClient } diff --git a/cmd/maestro/server/api_server.go b/cmd/maestro/server/api_server.go index 023dee55..ddc43044 100755 --- a/cmd/maestro/server/api_server.go +++ b/cmd/maestro/server/api_server.go @@ -124,9 +124,8 @@ func NewAPIServer(eventBroadcaster *event.EventBroadcaster) Server { Handler: mainHandler, } - // TODO: support authn and authz for gRPC if env().Config.GRPCServer.EnableGRPCServer { - s.grpcServer = NewGRPCServer(env().Services.Resources(), eventBroadcaster, *env().Config.GRPCServer) + s.grpcServer = NewGRPCServer(env().Services.Resources(), eventBroadcaster, *env().Config.GRPCServer, env().Clients.GRPCAuthorizer) } return s } diff --git a/cmd/maestro/server/auth_interceptor.go b/cmd/maestro/server/auth_interceptor.go new file mode 100644 index 00000000..892f9e05 --- /dev/null +++ b/cmd/maestro/server/auth_interceptor.go @@ -0,0 +1,172 @@ +package server + +import ( + "context" + "fmt" + "strings" + + "github.com/golang/glog" + "github.com/openshift-online/maestro/pkg/client/grpcauthorizer" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/status" +) + +// Context key type defined to avoid collisions in other pkgs using context +// See https://golang.org/pkg/context/#WithValue +type contextKey string + +const ( + contextUserKey contextKey = "user" + contextGroupsKey contextKey = "groups" +) + +func newContextWithIdentity(ctx context.Context, user string, groups []string) context.Context { + ctx = context.WithValue(ctx, contextUserKey, user) + return context.WithValue(ctx, contextGroupsKey, groups) +} + +// identityFromCertificate retrieves the user and groups from the client certificate if they are present. +func identityFromCertificate(ctx context.Context) (string, []string, error) { + p, ok := peer.FromContext(ctx) + if !ok { + return "", nil, status.Error(codes.Unauthenticated, "no peer found") + } + + tlsAuth, ok := p.AuthInfo.(credentials.TLSInfo) + if !ok { + return "", nil, status.Error(codes.Unauthenticated, "unexpected peer transport credentials") + } + + if len(tlsAuth.State.VerifiedChains) == 0 || len(tlsAuth.State.VerifiedChains[0]) == 0 { + return "", nil, status.Error(codes.Unauthenticated, "could not verify peer certificate") + } + + if tlsAuth.State.VerifiedChains[0][0] == nil { + return "", nil, status.Error(codes.Unauthenticated, "could not verify peer certificate") + } + + user := tlsAuth.State.VerifiedChains[0][0].Subject.CommonName + groups := tlsAuth.State.VerifiedChains[0][0].Subject.Organization + + if user == "" { + return "", nil, status.Error(codes.Unauthenticated, "could not find user in peer certificate") + } + + if len(groups) == 0 { + return "", nil, status.Error(codes.Unauthenticated, "could not find group in peer certificate") + } + + return user, groups, nil +} + +// identityFromToken retrieves the user and groups from the access token if they are present. +func identityFromToken(ctx context.Context, grpcAuthorizer grpcauthorizer.GRPCAuthorizer) (string, []string, error) { + // Extract the metadata from the context + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return "", nil, status.Error(codes.InvalidArgument, "missing metadata") + } + + // Extract the access token from the metadata + authorization, ok := md["authorization"] + if !ok || len(authorization) == 0 { + return "", nil, status.Error(codes.Unauthenticated, "invalid token") + } + + token := strings.TrimPrefix(authorization[0], "Bearer ") + // Extract the user and groups from the access token + return grpcAuthorizer.TokenReview(ctx, token) +} + +// newAuthUnaryInterceptor creates a unary interceptor that retrieves the user and groups +// based on the specified authentication type. It supports retrieving from either the access +// token or the client certificate depending on the provided authNType. +// The interceptor then adds the retrieved identity information (user and groups) to the +// context and invokes the provided handler. +func newAuthUnaryInterceptor(authNType string, authorizer grpcauthorizer.GRPCAuthorizer) grpc.UnaryServerInterceptor { + return func( + ctx context.Context, + req interface{}, + info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, + ) (interface{}, error) { + var user string + var groups []string + var err error + switch authNType { + case "token": + user, groups, err = identityFromToken(ctx, authorizer) + if err != nil { + glog.Errorf("unable to get user and groups from token: %v", err) + return nil, err + } + case "mtls": + user, groups, err = identityFromCertificate(ctx) + if err != nil { + glog.Errorf("unable to get user and groups from certificate: %v", err) + return nil, err + } + default: + return nil, fmt.Errorf("unsupported authentication type %s", authNType) + } + + // call the handler with the new context containing the user and groups + return handler(newContextWithIdentity(ctx, user, groups), req) + } +} + +// wrappedStream wraps a grpc.ServerStream associated with an incoming RPC, and +// a custom context containing the user and groups derived from the client certificate +// specified in the incoming RPC metadata +type wrappedStream struct { + grpc.ServerStream + ctx context.Context +} + +func (w *wrappedStream) Context() context.Context { + return w.ctx +} + +func newWrappedStream(ctx context.Context, s grpc.ServerStream) grpc.ServerStream { + return &wrappedStream{s, ctx} +} + +// newAuthStreamInterceptor creates a stream interceptor that retrieves the user and groups +// based on the specified authentication type. It supports retrieving from either the access +// token or the client certificate depending on the provided authNType. +// The interceptor then adds the retrieved identity information (user and groups) to the +// context and invokes the provided handler. +func newAuthStreamInterceptor(authNType string, authorizer grpcauthorizer.GRPCAuthorizer) grpc.StreamServerInterceptor { + return func( + srv interface{}, + ss grpc.ServerStream, + info *grpc.StreamServerInfo, + handler grpc.StreamHandler, + ) error { + var user string + var groups []string + var err error + switch authNType { + case "token": + user, groups, err = identityFromToken(ss.Context(), authorizer) + if err != nil { + glog.Errorf("unable to get user and groups from token: %v", err) + return err + } + case "mtls": + user, groups, err = identityFromCertificate(ss.Context()) + if err != nil { + glog.Errorf("unable to get user and groups from certificate: %v", err) + return err + } + default: + return fmt.Errorf("unsupported authentication Type %s", authNType) + } + + return handler(srv, newWrappedStream(newContextWithIdentity(ss.Context(), user, groups), ss)) + } +} diff --git a/cmd/maestro/server/grpc_broker.go b/cmd/maestro/server/grpc_broker.go index 3707e087..2275691d 100644 --- a/cmd/maestro/server/grpc_broker.go +++ b/cmd/maestro/server/grpc_broker.go @@ -14,7 +14,6 @@ import ( "github.com/golang/glog" "github.com/google/uuid" "google.golang.org/grpc" - "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" "google.golang.org/protobuf/types/known/emptypb" "k8s.io/klog/v2" @@ -74,26 +73,7 @@ func NewGRPCBroker(eventBroadcaster *event.EventBroadcaster) EventServer { MaxConnectionAge: config.MaxConnectionAge, })) - if config.EnableTLS { - // Check tls cert and key path path - if config.TLSCertFile == "" || config.TLSKeyFile == "" { - check( - fmt.Errorf("unspecified required --grpc-tls-cert-file, --grpc-tls-key-file"), - "Can't start gRPC broker", - ) - } - - // Serve with TLS - creds, err := credentials.NewServerTLSFromFile(config.TLSCertFile, config.TLSKeyFile) - if err != nil { - glog.Fatalf("Failed to generate credentials %v", err) - } - grpcServerOptions = append(grpcServerOptions, grpc.Creds(creds)) - glog.Infof("Serving gRPC broker with TLS at %s", config.BrokerBindPort) - } else { - glog.Infof("Serving gRPC broker without TLS at %s", config.BrokerBindPort) - } - + glog.Infof("Serving gRPC broker without TLS at %s", config.BrokerBindPort) sessionFactory := env().Database.SessionFactory return &GRPCBroker{ grpcServer: grpc.NewServer(grpcServerOptions...), @@ -109,14 +89,15 @@ func NewGRPCBroker(eventBroadcaster *event.EventBroadcaster) EventServer { // Start starts the gRPC broker func (bkr *GRPCBroker) Start(ctx context.Context) { + glog.Info("Starting gRPC broker") lis, err := net.Listen("tcp", bkr.bindAddress) if err != nil { - glog.Fatalf("failed to listen: %v", err) + check(fmt.Errorf("failed to listen: %v", err), "Can't start gRPC broker") } pbv1.RegisterCloudEventServiceServer(bkr.grpcServer, bkr) go func() { if err := bkr.grpcServer.Serve(lis); err != nil { - glog.Fatalf("failed to start gRPC broker: %v", err) + check(fmt.Errorf("failed to serve gRPC broker: %v", err), "Can't start gRPC broker") } }() diff --git a/cmd/maestro/server/grpc_server.go b/cmd/maestro/server/grpc_server.go index e58ee348..6b1f7469 100644 --- a/cmd/maestro/server/grpc_server.go +++ b/cmd/maestro/server/grpc_server.go @@ -2,8 +2,11 @@ package server import ( "context" + "crypto/tls" + "crypto/x509" "fmt" "net" + "os" "time" ce "github.com/cloudevents/sdk-go/v2" @@ -26,6 +29,7 @@ import ( "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/client/cloudevents" + "github.com/openshift-online/maestro/pkg/client/grpcauthorizer" "github.com/openshift-online/maestro/pkg/config" "github.com/openshift-online/maestro/pkg/event" "github.com/openshift-online/maestro/pkg/services" @@ -34,14 +38,16 @@ import ( // GRPCServer includes a gRPC server and a resource service type GRPCServer struct { pbv1.UnimplementedCloudEventServiceServer - grpcServer *grpc.Server - eventBroadcaster *event.EventBroadcaster - resourceService services.ResourceService - bindAddress string + grpcServer *grpc.Server + eventBroadcaster *event.EventBroadcaster + resourceService services.ResourceService + disableAuthorizer bool + grpcAuthorizer grpcauthorizer.GRPCAuthorizer + bindAddress string } // NewGRPCServer creates a new GRPCServer -func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *event.EventBroadcaster, config config.GRPCServerConfig) *GRPCServer { +func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *event.EventBroadcaster, config config.GRPCServerConfig, grpcAuthorizer grpcauthorizer.GRPCAuthorizer) *GRPCServer { grpcServerOptions := make([]grpc.ServerOption, 0) grpcServerOptions = append(grpcServerOptions, grpc.MaxRecvMsgSize(config.MaxReceiveMessageSize)) grpcServerOptions = append(grpcServerOptions, grpc.MaxSendMsgSize(config.MaxSendMessageSize)) @@ -53,7 +59,7 @@ func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *e MaxConnectionAge: config.MaxConnectionAge, })) - if config.EnableTLS { + if !config.DisableTLS { // Check tls cert and key path path if config.TLSCertFile == "" || config.TLSKeyFile == "" { check( @@ -63,29 +69,70 @@ func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *e } // Serve with TLS - creds, err := credentials.NewServerTLSFromFile(config.TLSCertFile, config.TLSKeyFile) + serverCerts, err := tls.LoadX509KeyPair(config.TLSCertFile, config.TLSKeyFile) if err != nil { - glog.Fatalf("Failed to generate credentials %v", err) + check(fmt.Errorf("failed to load server certificates: %v", err), "Can't start gRPC server") + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{serverCerts}, + MinVersion: tls.VersionTLS13, + MaxVersion: tls.VersionTLS13, + } + + if config.GRPCAuthNType == "mtls" { + if len(config.ClientCAFile) == 0 { + check(fmt.Errorf("no client CA file specified when using mtls authorization type"), "Can't start gRPC server") + } + + certPool, err := x509.SystemCertPool() + if err != nil { + check(fmt.Errorf("failed to load system cert pool: %v", err), "Can't start gRPC server") + } + + caPEM, err := os.ReadFile(config.ClientCAFile) + if err != nil { + check(fmt.Errorf("failed to read client CA file: %v", err), "Can't start gRPC server") + } + + if ok := certPool.AppendCertsFromPEM(caPEM); !ok { + check(fmt.Errorf("failed to append client CA to cert pool"), "Can't start gRPC server") + } + + tlsConfig.ClientCAs = certPool + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert + + grpcServerOptions = append(grpcServerOptions, grpc.Creds(credentials.NewTLS(tlsConfig)), + grpc.UnaryInterceptor(newAuthUnaryInterceptor(config.GRPCAuthNType, grpcAuthorizer)), + grpc.StreamInterceptor(newAuthStreamInterceptor(config.GRPCAuthNType, grpcAuthorizer))) + glog.Infof("Serving gRPC service with mTLS at %s", config.ServerBindPort) + } else { + grpcServerOptions = append(grpcServerOptions, grpc.Creds(credentials.NewTLS(tlsConfig)), + grpc.UnaryInterceptor(newAuthUnaryInterceptor(config.GRPCAuthNType, grpcAuthorizer)), + grpc.StreamInterceptor(newAuthStreamInterceptor(config.GRPCAuthNType, grpcAuthorizer))) + glog.Infof("Serving gRPC service with TLS at %s", config.ServerBindPort) } - grpcServerOptions = append(grpcServerOptions, grpc.Creds(creds)) - glog.Infof("Serving gRPC service with TLS at %s", config.ServerBindPort) } else { + // Note: Do not use this in production. glog.Infof("Serving gRPC service without TLS at %s", config.ServerBindPort) } return &GRPCServer{ - grpcServer: grpc.NewServer(grpcServerOptions...), - eventBroadcaster: eventBroadcaster, - resourceService: resourceService, - bindAddress: env().Config.HTTPServer.Hostname + ":" + config.ServerBindPort, + grpcServer: grpc.NewServer(grpcServerOptions...), + eventBroadcaster: eventBroadcaster, + resourceService: resourceService, + disableAuthorizer: config.DisableTLS, + grpcAuthorizer: grpcAuthorizer, + bindAddress: env().Config.HTTPServer.Hostname + ":" + config.ServerBindPort, } } // Start starts the gRPC server func (svr *GRPCServer) Start() error { + glog.Info("Starting gRPC server") lis, err := net.Listen("tcp", svr.bindAddress) if err != nil { - glog.Fatalf("failed to listen: %v", err) + glog.Errorf("failed to listen: %v", err) return err } pbv1.RegisterCloudEventServiceServer(svr.grpcServer, svr) @@ -105,6 +152,19 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return nil, fmt.Errorf("failed to convert protobuf to cloudevent: %v", err) } + if !svr.disableAuthorizer { + // check if the event is from the authorized source + user := ctx.Value(contextUserKey).(string) + groups := ctx.Value(contextGroupsKey).([]string) + allowed, err := svr.grpcAuthorizer.AccessReview(ctx, "pub", "source", evt.Source(), user, groups) + if err != nil { + return nil, fmt.Errorf("failed to authorize the request: %v", err) + } + if !allowed { + return nil, fmt.Errorf("unauthorized to publish the event from source %s", evt.Source()) + } + } + eventType, err := types.ParseCloudEventsType(evt.Type()) if err != nil { return nil, fmt.Errorf("failed to parse cloud event type %s, %v", evt.Type(), err) @@ -163,6 +223,20 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) // Subscribe implements the Subscribe method of the CloudEventServiceServer interface func (svr *GRPCServer) Subscribe(subReq *pbv1.SubscriptionRequest, subServer pbv1.CloudEventService_SubscribeServer) error { + if !svr.disableAuthorizer { + // check if the client is authorized to subscribe the event from the source + ctx := subServer.Context() + user := ctx.Value(contextUserKey).(string) + groups := ctx.Value(contextGroupsKey).([]string) + allowed, err := svr.grpcAuthorizer.AccessReview(ctx, "sub", "source", subReq.Source, user, groups) + if err != nil { + return fmt.Errorf("failed to authorize the request: %v", err) + } + if !allowed { + return fmt.Errorf("unauthorized to subscribe the event from source %s", subReq.Source) + } + } + clientID, errChan := svr.eventBroadcaster.Register(subReq.Source, func(res *api.Resource) error { evt, err := encodeResourceStatus(res) if err != nil { diff --git a/docs/grpc.md b/docs/grpc.md index b3d22222..ee6f55f8 100644 --- a/docs/grpc.md +++ b/docs/grpc.md @@ -1,8 +1,101 @@ # gRPC server -gPRC server is disabled by default. You can enable it by passing `--enable-grpc-server=true` to the maestro server start command. +gPRC server is disabled by default. You can enable it by passing `--enable-grpc-server=true` to the maestro server command. + +## Authentication and Authorization + +By default, the gRPC server enable server side TLS. To disable that, set `--disable-grpc-tls=true` to the maestro server command. However, if you need Authentication and Authorization, server side TLS must remain enabled. + +For authorization, the gRPC server uses a mock authorizer by default. To enable real authorization, set `--grpc-authn-type` to either `mtls` or `token`. Depending on the authorizer type, you will need to create authorization rule resources, which are standard Kubernetes RBAC resources. + +1. mTLS-Based Authorization + +For mTLS-based authorization, specify the client CA file using `--grpc-client-ca-file`. The server will validate the client certificate against this CA. + +Then create authorization rules based on the `CN (Common Name)` or `O (Organization)` in the client certificate, representing the user or group. For example, to allow the user "Alice" to publish and subscribe to the `policy` source, use the following Kubernetes RBAC configuration: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: policy-pub-sub +rules: +- nonResourceURLs: + - /sources/policy + verbs: + - pub + - sub +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: policy-pub-sub +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: policy-pub-sub +subjects: +- kind: User + name: Alice + apiGroup: rbac.authorization.k8s.io +``` + +On the gRPC client side, configure the [gRPC options](https://pkg.go.dev/open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc#GRPCOptions) with the client certificate and key files, as follows: + +```golang +grpcOptions = grpcoptions.NewGRPCOptions() +grpcOptions.URL = grpcServerAddr +grpcOptions.CAFile = grpcServerCAFile +grpcOptions.ClientCertFile = grpcClientCertFile +grpcOptions.ClientKeyFile = grpcClientKeyFile +``` + +The `grpcClientCertFile` and `grpcClientKeyFile` should contain the certificate signed by the client CA. For the example above, the CN must be "Alice". + +2. Token-Based Authorization + +For token-based authorization, the gRPC server authenticates the client using a Kubernetes service account token. The service account is supposed created by the gRPC client. + +Create authorization rules based on the service account associated with the token. For example, to allow the service account `open-cluster-management/policy-controller` to publish and subscribe to the `policy` source, use the following Kubernetes RBAC configuration: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: policy-pub-sub +rules: +- nonResourceURLs: + - /sources/policy + verbs: + - pub + - sub +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: policy-pub-sub +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: policy-pub-sub +subjects: +- kind: ServiceAccount + name: policy-controller + namespace: open-cluster-management +``` + +On the gRPC client side, configure the gRPC options with the token file, as follows: -## How to Use +```golang +grpcOptions = grpcoptions.NewGRPCOptions() +grpcOptions.URL = grpcServerAddr +grpcOptions.CAFile = grpcServerCAFile +grpcOptions.TokenFile = grpcClientTokenFile +``` + +The `grpcClientTokenFile` stores the token for the corresponding service account. In the example above, it holds the token for the `open-cluster-management/policy-controller` service account. + +## How to Use gPRC Source Client ### Initliaze the gRPC source client @@ -16,6 +109,12 @@ gPRC server is disabled by default. You can enable it by passing `--enable-grpc- grpcOptions = grpcoptions.NewGRPCOptions() grpcOptions.URL = h.Env().Config.GRPCServer.BindAddress + // set grpc client authentication and authorization configuration + // if gRPC Server enable authentication and authorization. + // grpcOptions.CAFile = grpcServerCAFile + // ClientCertFile = grpcClientCertFile + // ClientKeyFile = grpcClientKeyFile + // grpcOptions.TokenFile = grpcClientTokenFile grpcSourceOption = grpcoptions.NewSourceOptions(grpcOptions, "grpc-source-example") ``` @@ -71,31 +170,31 @@ see the below for an example of the resource: "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { - "name": "nginx", - "namespace": "default" + "name": "nginx", + "namespace": "default" }, "spec": { - "replicas": %d, - "selector": { + "replicas": %d, + "selector": { "matchLabels": { - "app": "nginx" + "app": "nginx" } - }, - "template": { + }, + "template": { "metadata": { - "labels": { + "labels": { "app": "nginx" - } + } }, "spec": { - "containers": [ + "containers": [ { - "image": "nginxinc/nginx-unprivileged", - "name": "nginx" + "image": "nginxinc/nginx-unprivileged", + "name": "nginx" } - ] + ] } - } + } } }`, &testManifest); ``` @@ -111,4 +210,3 @@ To subscribe to the resource status, you need to call the `Subscribe` method of return nil }) ``` - diff --git a/go.mod b/go.mod index c5fc151d..aa9165fb 100755 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/yaacov/tree-search-language v0.0.0-20190923184055-1c2dad2e354b + golang.org/x/oauth2 v0.16.0 google.golang.org/grpc v1.62.1 google.golang.org/protobuf v1.33.0 gopkg.in/resty.v1 v1.12.0 @@ -138,7 +139,6 @@ require ( golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect golang.org/x/net v0.23.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/term v0.19.0 // indirect diff --git a/pkg/client/grpcauthorizer/interface.go b/pkg/client/grpcauthorizer/interface.go new file mode 100644 index 00000000..fa1351f6 --- /dev/null +++ b/pkg/client/grpcauthorizer/interface.go @@ -0,0 +1,32 @@ +package grpcauthorizer + +import "context" + +// GRPCAuthorizer defines an interface for performing access reviews in a gRPC-based authorization. +type GRPCAuthorizer interface { + // TokenReview validates the given token and returns the user and groups associated with it. + // + // Parameters: + // - ctx: The context for managing request lifecycle. + // - token: The token to validate. + // + // Returns: + // - user: The user associated with the token. + // - groups: The groups associated with the token. + // - err: Any error encountered during the review process. + TokenReview(ctx context.Context, token string) (user string, groups []string, err error) + // AccessReview checks if the specified user or groups has permission to perform a given action on a specified resource. + // + // Parameters: + // - ctx: The context for managing request lifecycle. + // - action: The action being requested, e.g., "pub" (publish) or "sub" (subscribe). + // - resourceType: The type of resource, e.g., "source" or "cluster". + // - resource: The specific resource name within the given resource type. + // - user: The user requesting the action (may be empty if groups are used). + // - groups: The groups requesting the action (may be empty if user is used). + // + // Returns: + // - allowed: True if access is granted, false otherwise. + // - err: Any error encountered during the review process. + AccessReview(ctx context.Context, action, resourceType, resource, user string, groups []string) (allowed bool, err error) +} diff --git a/pkg/client/grpcauthorizer/kube_authorizer.go b/pkg/client/grpcauthorizer/kube_authorizer.go new file mode 100644 index 00000000..74441ddb --- /dev/null +++ b/pkg/client/grpcauthorizer/kube_authorizer.go @@ -0,0 +1,86 @@ +package grpcauthorizer + +import ( + "context" + "fmt" + + "github.com/golang/glog" + authenticationv1 "k8s.io/api/authentication/v1" + authorizationv1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// KubeGRPCAuthorizer is a gRPC authorizer that uses the Kubernetes RBAC API to authorize requests. +type KubeGRPCAuthorizer struct { + kubeClient kubernetes.Interface +} + +func NewKubeGRPCAuthorizer(kubeClient kubernetes.Interface) GRPCAuthorizer { + return &KubeGRPCAuthorizer{ + kubeClient: kubeClient, + } +} + +var _ GRPCAuthorizer = &KubeGRPCAuthorizer{} + +// TokenReview validates the given token and returns the user and groups associated with it. +func (k *KubeGRPCAuthorizer) TokenReview(ctx context.Context, token string) (user string, groups []string, err error) { + glog.V(4).Infof("TokenReview: token=%s", token) + + tr, err := k.kubeClient.AuthenticationV1().TokenReviews().Create(ctx, &authenticationv1.TokenReview{ + Spec: authenticationv1.TokenReviewSpec{ + Token: token, + }, + }, metav1.CreateOptions{}) + if err != nil { + return "", nil, err + } + + if tr.Status.Authenticated { + return tr.Status.User.Username, tr.Status.User.Groups, nil + } + + return "", nil, fmt.Errorf("token not authenticated") +} + +// AccessReview checks if the given user or group is allowed to perform the given action on the given resource by making a SubjectAccessReview request. +func (k *KubeGRPCAuthorizer) AccessReview(ctx context.Context, action, resourceType, resource, user string, groups []string) (allowed bool, err error) { + glog.V(4).Infof("AccessReview: action=%s, resourceType=%s, resource=%s, user=%s, groups=%s", action, resourceType, resource, user, groups) + if user != "" && len(groups) == 0 { + return false, fmt.Errorf("both user and groups cannot be specified") + } + + if action != "pub" && action != "sub" { + return false, fmt.Errorf("unsupported action: %s", action) + } + + if resource == "" { + return false, fmt.Errorf("resource cannot be empty") + } + + nonResourceUrl := "" + switch resourceType { + case "source": + nonResourceUrl = fmt.Sprintf("/sources/%s", resource) + default: + return false, fmt.Errorf("unsupported resource type: %s", resourceType) + } + + sar, err := k.kubeClient.AuthorizationV1().SubjectAccessReviews().Create(ctx, &authorizationv1.SubjectAccessReview{ + Spec: authorizationv1.SubjectAccessReviewSpec{ + NonResourceAttributes: &authorizationv1.NonResourceAttributes{ + Path: nonResourceUrl, + Verb: action, + }, + User: user, + Groups: groups, + }, + }, metav1.CreateOptions{}) + + if err != nil { + return false, err + } + + return sar.Status.Allowed, nil +} diff --git a/pkg/client/grpcauthorizer/mock_authorizer.go b/pkg/client/grpcauthorizer/mock_authorizer.go new file mode 100644 index 00000000..2e52c1e2 --- /dev/null +++ b/pkg/client/grpcauthorizer/mock_authorizer.go @@ -0,0 +1,23 @@ +package grpcauthorizer + +import "context" + +// MockGRPCAuthorizer returns allowed=true for every request +type MockGRPCAuthorizer struct { +} + +func NewMockGRPCAuthorizer() GRPCAuthorizer { + return &MockGRPCAuthorizer{} +} + +var _ GRPCAuthorizer = &MockGRPCAuthorizer{} + +// TokenReview returns an empty user and groups +func (m *MockGRPCAuthorizer) TokenReview(ctx context.Context, token string) (user string, groups []string, err error) { + return "", []string{}, nil +} + +// SelfAccessReview returns allowed=true for every request +func (m *MockGRPCAuthorizer) AccessReview(ctx context.Context, action, resourceType, resource, user string, groups []string) (allowed bool, err error) { + return true, nil +} diff --git a/pkg/config/grpc_server.go b/pkg/config/grpc_server.go index 592bbd94..cdbb5eb7 100755 --- a/pkg/config/grpc_server.go +++ b/pkg/config/grpc_server.go @@ -9,9 +9,12 @@ import ( type GRPCServerConfig struct { EnableGRPCServer bool `json:"enable_grpc_server"` + DisableTLS bool `json:"disable_grpc_tls"` TLSCertFile string `json:"grpc_tls_cert_file"` TLSKeyFile string `json:"grpc_tls_key_file"` - EnableTLS bool `json:"enable_grpc_tls"` + GRPCAuthNType string `json:"grpc_authn_type"` + GRPCAuthorizerConfig string `json:"grpc_authorizer_config"` + ClientCAFile string `json:"grpc_client_ca_file"` ServerBindPort string `json:"server_bind_port"` BrokerBindPort string `json:"broker_bind_port"` MaxConcurrentStreams uint32 `json:"max_concurrent_steams"` @@ -38,7 +41,10 @@ func (s *GRPCServerConfig) AddFlags(fs *pflag.FlagSet) { fs.DurationVar(&s.MaxConnectionAge, "grpc-max-connection-age", time.Duration(math.MaxInt64), "A duration for the maximum amount of time connection may exist before closing") fs.IntVar(&s.WriteBufferSize, "grpc-write-buffer-size", 32*1024, "gPRC write buffer size") fs.IntVar(&s.ReadBufferSize, "grpc-read-buffer-size", 32*1024, "gPRC read buffer size") + fs.BoolVar(&s.DisableTLS, "disable-grpc-tls", false, "Disable TLS for gRPC server, default is false") fs.StringVar(&s.TLSCertFile, "grpc-tls-cert-file", "", "The path to the tls.crt file") fs.StringVar(&s.TLSKeyFile, "grpc-tls-key-file", "", "The path to the tls.key file") - fs.BoolVar(&s.EnableTLS, "enable-grpc-tls", false, "Enable TLS for gRPC server") + fs.StringVar(&s.GRPCAuthNType, "grpc-authn-type", "mock", "Specify the gRPC authentication type (e.g., mock, mtls or token)") + fs.StringVar(&s.GRPCAuthorizerConfig, "grpc-authorizer-config", "", "Path to the gRPC authorizer configuration file") + fs.StringVar(&s.ClientCAFile, "grpc-client-ca-file", "", "The path to the client ca file, must specify if using mtls authentication type") } diff --git a/templates/service-template.yml b/templates/service-template.yml index 08abd0f9..2ae608ca 100755 --- a/templates/service-template.yml +++ b/templates/service-template.yml @@ -119,6 +119,11 @@ parameters: description: Message driver type, mqtt or grpc. value: mqtt +- name: DISABLE_GRPC_TLS + displayName: Disable gRPC TLS + description: Disable TLS for gRPC server + value: "false" + - name: METRICS_SERVER_BINDPORT displayName: Metrics Server Bindport description: Metrics server bind port @@ -209,6 +214,31 @@ objects: labels: app: maestro + - apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: maestro + rules: + - apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: ["create"] + - apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + + - apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: maestro + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: maestro + subjects: + - kind: ServiceAccount + name: maestro + namespace: maestro + - kind: Deployment apiVersion: apps/v1 metadata: @@ -311,6 +341,7 @@ objects: - --https-cert-file=/secrets/tls/tls.crt - --https-key-file=/secrets/tls/tls.key - --enable-grpc-server=${ENABLE_GRPC_SERVER} + - --disable-grpc-tls=${DISABLE_GRPC_TLS} - --grpc-tls-cert-file=/secrets/tls/tls.crt - --grpc-tls-key-file=/secrets/tls/tls.key - --acl-file=/configs/authentication/acl.yml diff --git a/test/e2e/pkg/grpc_test.go b/test/e2e/pkg/grpc_test.go index 8d5c6386..5670c3a4 100644 --- a/test/e2e/pkg/grpc_test.go +++ b/test/e2e/pkg/grpc_test.go @@ -27,7 +27,6 @@ import ( var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { Context("GRPC Manifest Tests", func() { - source := "grpc-e2e" deployName := fmt.Sprintf("nginx-%s", rand.String(5)) resourceID := uuid.NewString() resourceStatus := &api.ResourceStatus{ @@ -36,7 +35,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("subscribe to resource status with grpc client", func() { go func() { - subClient, err := grpcClient.Subscribe(ctx, &pbv1.SubscriptionRequest{Source: source}) + subClient, err := grpcClient.Subscribe(ctx, &pbv1.SubscriptionRequest{Source: sourceID}) if err != nil { return } @@ -96,7 +95,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec using grpc client", func() { - evt := helper.NewEvent(source, "create_request", consumer.Name, resourceID, deployName, 1, 1) + evt := helper.NewEvent(sourceID, "create_request", consumer.Name, resourceID, deployName, 1, 1) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -153,7 +152,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec with update request using grpc client", func() { - evt := helper.NewEvent(source, "update_request", consumer.Name, resourceID, deployName, 1, 2) + evt := helper.NewEvent(sourceID, "update_request", consumer.Name, resourceID, deployName, 1, 2) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -210,7 +209,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec with delete request using grpc client", func() { - evt := helper.NewEvent(source, "delete_request", consumer.Name, resourceID, deployName, 2, 2) + evt := helper.NewEvent(sourceID, "delete_request", consumer.Name, resourceID, deployName, 2, 2) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -253,7 +252,6 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) Context("GRPC Manifest Bundle Tests", func() { - source := "grpc-e2e" deployName := fmt.Sprintf("nginx-%s", rand.String(5)) resourceID := uuid.NewString() resourceBundleStatus := &api.ResourceBundleStatus{ @@ -262,7 +260,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("subscribe to resource bundle status with grpc client", func() { go func() { - subClient, err := grpcClient.Subscribe(ctx, &pbv1.SubscriptionRequest{Source: source}) + subClient, err := grpcClient.Subscribe(ctx, &pbv1.SubscriptionRequest{Source: sourceID}) if err != nil { return } @@ -304,7 +302,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec using grpc client", func() { - evt := helper.NewBundleEvent(source, "create_request", consumer.Name, resourceID, deployName, 1, 1) + evt := helper.NewBundleEvent(sourceID, "create_request", consumer.Name, resourceID, deployName, 1, 1) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -376,7 +374,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec with update request using grpc client", func() { - evt := helper.NewBundleEvent(source, "update_request", consumer.Name, resourceID, deployName, 1, 2) + evt := helper.NewBundleEvent(sourceID, "update_request", consumer.Name, resourceID, deployName, 1, 2) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -448,7 +446,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec with delete request using grpc client", func() { - evt := helper.NewBundleEvent(source, "delete_request", consumer.Name, resourceID, deployName, 2, 2) + evt := helper.NewBundleEvent(sourceID, "delete_request", consumer.Name, resourceID, deployName, 2, 2) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") diff --git a/test/e2e/pkg/suite_test.go b/test/e2e/pkg/suite_test.go index 39cf809c..3792bbee 100644 --- a/test/e2e/pkg/suite_test.go +++ b/test/e2e/pkg/suite_test.go @@ -8,13 +8,14 @@ import ( "fmt" "log" "net/http" + "os" "testing" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" - matav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" @@ -23,7 +24,6 @@ import ( grpcoptions "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc" "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" pbv1 "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protobuf/v1" "github.com/openshift-online/maestro/pkg/api/openapi" @@ -44,6 +44,7 @@ var ( helper *test.Helper cancel context.CancelFunc ctx context.Context + grpcCertDir string ) func TestE2E(t *testing.T) { @@ -86,16 +87,41 @@ var _ = BeforeSuite(func() { } apiClient = openapi.NewAPIClient(cfg) - var err error - grpcConn, err = grpc.Dial(grpcServerAddress, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - log.Fatalf("fail to dial grpc server: %v", err) - } - grpcClient = pbv1.NewCloudEventServiceClient(grpcConn) + grpcCertDir, err := os.MkdirTemp("/tmp", "maestro-grpc-certs-") + Expect(err).To(Succeed()) + + // validate the consumer kubeconfig and name + restConfig, err := clientcmd.BuildConfigFromFlags("", consumer.KubeConfig) + Expect(err).To(Succeed()) + consumer.ClientSet, err = kubernetes.NewForConfig(restConfig) + Expect(err).To(Succeed()) + Expect(consumer.Name).NotTo(BeEmpty(), "consumer name is not provided") + + grpcCertSrt, err := consumer.ClientSet.CoreV1().Secrets("maestro").Get(ctx, "maestro-grpc-cert", metav1.GetOptions{}) + Expect(err).To(Succeed()) + grpcServerCAFile := fmt.Sprintf("%s/ca.crt", grpcCertDir) + grpcClientCert := fmt.Sprintf("%s/client.crt", grpcCertDir) + grpcClientKey := fmt.Sprintf("%s/client.key", grpcCertDir) + Expect(os.WriteFile(grpcServerCAFile, grpcCertSrt.Data["ca.crt"], 0644)).To(Succeed()) + Expect(os.WriteFile(grpcClientCert, grpcCertSrt.Data["client.crt"], 0644)).To(Succeed()) + Expect(os.WriteFile(grpcClientKey, grpcCertSrt.Data["client.key"], 0644)).To(Succeed()) + + grpcClientTokenSrt, err := consumer.ClientSet.CoreV1().Secrets("maestro").Get(ctx, "grpc-client-token", metav1.GetOptions{}) + Expect(err).To(Succeed()) + grpcClientTokenFile := fmt.Sprintf("%s/token", grpcCertDir) + Expect(os.WriteFile(grpcClientTokenFile, grpcClientTokenSrt.Data["token"], 0644)).To(Succeed()) - sourceID = "sourceclient-test" + rand.String(5) grpcOptions = grpcoptions.NewGRPCOptions() grpcOptions.URL = grpcServerAddress + grpcOptions.CAFile = grpcServerCAFile + grpcOptions.TokenFile = grpcClientTokenFile + sourceID = "sourceclient-test" + rand.String(5) + + // create the clusterrole for grpc authz + Expect(helper.CreateGRPCAuthRule(ctx, consumer.ClientSet, "grpc-pub-sub", "source", sourceID, []string{"pub", "sub"})).To(Succeed()) + grpcConn, err = helper.CreateGRPCConn(grpcServerAddress, grpcServerCAFile, grpcClientTokenFile) + Expect(err).To(Succeed()) + grpcClient = pbv1.NewCloudEventServiceClient(grpcConn) workClient, err = grpcsource.NewMaestroGRPCSourceWorkClient( ctx, @@ -104,19 +130,13 @@ var _ = BeforeSuite(func() { sourceID, ) Expect(err).ShouldNot(HaveOccurred()) - - // validate the consumer kubeconfig and name - restConfig, err := clientcmd.BuildConfigFromFlags("", consumer.KubeConfig) - Expect(err).To(Succeed()) - consumer.ClientSet, err = kubernetes.NewForConfig(restConfig) - Expect(err).To(Succeed()) - Expect(consumer.Name).NotTo(BeEmpty(), "consumer name is not provided") }) var _ = AfterSuite(func() { // dump debug info dumpDebugInfo() grpcConn.Close() + os.RemoveAll(grpcCertDir) cancel() }) @@ -135,7 +155,7 @@ func dumpDebugInfo() { func dumpPodLogs(ctx context.Context, kubeClient kubernetes.Interface, podSelector, podNamespace string) error { // get pods from podSelector - pods, err := kubeClient.CoreV1().Pods(podNamespace).List(ctx, matav1.ListOptions{LabelSelector: podSelector}) + pods, err := kubeClient.CoreV1().Pods(podNamespace).List(ctx, metav1.ListOptions{LabelSelector: podSelector}) if err != nil { return fmt.Errorf("failed to list pods with pod selector (%s): %v", podSelector, err) } diff --git a/test/e2e/setup/e2e_setup.sh b/test/e2e/setup/e2e_setup.sh index 2c7a9d00..bd966061 100755 --- a/test/e2e/setup/e2e_setup.sh +++ b/test/e2e/setup/e2e_setup.sh @@ -88,7 +88,6 @@ apiVersion: v1 kind: Service metadata: name: maestro-mqtt-server - namespace: maestro spec: ports: - name: mosquitto @@ -103,7 +102,6 @@ apiVersion: v1 kind: Service metadata: name: maestro-mqtt-agent - namespace: maestro spec: ports: - name: mosquitto @@ -122,11 +120,11 @@ kubectl patch service maestro -n $namespace -p '{"spec":{"type":"NodePort", "por kubectl patch service maestro-grpc -n $namespace -p '{"spec":{"type":"NodePort", "ports": [{"nodePort": 30090, "port": 8090, "targetPort": 8090}]}}' --type merge # 5. create a self-signed certificate for mqtt -certDir=$(mktemp -d) -step certificate create "maestro-mqtt-ca" ${certDir}/ca.crt ${certDir}/ca.key --profile root-ca --no-password --insecure -step certificate create "maestro-mqtt-broker" ${certDir}/server.crt ${certDir}/server.key -san maestro-mqtt -san maestro-mqtt.maestro -san maestro-mqtt-server -san maestro-mqtt-server.maestro -san maestro-mqtt-agent -san maestro-mqtt-agent.maestro --profile leaf --ca ${certDir}/ca.crt --ca-key ${certDir}/ca.key --no-password --insecure -step certificate create "maestro-server-client" ${certDir}/server-client.crt ${certDir}/server-client.key --profile leaf --ca ${certDir}/ca.crt --ca-key ${certDir}/ca.key --no-password --insecure -step certificate create "maestro-agent-client" ${certDir}/agent-client.crt ${certDir}/agent-client.key --profile leaf --ca ${certDir}/ca.crt --ca-key ${certDir}/ca.key --no-password --insecure +mqttCertDir=$(mktemp -d) +step certificate create "maestro-mqtt-ca" ${mqttCertDir}/ca.crt ${mqttCertDir}/ca.key --profile root-ca --no-password --insecure +step certificate create "maestro-mqtt-broker" ${mqttCertDir}/server.crt ${mqttCertDir}/server.key -san maestro-mqtt -san maestro-mqtt.maestro -san maestro-mqtt-server -san maestro-mqtt-server.maestro -san maestro-mqtt-agent -san maestro-mqtt-agent.maestro --profile leaf --ca ${mqttCertDir}/ca.crt --ca-key ${mqttCertDir}/ca.key --no-password --insecure +step certificate create "maestro-server-client" ${mqttCertDir}/server-client.crt ${mqttCertDir}/server-client.key --profile leaf --ca ${mqttCertDir}/ca.crt --ca-key ${mqttCertDir}/ca.key --no-password --insecure +step certificate create "maestro-agent-client" ${mqttCertDir}/agent-client.crt ${mqttCertDir}/agent-client.key --profile leaf --ca ${mqttCertDir}/ca.crt --ca-key ${mqttCertDir}/ca.key --no-password --insecure # apply the mosquitto configmap cat << EOF | kubectl -n $namespace apply -f - @@ -147,13 +145,61 @@ data: EOF # create secret containing the mqtt certs and patch the maestro-mqtt deployment -kubectl create secret generic maestro-mqtt-certs -n $namespace --from-file=ca.crt=${certDir}/ca.crt --from-file=server.crt=${certDir}/server.crt --from-file=server.key=${certDir}/server.key +kubectl create secret generic maestro-mqtt-certs -n $namespace --from-file=ca.crt=${mqttCertDir}/ca.crt --from-file=server.crt=${mqttCertDir}/server.crt --from-file=server.key=${mqttCertDir}/server.key kubectl patch deploy/maestro-mqtt -n $namespace --type='json' -p='[{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"mosquitto-certs","secret":{"secretName":"maestro-mqtt-certs"}}},{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"mosquitto-certs","mountPath":"/mosquitto/certs"}}]' kubectl wait deploy/maestro-mqtt -n $namespace --for condition=Available=True --timeout=200s -maestroServerPatch='[{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"mqtt-certs","secret":{"secretName":"maestro-server-certs"}}},{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"mqtt-certs","mountPath":"/secrets/mqtt-certs"}},{"op":"replace","path":"/spec/template/spec/containers/0/livenessProbe/initialDelaySeconds","value":1},{"op":"replace","path":"/spec/template/spec/containers/0/readinessProbe/initialDelaySeconds","value":1}]' +# 6. create a self-signed certificate for maestro grpc +grpcCertDir=$(mktemp -d) +step certificate create "maestro-grpc-ca" ${grpcCertDir}/ca.crt ${grpcCertDir}/ca.key --profile root-ca --no-password --insecure +step certificate create "maestro-grpc-server" ${grpcCertDir}/server.crt ${grpcCertDir}/server.key -san maestro-grpc -san maestro-grpc.maestro -san localhost -san 127.0.0.1 --profile leaf --ca ${grpcCertDir}/ca.crt --ca-key ${grpcCertDir}/ca.key --no-password --insecure +cat << EOF > ${grpcCertDir}/cert.tpl +{ + "subject":{"organization":"open-cluster-management","commonName":"grpc-client"}, + "keyUsage":["digitalSignature"], + "extKeyUsage": ["serverAuth","clientAuth"] +} +EOF +step certificate create "maestro-grpc-client" ${grpcCertDir}/client.crt ${grpcCertDir}/client.key --template ${grpcCertDir}/cert.tpl --ca ${grpcCertDir}/ca.crt --ca-key ${grpcCertDir}/ca.key --no-password --insecure +kubectl create secret generic maestro-grpc-cert -n $namespace --from-file=ca.crt=${grpcCertDir}/ca.crt --from-file=server.crt=${grpcCertDir}/server.crt --from-file=server.key=${grpcCertDir}/server.key --from-file=client.crt=${grpcCertDir}/client.crt --from-file=client.key=${grpcCertDir}/client.key + +# create the grpc clusterrolebinding for publishing and subscribing +cat << EOF | kubectl -n $namespace apply -f - +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: grpc-pub-sub +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: grpc-pub-sub +subjects: +- kind: User + name: grpc-client + apiGroup: rbac.authorization.k8s.io +- kind: ServiceAccount + name: grpc-client + namespace: $namespace +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: grpc-client +--- +apiVersion: v1 +kind: Secret +metadata: + name: grpc-client-token + annotations: + kubernetes.io/service-account.name: grpc-client +type: kubernetes.io/service-account-token +--- +EOF + +# patch the maestro deployment to mount the grpc certs and mqtt certs +maestroServerPatch='[{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"mqtt-certs","secret":{"secretName":"maestro-server-certs"}}},{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"mqtt-certs","mountPath":"/secrets/mqtt-certs"}},{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"maestro-grpc-cert","secret":{"secretName":"maestro-grpc-cert"}}},{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"maestro-grpc-cert","mountPath":"/secrets/maestro-grpc-cert"}},{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--grpc-client-ca-file=/secrets/maestro-grpc-cert/ca.crt"},{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--grpc-authn-type=token"},{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--grpc-tls-cert-file=/secrets/maestro-grpc-cert/server.crt"},{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--grpc-tls-key-file=/secrets/maestro-grpc-cert/server.key"},{"op":"replace","path":"/spec/template/spec/containers/0/livenessProbe/initialDelaySeconds","value":1},{"op":"replace","path":"/spec/template/spec/containers/0/readinessProbe/initialDelaySeconds","value":1}]' if [ -n "${ENABLE_BROADCAST_SUBSCRIPTION}" ] && [ "${ENABLE_BROADCAST_SUBSCRIPTION}" = "true" ]; then - maestroServerPatch='[{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--subscription-type=broadcast"},{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"mqtt-certs","secret":{"secretName":"maestro-server-certs"}}},{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"mqtt-certs","mountPath":"/secrets/mqtt-certs"}},{"op":"replace","path":"/spec/template/spec/containers/0/livenessProbe/initialDelaySeconds","value":1},{"op":"replace","path":"/spec/template/spec/containers/0/readinessProbe/initialDelaySeconds","value":1}]' + maestroServerPatch='[{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--subscription-type=broadcast"},{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"mqtt-certs","secret":{"secretName":"maestro-server-certs"}}},{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"mqtt-certs","mountPath":"/secrets/mqtt-certs"}},{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"maestro-grpc-cert","secret":{"secretName":"maestro-grpc-cert"}}},{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"maestro-grpc-cert","mountPath":"/secrets/maestro-grpc-cert"}},{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--grpc-client-ca-file=/secrets/maestro-grpc-cert/ca.crt"},{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--grpc-authn-type=token"},{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--grpc-tls-cert-file=/secrets/maestro-grpc-cert/server.crt"},{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--grpc-tls-key-file=/secrets/maestro-grpc-cert/server.key"},{"op":"replace","path":"/spec/template/spec/containers/0/livenessProbe/initialDelaySeconds","value":1},{"op":"replace","path":"/spec/template/spec/containers/0/readinessProbe/initialDelaySeconds","value":1}]' cat << EOF | kubectl -n $namespace apply -f - apiVersion: v1 kind: Secret @@ -188,7 +234,7 @@ EOF fi # create secret containing the client certs to mqtt broker and patch the maestro deployment -kubectl create secret generic maestro-server-certs -n $namespace --from-file=ca.crt=${certDir}/ca.crt --from-file=client.crt=${certDir}/server-client.crt --from-file=client.key=${certDir}/server-client.key +kubectl create secret generic maestro-server-certs -n $namespace --from-file=ca.crt=${mqttCertDir}/ca.crt --from-file=client.crt=${mqttCertDir}/server-client.crt --from-file=client.key=${mqttCertDir}/server-client.key kubectl patch deploy/maestro -n $namespace --type='json' -p=${maestroServerPatch} kubectl wait deploy/maestro -n $namespace --for condition=Available=True --timeout=200s @@ -217,7 +263,7 @@ metadata: name: maestro-agent-mqtt stringData: config.yaml: | - brokerHost: maestro-mqtt-agent.maestro:1883 + brokerHost: maestro-mqtt-agent.${namespace}:1883 caFile: /secrets/mqtt-certs/ca.crt clientCertFile: /secrets/mqtt-certs/client.crt clientKeyFile: /secrets/mqtt-certs/client.key @@ -227,9 +273,9 @@ stringData: EOF # create secret containing the client certs to mqtt broker and patch the maestro-agent deployment -kubectl create secret generic maestro-agent-certs -n ${agent_namespace} --from-file=ca.crt=${certDir}/ca.crt --from-file=client.crt=${certDir}/agent-client.crt --from-file=client.key=${certDir}/agent-client.key +kubectl create secret generic maestro-agent-certs -n ${agent_namespace} --from-file=ca.crt=${mqttCertDir}/ca.crt --from-file=client.crt=${mqttCertDir}/agent-client.crt --from-file=client.key=${mqttCertDir}/agent-client.key kubectl patch deploy/maestro-agent -n ${agent_namespace} --type='json' -p='[{"op":"add","path":"/spec/template/spec/containers/0/command/-","value":"--appliedmanifestwork-eviction-grace-period=30s"},{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"mqtt-certs","secret":{"secretName":"maestro-agent-certs"}}},{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"mqtt-certs","mountPath":"/secrets/mqtt-certs"}}]' kubectl wait deploy/maestro-agent -n ${agent_namespace} --for condition=Available=True --timeout=200s # remove the certs -rm -rf ${certDir} +rm -rf ${mqttCertDir} ${grpcCertDir} diff --git a/test/factories.go b/test/factories.go index bbfd07c3..b1ba8678 100755 --- a/test/factories.go +++ b/test/factories.go @@ -2,18 +2,29 @@ package test import ( "context" + "crypto/tls" + "crypto/x509" "encoding/json" "fmt" + "os" "time" cloudevents "github.com/cloudevents/sdk-go/v2" "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/api/openapi" "github.com/openshift-online/maestro/pkg/db" + "golang.org/x/oauth2" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/oauth" "gorm.io/datatypes" + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/rand" + "k8s.io/client-go/kubernetes" workv1 "open-cluster-management.io/api/work/v1" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" @@ -443,3 +454,82 @@ func (helper *Helper) NewBundleEvent(source, action, consumerName, resourceID, d return &evt } + +func (helper *Helper) CreateGRPCAuthRule(ctx context.Context, kubeClient kubernetes.Interface, ruleName, resourceType, resourceID string, actions []string) error { + // create the cluster rolefor grpc authz + nonResourceUrl := "" + switch resourceType { + case "source": + nonResourceUrl = fmt.Sprintf("/sources/%s", resourceID) + case "cluster": + nonResourceUrl = fmt.Sprintf("/clusters/%s", resourceID) + default: + return fmt.Errorf("unsupported resource type: %s", resourceType) + } + + _, err := kubeClient.RbacV1().ClusterRoles().Create(ctx, &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: ruleName, + }, + Rules: []rbacv1.PolicyRule{ + { + NonResourceURLs: []string{nonResourceUrl}, + Verbs: actions, + }, + }, + }, metav1.CreateOptions{}) + if errors.IsAlreadyExists(err) { + // update the cluster role + _, err = kubeClient.RbacV1().ClusterRoles().Update(ctx, &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: ruleName, + }, + Rules: []rbacv1.PolicyRule{ + { + NonResourceURLs: []string{nonResourceUrl}, + Verbs: actions, + }, + }, + }, metav1.UpdateOptions{}) + if err != nil { + return err + } + } + + return err +} + +func (helper *Helper) CreateGRPCConn(serverAddr, serverCAFile, tokenFile string) (*grpc.ClientConn, error) { + certPool, err := x509.SystemCertPool() + if err != nil { + return nil, err + } + + caPEM, err := os.ReadFile(serverCAFile) + if err != nil { + return nil, err + } + + ok := certPool.AppendCertsFromPEM(caPEM) + if !ok { + return nil, fmt.Errorf("failed to append server CA certificate") + } + + tlsConfig := &tls.Config{ + RootCAs: certPool, + MinVersion: tls.VersionTLS13, + MaxVersion: tls.VersionTLS13, + } + + token, err := os.ReadFile(tokenFile) + if err != nil { + return nil, err + } + + perRPCCred := oauth.TokenSource{ + TokenSource: oauth2.StaticTokenSource(&oauth2.Token{ + AccessToken: string(token), + })} + + return grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), grpc.WithPerRPCCredentials(perRPCCred)) +} diff --git a/test/helper.go b/test/helper.go index 3955a940..8b3e8281 100755 --- a/test/helper.go +++ b/test/helper.go @@ -160,6 +160,7 @@ func (helper *Helper) Teardown() { func (helper *Helper) startAPIServer() { // TODO jwk mock server needs to be refactored out of the helper and into the testing environment helper.Env().Config.HTTPServer.JwkCertURL = jwkURL + helper.Env().Config.GRPCServer.DisableTLS = true helper.APIServer = server.NewAPIServer(helper.EventBroadcaster) go func() { glog.V(10).Info("Test API server started") From b340060d5c23ef1559ca159964a6f93bca468e04 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Thu, 5 Sep 2024 15:49:42 +0800 Subject: [PATCH 24/67] add aro-hpc scability test (#171) Signed-off-by: Wei Liu --- go.mod | 6 +- go.sum | 0 test/performance/README.md | 167 +++++ test/performance/cmd/main.go | 134 ++++ test/performance/hack/aro-hcp/check-result.sh | 8 + test/performance/hack/aro-hcp/cleanup.sh | 10 + .../hack/aro-hcp/create-clusters.sh | 29 + test/performance/hack/aro-hcp/create-works.sh | 29 + .../hack/aro-hcp/prepare.consumer.sh | 25 + test/performance/hack/aro-hcp/prepare.kind.sh | 19 + .../hack/aro-hcp/prepare.kv.certs.sh | 105 +++ test/performance/hack/aro-hcp/prepare.kv.sh | 21 + .../hack/aro-hcp/prepare.maestro.sh | 9 + .../hack/aro-hcp/start-consumer-agents.sh | 32 + .../hack/aro-hcp/start-spoke-watcher.sh | 22 + test/performance/pkg/hub/perparer.aro-hcp.go | 144 ++++ .../pkg/hub/sourceclient/client.go | 118 ++++ test/performance/pkg/hub/store/createonly.go | 56 ++ .../manifests/aro-hcp/managedcluster.yaml | 11 + .../aro-hcp/manifestwork.hypershift.yaml | 546 +++++++++++++++ .../aro-hcp/manifestwork.namespace.yaml | 24 + .../pkg/hub/workloads/workload.aro-hcp.go | 189 ++++++ test/performance/pkg/spoke/spoke.aro-hcp.go | 130 ++++ test/performance/pkg/util/events.go | 54 ++ test/performance/pkg/util/util.go | 115 ++++ test/performance/pkg/watcher/hypershift.go | 313 +++++++++ .../pkg/watcher/watcher.aro-hpc.go | 624 ++++++++++++++++++ .../resource-usage/cpu-mem/db-cpu-avg.png | Bin 0 -> 95890 bytes .../resource-usage/cpu-mem/db-cpu-max.png | Bin 0 -> 95991 bytes .../resource-usage/cpu-mem/db-mem-avg.png | Bin 0 -> 94199 bytes .../resource-usage/cpu-mem/db-mem-max.png | Bin 0 -> 95228 bytes .../resource-usage/cpu-mem/db-mem-ws-avg.png | Bin 0 -> 98253 bytes .../resource-usage/cpu-mem/db-mem-ws-max.png | Bin 0 -> 95009 bytes .../resource-usage/cpu-mem/svc-cpu-avg.png | Bin 0 -> 96770 bytes .../resource-usage/cpu-mem/svc-cpu-max.png | Bin 0 -> 95575 bytes .../resource-usage/cpu-mem/svc-mem-avg.png | Bin 0 -> 94553 bytes .../resource-usage/cpu-mem/svc-mem-max.png | Bin 0 -> 94361 bytes .../resource-usage/cpu-mem/svc-mem-ws-avg.png | Bin 0 -> 97885 bytes .../resource-usage/cpu-mem/svc-mem-ws-max.png | Bin 0 -> 97163 bytes .../aro-hpc/resource-usage/mqtt/conns.png | Bin 0 -> 147274 bytes .../resource-usage/mqtt/req-counts.png | Bin 0 -> 246083 bytes .../resource-usage/mqtt/throughput.png | Bin 0 -> 216697 bytes 42 files changed, 2937 insertions(+), 3 deletions(-) mode change 100755 => 100644 go.sum create mode 100644 test/performance/README.md create mode 100644 test/performance/cmd/main.go create mode 100644 test/performance/hack/aro-hcp/check-result.sh create mode 100644 test/performance/hack/aro-hcp/cleanup.sh create mode 100755 test/performance/hack/aro-hcp/create-clusters.sh create mode 100755 test/performance/hack/aro-hcp/create-works.sh create mode 100755 test/performance/hack/aro-hcp/prepare.consumer.sh create mode 100755 test/performance/hack/aro-hcp/prepare.kind.sh create mode 100755 test/performance/hack/aro-hcp/prepare.kv.certs.sh create mode 100755 test/performance/hack/aro-hcp/prepare.kv.sh create mode 100755 test/performance/hack/aro-hcp/prepare.maestro.sh create mode 100755 test/performance/hack/aro-hcp/start-consumer-agents.sh create mode 100755 test/performance/hack/aro-hcp/start-spoke-watcher.sh create mode 100644 test/performance/pkg/hub/perparer.aro-hcp.go create mode 100644 test/performance/pkg/hub/sourceclient/client.go create mode 100644 test/performance/pkg/hub/store/createonly.go create mode 100644 test/performance/pkg/hub/workloads/manifests/aro-hcp/managedcluster.yaml create mode 100644 test/performance/pkg/hub/workloads/manifests/aro-hcp/manifestwork.hypershift.yaml create mode 100644 test/performance/pkg/hub/workloads/manifests/aro-hcp/manifestwork.namespace.yaml create mode 100644 test/performance/pkg/hub/workloads/workload.aro-hcp.go create mode 100644 test/performance/pkg/spoke/spoke.aro-hcp.go create mode 100644 test/performance/pkg/util/events.go create mode 100644 test/performance/pkg/util/util.go create mode 100644 test/performance/pkg/watcher/hypershift.go create mode 100644 test/performance/pkg/watcher/watcher.aro-hpc.go create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/db-cpu-avg.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/db-cpu-max.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/db-mem-avg.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/db-mem-max.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/db-mem-ws-avg.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/db-mem-ws-max.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-cpu-avg.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-cpu-max.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-mem-avg.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-mem-max.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-mem-ws-avg.png create mode 100644 test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-mem-ws-max.png create mode 100644 test/performance/result/aro-hpc/resource-usage/mqtt/conns.png create mode 100644 test/performance/result/aro-hpc/resource-usage/mqtt/req-counts.png create mode 100644 test/performance/result/aro-hpc/resource-usage/mqtt/throughput.png diff --git a/go.mod b/go.mod index aa9165fb..1e6b776e 100755 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/onsi/gomega v1.32.0 github.com/openshift-online/ocm-common v0.0.0-20240620110211-2ecfa6ec5707 github.com/openshift-online/ocm-sdk-go v0.1.421 + github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81 github.com/prometheus/client_golang v1.18.0 github.com/segmentio/ksuid v1.0.2 github.com/spf13/cobra v1.8.0 @@ -42,12 +43,14 @@ require ( gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11 k8s.io/api v0.30.2 k8s.io/apimachinery v0.30.2 + k8s.io/apiserver v0.30.1 k8s.io/client-go v0.30.2 k8s.io/component-base v0.30.2 k8s.io/klog/v2 v2.120.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8 + sigs.k8s.io/yaml v1.4.0 ) require ( @@ -110,7 +113,6 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openshift/api v0.0.0-20240527133614-ba11c1587003 // indirect github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 // indirect - github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/profile v1.3.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect @@ -155,7 +157,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/mysql v1.4.7 // indirect k8s.io/apiextensions-apiserver v0.30.1 // indirect - k8s.io/apiserver v0.30.1 // indirect k8s.io/kms v0.30.1 // indirect k8s.io/kube-aggregator v0.30.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect @@ -165,5 +166,4 @@ require ( sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum old mode 100755 new mode 100644 diff --git a/test/performance/README.md b/test/performance/README.md new file mode 100644 index 00000000..dd71c026 --- /dev/null +++ b/test/performance/README.md @@ -0,0 +1,167 @@ +# Performance Test + +## ARO HCP + +### Workloads + +There are 10 consumers in the maestro server and each consumer has 600 resource bundles, include + +- 300 managed cluster resource bundles, one managed cluster resource bundle contains a [ManagedCluster](./pkg/hub/workloads/manifests/aro-hpc/managedcluster.yaml) CR +- 300 manifestworks resource bundles, one managed cluster resource bundle contains two ManifestWork CRs: [namespace](./pkg/hub/workloads/manifests/aro-hpc/manifestwork.namespace.yaml) and [hypershift](./pkg/hub/workloads/manifests/aro-hpc/manifestwork.hypershift.yaml) + +And after the resources are applied on the consumer agent part, there is a status simulator to add the mock status for the resources, finally, one resource will have spec and status, the whole sample can be found from [here](https://drive.google.com/file/d/1OXJX_RFsMqvHgVmroR1XiOAU6LrNYF0y/view?usp=sharing) for managed cluster and manifestworks resources. + +#### Workload Size + +``` +total_records=10x300x2=6000 + +one_managed_cluster_resource_bundles_record_size=3K (3127, spec=742, status=2067) +one_manifestworks_resource_bundles_record_size=49K (49899, spec=30771, status=18802) +total_size_records_per_consumer=300x3+300x49=15M +total_size_records=15x10=150M +``` + +### Test Steps + +1. Follow [ARO-HCP doc](https://github.com/Azure/ARO-HCP/blob/38b459d9e88898d79780e6aa0eacb841828aab07/dev-infrastructure/docs/development-setup.md#maestro-infrastructure) to deploy maestro in the ARO + +2. Add 10 consumers in the maestro + +```sh +counts=10 test/performance/hack/aro-hpc/prepare.consumer.sh +``` + +3. Prepare a KinD cluster to run consumer agents + +```sh +test/performance/hack/aro-hpc/prepare.kind.sh +``` + +4. Start 10 consumer agents + +```sh +# tail -f _output/performance/aro/logs/agents.log +counts=10 test/performance/hack/aro-hpc/start-consumer-agents.sh +``` + +5. Start a watcher to simulate a controller to update the resource status + +```sh +# tail -f _output/performance/aro/logs/watcher.log +counts=10 test/performance/hack/aro-hpc/start-spoke-watcher.sh +``` + +6. Create resource bundles for two consumers: 1 and 2 + +```sh +index=9 test/performance/hack/aro-hpc/create-works.sh +index=10 test/performance/hack/aro-hpc/create-works.sh +``` + +7. Wait the resources are updated on spoke, repeat the step 6 + +### Maestro server cpu/memory consumption + +![cpu-avg](./result/aro-hpc/resource-usage/cpu-mem/svc-cpu-avg.png) + +![cpu-max](./result/aro-hpc/resource-usage/cpu-mem/svc-cpu-max.png) + +![mem-ws-avg](./result/aro-hpc/resource-usage/cpu-mem/svc-mem-ws-avg.png) + +![mem-ws-max](./result/aro-hpc/resource-usage/cpu-mem/svc-mem-ws-max.png) + +![mem-rss-avg](./result/aro-hpc/resource-usage/cpu-mem/svc-mem-avg.png) + +![mem-rss-max](./result/aro-hpc/resource-usage/cpu-mem/svc-mem-max.png) + +### PostgreSQL cpu/memory/storage consumption + +![cpu-avg](./result/aro-hpc/resource-usage/cpu-mem/db-cpu-avg.png) + +![cpu-max](./result/aro-hpc/resource-usage/cpu-mem/db-cpu-max.png) + +![mem-ws-avg](./result/aro-hpc/resource-usage/cpu-mem/db-mem-ws-avg.png) + +![mem-ws-max](./result/aro-hpc/resource-usage/cpu-mem/db-mem-ws-max.png) + +![mem-rss-avg](./result/aro-hpc/resource-usage/cpu-mem/db-mem-avg.png) + +![mem-rss-max](./result/aro-hpc/resource-usage/cpu-mem/db-mem-max.png) + +``` +# PostgreSQL Table Size +total | records +-------+--------- +15 MB | 1200 +27 MB | 2400 +40 MB | 3600 +52 MB | 4800 +65 MB | 6000 +``` + +### Event Grid consumption + +![mqtt-connections](./result/aro-hpc/resource-usage/mqtt/conns.png) + +![mqtt-throughput](./result/aro-hpc/resource-usage/mqtt/throughput.png) + +![mqtt-request-counts](./result/aro-hpc/resource-usage/mqtt/req-counts.png) + +### Responsiveness + +1. The maestro server resource creation velocity: avg=54r/s, max=93r/s (source client sends 6000 requests with a given QPS(avg=56, max=93) ) +2. The maestro server resource status update velocity: avg=2r/s, max=15r/s (10 agents, each agent sync the resource status every 10s) +3. List time consumption + +``` +# list all resources for one consumer (total resources 6000) +lists resources (counts=600) from consumer 1, time=3266ms +lists resources (counts=600) from consumer 2, time=3182ms +lists resources (counts=600) from consumer 3, time=3158ms +lists resources (counts=600) from consumer 4, time=3147ms +lists resources (counts=600) from consumer 5, time=3245ms +lists resources (counts=600) from consumer 6, time=3309ms +lists resources (counts=600) from consumer 7, time=3097ms +lists resources (counts=600) from consumer 8, time=4037ms +lists resources (counts=600) from consumer 9, time=3191ms +lists resources (counts=600) from consumer 10, time=3167ms +avg_time=3279ms + +# only list managed cluster resource bundles for one consumer (total resources 6000) +lists resources (counts=300) from consumer 1, time=345ms +lists resources (counts=300) from consumer 2, time=275ms +lists resources (counts=300) from consumer 3, time=279ms +lists resources (counts=300) from consumer 4, time=249ms +lists resources (counts=300) from consumer 5, time=272ms +lists resources (counts=300) from consumer 6, time=335ms +lists resources (counts=300) from consumer 7, time=313ms +lists resources (counts=300) from consumer 8, time=281ms +lists resources (counts=300) from consumer 9, time=295ms +lists resources (counts=300) from consumer 10, time=298ms +avg_time=294ms + +# only list hyper shift resource bundles for one consumer (total resources 6000) +lists resources (counts=300) from consumer 1, time=2915ms +lists resources (counts=300) from consumer 2, time=2707ms +lists resources (counts=300) from consumer 3, time=3455ms +lists resources (counts=300) from consumer 4, time=2842ms +lists resources (counts=300) from consumer 5, time=2741ms +lists resources (counts=300) from consumer 6, time=2741ms +lists resources (counts=300) from consumer 7, time=2820ms +lists resources (counts=300) from consumer 8, time=2794ms +lists resources (counts=300) from consumer 9, time=3070ms +lists resources (counts=300) from consumer 10, time=2851ms +avg_time=2893ms + +# list all (total resources 6000) +lists resources 1200 from 2 consumers, time=6643ms +lists resources 1800 from 3 consumers, time=9452ms +lists resources 2400 from 4 consumers, time=12864ms +lists resources 3000 from 5 consumers, time=15584ms +lists resources 3600 from 6 consumers, time=17807ms +lists resources 4200 from 7 consumers, time=20371ms +lists resources 4800 from 8 consumers, time=22623ms +lists resources 5400 from 9 consumers, time=25392ms +lists resources 6000 from 10 consumers, time=28377ms +``` diff --git a/test/performance/cmd/main.go b/test/performance/cmd/main.go new file mode 100644 index 00000000..924ad534 --- /dev/null +++ b/test/performance/cmd/main.go @@ -0,0 +1,134 @@ +package main + +import ( + "context" + goflag "flag" + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "k8s.io/apiserver/pkg/server" + utilflag "k8s.io/component-base/cli/flag" + "k8s.io/component-base/logs" + "k8s.io/klog/v2" + + "github.com/openshift-online/maestro/test/performance/pkg/hub" + "github.com/openshift-online/maestro/test/performance/pkg/spoke" + "github.com/openshift-online/maestro/test/performance/pkg/watcher" +) + +func main() { + pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) + pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) + + logs.AddFlags(pflag.CommandLine) + logs.InitLogs() + defer logs.FlushLogs() + + cmd := &cobra.Command{ + Use: "maestroperf", + Short: "Maestro Performance Test Tool", + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + os.Exit(1) + }, + } + + cmd.AddCommand( + newAROHCPPreparationCommand(), + newAROHCPSpokeCommand(), + newAROHCPWatchCommand(), + ) + + if err := cmd.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } +} + +func newAROHCPPreparationCommand() *cobra.Command { + o := hub.NewAROHCPPreparerOptions() + cmd := &cobra.Command{ + Use: "aro-hcp-prepare", + Short: "Prepare clusters or works in Maestro for ARO HCP", + Long: "Prepare clusters or works in Maestro for ARO HCP", + Run: func(cmd *cobra.Command, args []string) { + // handle SIGTERM and SIGINT by cancelling the context. + ctx, cancel := context.WithCancel(context.Background()) + shutdownHandler := server.SetupSignalHandler() + go func() { + defer cancel() + <-shutdownHandler + klog.Infof("\nShutting down aro-hcp-prepare.") + }() + + if err := o.Run(ctx); err != nil { + klog.Errorf("failed to run aro-hcp-prepare, %v", err) + } + }, + } + + flags := cmd.Flags() + o.AddFlags(flags) + return cmd +} + +func newAROHCPSpokeCommand() *cobra.Command { + o := spoke.NewAROHCPSpokeOptions() + cmd := &cobra.Command{ + Use: "aro-hcp-spoke", + Short: "Start agents for ARO HCP", + Long: "Start agents for ARO HCP", + Run: func(cmd *cobra.Command, args []string) { + // handle SIGTERM and SIGINT by cancelling the context. + ctx, cancel := context.WithCancel(context.Background()) + shutdownHandler := server.SetupSignalHandler() + go func() { + defer cancel() + <-shutdownHandler + klog.Infof("\nShutting down aro-hcp-spoke.") + }() + + if err := o.Run(ctx); err != nil { + klog.Errorf("failed to run aro-hcp-spoke, %v", err) + } + + <-ctx.Done() + }, + } + + flags := cmd.Flags() + o.AddFlags(flags) + return cmd +} + +func newAROHCPWatchCommand() *cobra.Command { + o := watcher.NewAROHCPWatcherOptions() + cmd := &cobra.Command{ + Use: "aro-hcp-watch", + Short: "Start watcher for ARO HCP", + Long: "Start watcher for ARO HCP", + Run: func(cmd *cobra.Command, args []string) { + // handle SIGTERM and SIGINT by cancelling the context. + ctx, cancel := context.WithCancel(context.Background()) + shutdownHandler := server.SetupSignalHandler() + go func() { + defer cancel() + <-shutdownHandler + klog.Infof("\nShutting down aro-hcp-watch.") + }() + + if err := o.Run(ctx); err != nil { + klog.Errorf("failed to run aro-hcp-watch, %v", err) + } + + <-ctx.Done() + }, + } + + flags := cmd.Flags() + o.AddFlags(flags) + return cmd +} diff --git a/test/performance/hack/aro-hcp/check-result.sh b/test/performance/hack/aro-hcp/check-result.sh new file mode 100644 index 00000000..a0f6c0ea --- /dev/null +++ b/test/performance/hack/aro-hcp/check-result.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +db_pod_name=$(kubectl -n maestro get pods -l name=maestro-db -ojsonpath='{.items[0].metadata.name}') + +kubectl -n maestro exec ${db_pod_name} -- psql -d maestro -U maestro -c 'select count(*) from resources' +kubectl -n maestro exec ${db_pod_name} -- psql -d maestro -U maestro -c "select created_at,updated_at,extract(epoch from age(updated_at,created_at)) from resources where consumer_name='maestro-cluster-9' order by created_at" +kubectl -n maestro exec ${db_pod_name} -- psql -d maestro -U maestro -c "select created_at,updated_at,extract(epoch from age(updated_at,created_at)) from resources where consumer_name='maestro-cluster-10' order by created_at" +kubectl -n maestro exec ${db_pod_name} -- psql -d maestro -U maestro -c "select pg_size_pretty(pg_total_relation_size('resources')) as total, pg_size_pretty(pg_relation_size('resources')) as data" diff --git a/test/performance/hack/aro-hcp/cleanup.sh b/test/performance/hack/aro-hcp/cleanup.sh new file mode 100644 index 00000000..56684d89 --- /dev/null +++ b/test/performance/hack/aro-hcp/cleanup.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +ARO_HCP_REPO_PATH="$HOME/go/src/github.com/Azure/ARO-HCP" + +ls _output/performance/aro/pids | xargs kill +kind delete clusters --all + +pushd $ARO_HCP_REPO_PATH/dev-infrastructure +AKSCONFIG=svc-cluster make clean +popd diff --git a/test/performance/hack/aro-hcp/create-clusters.sh b/test/performance/hack/aro-hcp/create-clusters.sh new file mode 100755 index 00000000..7bc3d88d --- /dev/null +++ b/test/performance/hack/aro-hcp/create-clusters.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +total=${total:-10} +begin_index=${begin_index:-1} + +lastIndex=$(($begin_index + $total - 1)) +echo "create clusters from maestro-cluster-$begin_index to maestro-cluster-$lastIndex" + +kubectl apply -f - < ${cert_dir}/${consumer_name}.json < ${cert_dir}/${consumer_name}.pfx + +openssl pkcs12 -in ${cert_dir}/${consumer_name}.pfx -passin "pass:" -nocerts -nodes -out ${cert_dir}/${consumer_name}.key +openssl pkcs12 -in ${cert_dir}/${consumer_name}.pfx -passin "pass:" -nokeys -out ${cert_dir}/${consumer_name}.pem + +thumbprint=$(openssl x509 -fingerprint -in ${cert_dir}/${consumer_name}.pem | grep "SHA1 Fingerprint" | sed -e 's/SHA1 Fingerprint=//g' | sed -e 's/://g') + +event_grid="${resource_groups}-eventgrid" +echo "Prepare client in event grid ${event_grid} for $consumer_name" +az eventgrid namespace client create -g ${resource_groups} \ + --namespace-name ${event_grid} \ + -n ${consumer_name} \ + --authentication-name ${consumer_name}.selfsigned.maestro.keyvault.aro-int.azure.com \ + --attributes "{'role':'consumer','consumer_name':'${consumer_name}'}" \ + --client-certificate-authentication "{validationScheme:ThumbprintMatch,allowed-thumbprints:[$thumbprint]}" + +host="${resource_groups}-eventgrid.${region}.ts.eventgrid.azure.net" +src_topic="sources/maestro/consumers/${consumer_name}/sourceevents" +agent_topic="sources/maestro/consumers/${consumer_name}/agentevents" + +cat > "${cert_dir}/${consumer_name}-config.yaml" << EOF +brokerHost: "$host:8883" +caFile: ${cert_dir}/ca.crt +clientCertFile: ${cert_dir}/${consumer_name}.pem +clientKeyFile: ${cert_dir}/${consumer_name}.key +topics: + sourceEvents: $src_topic + agentEvents: $agent_topic +EOF + +echo "The certificates is creaed for $consumer_name" diff --git a/test/performance/hack/aro-hcp/prepare.kv.sh b/test/performance/hack/aro-hcp/prepare.kv.sh new file mode 100755 index 00000000..10fd15c1 --- /dev/null +++ b/test/performance/hack/aro-hcp/prepare.kv.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +REPO_DIR="$(cd "$(dirname ${BASH_SOURCE[0]})/../../../.." ; pwd -P)" + +subscription_id="${subscription_id}" +resource_groups="${resource_groups}" +region="${region}" + +work_dir=${REPO_DIR}/_output/performance/aro +cert_dir=${REPO_DIR}/_output/performance/aro/cert + +mkdir -p ${cert_dir} + +kubectl --kubeconfig $HOME/.kube/svc-cluster.kubeconfig -n maestro get secrets maestro-mqtt -ojsonpath='{.data.ca\.crt}' | base64 -d > ${cert_dir}/ca.crt + +vault_name=$(az keyvault list --query "[?starts_with(name, 'maestro-kv')].name" -g ${resource_groups} --output tsv) + +echo "Create a Key Vault Administrator for $vault_name" +az role assignment create --role "Key Vault Administrator" \ + --assignee ${assignee} \ + --scope /subscriptions/${subscription_id}/resourceGroups/${resource_groups}/providers/Microsoft.KeyVault/vaults/${vault_name} diff --git a/test/performance/hack/aro-hcp/prepare.maestro.sh b/test/performance/hack/aro-hcp/prepare.maestro.sh new file mode 100755 index 00000000..df114779 --- /dev/null +++ b/test/performance/hack/aro-hcp/prepare.maestro.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +ARO_HCP_REPO_PATH="$HOME/go/src/github.com/Azure/ARO-HCP" + +pushd $ARO_HCP_REPO_PATH/dev-infrastructure +AKSCONFIG=svc-cluster make cluster +AKSCONFIG=svc-cluster make aks.kubeconfig +KUBECONFIG=${HOME}/.kube/svc-cluster.kubeconfig scripts/maestro-server.sh +popd diff --git a/test/performance/hack/aro-hcp/start-consumer-agents.sh b/test/performance/hack/aro-hcp/start-consumer-agents.sh new file mode 100755 index 00000000..df836207 --- /dev/null +++ b/test/performance/hack/aro-hcp/start-consumer-agents.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +REPO_DIR="$(cd "$(dirname ${BASH_SOURCE[0]})/../../../.." ; pwd -P)" + +# the counts of agents that are running at one kind cluster +counts=${counts:-1} + +# work dir +work_dir=${REPO_DIR}/_output/performance/aro +spoke_kube_dir=${work_dir}/clusters +agent_config_dir=${work_dir}/cert +agent_log_dir=${work_dir}/logs +pid_dir=${work_dir}/pids + +mkdir -p ${agent_log_dir} +mkdir -p ${pid_dir} + + +# start agents +echo "Start ${counts} agents ..." +echo "The kind cluster ${spoke_kube_dir}/test.kubeconfig is used" + +args="--agent-config-dir=${agent_config_dir}" +args="${args} --hub-kubeconfig=${KUBECONFIG}" +args="${args} --spoke-kubeconfig=${spoke_kube_dir}/test.kubeconfig" +args="${args} --cluster-begin-index=1" +args="${args} --cluster-counts=${counts}" + +(exec "${REPO_DIR}"/maestroperf aro-hcp-spoke $args) &> ${agent_log_dir}/agents.log & +PERF_PID=$! +echo "$counts agents started: $PERF_PID" +touch $pid_dir/$PERF_PID diff --git a/test/performance/hack/aro-hcp/start-spoke-watcher.sh b/test/performance/hack/aro-hcp/start-spoke-watcher.sh new file mode 100755 index 00000000..198a7ff3 --- /dev/null +++ b/test/performance/hack/aro-hcp/start-spoke-watcher.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +REPO_DIR="$(cd "$(dirname ${BASH_SOURCE[0]})/../../../.." ; pwd -P)" + +index=${index:-1} +counts=${counts:-2} + +# work dir +work_dir=${REPO_DIR}/_output/performance/aro +spoke_kube_dir=${work_dir}/clusters +log_dir=${work_dir}/logs +pid_dir=${work_dir}/pids + + +args="--spoke-kubeconfig=${spoke_kube_dir}/test.kubeconfig" +args="${args} --clusters-index=$index" +args="${args} --clusters-counts=$counts" + +(exec "${REPO_DIR}"/maestroperf aro-hcp-watch $args) &> ${log_dir}/watcher.log & +PERF_PID=$! +echo "watcher started: $PERF_PID" +touch $pid_dir/$PERF_PID diff --git a/test/performance/pkg/hub/perparer.aro-hcp.go b/test/performance/pkg/hub/perparer.aro-hcp.go new file mode 100644 index 00000000..330a97c0 --- /dev/null +++ b/test/performance/pkg/hub/perparer.aro-hcp.go @@ -0,0 +1,144 @@ +package hub + +import ( + "context" + "fmt" + "time" + + "github.com/spf13/pflag" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" + + "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc" + "open-cluster-management.io/sdk-go/pkg/cloudevents/work" + "open-cluster-management.io/sdk-go/pkg/cloudevents/work/source/codec" + + "github.com/openshift-online/maestro/test/performance/pkg/hub/store" + "github.com/openshift-online/maestro/test/performance/pkg/hub/workloads" + "github.com/openshift-online/maestro/test/performance/pkg/util" +) + +const ( + sourceID = "maestro-performance-test" + defaultMaestroServiceAddress = "http://maestro:8000" + defaultMaestroGRPCAddress = "maestro-grpc:8090" +) + +type AROHCPPreparerOptions struct { + MaestroServiceAddress string + GRPCServiceAddress string + + ClusterBeginIndex int + ClusterCounts int + + OnlyClusters bool + + WorkCounts int +} + +func NewAROHCPPreparerOptions() *AROHCPPreparerOptions { + return &AROHCPPreparerOptions{ + MaestroServiceAddress: defaultMaestroServiceAddress, + GRPCServiceAddress: defaultMaestroGRPCAddress, + ClusterBeginIndex: 1, + ClusterCounts: 1, + WorkCounts: 1, + } +} + +func (o *AROHCPPreparerOptions) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&o.MaestroServiceAddress, "maestro-service-address", o.MaestroServiceAddress, "Address of the Maestro API service") + fs.StringVar(&o.GRPCServiceAddress, "grpc-service-address", o.GRPCServiceAddress, "Address of the Maestro GRPC service") + fs.IntVar(&o.ClusterBeginIndex, "cluster-begin-index", o.ClusterBeginIndex, "Begin index of the clusters") + fs.IntVar(&o.ClusterCounts, "cluster-counts", o.ClusterCounts, "Counts of the clusters") + fs.BoolVar(&o.OnlyClusters, "only-clusters", o.OnlyClusters, "Only create clusters") + fs.IntVar(&o.WorkCounts, "work-counts", o.WorkCounts, "Counts of the works") +} + +func (o *AROHCPPreparerOptions) Run(ctx context.Context) error { + if o.OnlyClusters { + return o.PrepareClusters(ctx) + } + + // initialize cluster with works + if err := o.CreateWorks(ctx, "init"); err != nil { + return err + } + + return nil +} + +func (o *AROHCPPreparerOptions) PrepareClusters(ctx context.Context) error { + apiClient := util.NewMaestroAPIClient(o.MaestroServiceAddress) + + index := o.ClusterBeginIndex + startTime := time.Now() + for i := 0; i < o.ClusterCounts; i++ { + clusterName := util.ClusterName(index) + + startTime := time.Now() + if err := util.CreateConsumer(ctx, apiClient, clusterName); err != nil { + return err + } + + klog.Infof("cluster %s is created, time=%dms", clusterName, util.UsedTime(startTime, time.Millisecond)) + + index = index + 1 + } + klog.Infof("Clusters (%d) are created, time=%dms", o.ClusterCounts, util.UsedTime(startTime, time.Millisecond)) + return nil +} + +func (o *AROHCPPreparerOptions) CreateWorks(ctx context.Context, phase string) error { + creator, err := work.NewClientHolderBuilder(&grpc.GRPCOptions{URL: o.GRPCServiceAddress}). + WithClientID(fmt.Sprintf("%s-client", sourceID)). + WithSourceID(sourceID). + WithCodecs(codec.NewManifestBundleCodec()). + WithWorkClientWatcherStore(store.NewCreateOnlyWatcherStore()). + WithResyncEnabled(false). + NewSourceClientHolder(ctx) + if err != nil { + return err + } + + workClient := creator.WorkInterface() + + index := o.ClusterBeginIndex + total := 0 + startTime := time.Now() + for i := 0; i < o.ClusterCounts; i++ { + clusterName := util.ClusterName(index) + + for j := 0; j < o.WorkCounts; j++ { + works, err := workloads.ToAROHCPManifestWorks(clusterName) + if err != nil { + return err + } + + startTime := time.Now() + for _, work := range works { + startTime := time.Now() + if _, err := workClient.WorkV1().ManifestWorks(clusterName).Create( + ctx, + work, + metav1.CreateOptions{}, + ); err != nil { + return err + } + + klog.Infof("the work %s/%s is created, time=%dms", + work.Namespace, work.Name, util.UsedTime(startTime, time.Millisecond)) + total = total + 1 + } + + klog.Infof("the works are created for cluster %s, time=%dms", + clusterName, util.UsedTime(startTime, time.Millisecond)) + } + index = index + 1 + } + + klog.Infof("Works (%d) are created, time=%dms", total, util.UsedTime(startTime, time.Millisecond)) + + return nil +} diff --git a/test/performance/pkg/hub/sourceclient/client.go b/test/performance/pkg/hub/sourceclient/client.go new file mode 100644 index 00000000..3c45abe3 --- /dev/null +++ b/test/performance/pkg/hub/sourceclient/client.go @@ -0,0 +1,118 @@ +package main + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + workv1client "open-cluster-management.io/api/client/work/clientset/versioned/typed/work/v1" + "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc" + + "github.com/openshift-online/maestro/pkg/client/cloudevents/grpcsource" + "github.com/openshift-online/maestro/test/performance/pkg/util" +) + +const sourceID = "maestro-performance-test" + +var ( + maestroServerAddr = "http://127.0.0.1:8000" + grpcServerAddr = "127.0.0.1:8090" +) + +func main() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + maestroAPIClient := util.NewMaestroAPIClient(maestroServerAddr) + + grpcOptions := grpc.NewGRPCOptions() + grpcOptions.URL = grpcServerAddr + + workClient, err := grpcsource.NewMaestroGRPCSourceWorkClient( + ctx, + maestroAPIClient, + grpcOptions, + sourceID, + ) + if err != nil { + log.Fatal(err) + } + + totalTime := 0 + for i := 1; i <= 10; i++ { + startTime := time.Now() + works, err := workClient.ManifestWorks(util.ClusterName(i)).List(ctx, metav1.ListOptions{}) + if err != nil { + log.Fatal(err) + } + + usedTime := util.UsedTime(startTime, time.Millisecond) + totalTime = totalTime + int(usedTime) + fmt.Printf("lists works %d, time=%d\n", len(works.Items), usedTime) + } + fmt.Printf("avg_time=%d\n", totalTime/10) + + for i := 1; i <= 10; i++ { + startTime := time.Now() + works, err := workClient.ManifestWorks(util.ClusterName(i)).List(ctx, metav1.ListOptions{ + LabelSelector: "maestro.performance.test=mc", + }) + if err != nil { + log.Fatal(err) + } + + usedTime := util.UsedTime(startTime, time.Millisecond) + totalTime = totalTime + int(usedTime) + fmt.Printf("lists works %d, time=%dms\n", len(works.Items), usedTime) + } + fmt.Printf("avg_time=%dms\n", totalTime/10) + + for i := 1; i <= 10; i++ { + startTime := time.Now() + works, err := workClient.ManifestWorks(util.ClusterName(i)).List(ctx, metav1.ListOptions{ + LabelSelector: "maestro.performance.test=hypershift", + }) + if err != nil { + log.Fatal(err) + } + + usedTime := util.UsedTime(startTime, time.Millisecond) + totalTime = totalTime + int(usedTime) + fmt.Printf("lists works %d, time=%dms\n", len(works.Items), usedTime) + } + fmt.Printf("avg_time=%dms\n", totalTime/10) + + listWorks(ctx, workClient, getClusterNames(2)) + listWorks(ctx, workClient, getClusterNames(3)) + listWorks(ctx, workClient, getClusterNames(4)) + listWorks(ctx, workClient, getClusterNames(5)) + listWorks(ctx, workClient, getClusterNames(6)) + listWorks(ctx, workClient, getClusterNames(7)) + listWorks(ctx, workClient, getClusterNames(8)) + listWorks(ctx, workClient, getClusterNames(9)) + listWorks(ctx, workClient, getClusterNames(10)) + +} + +func listWorks(ctx context.Context, workClient workv1client.WorkV1Interface, names string) { + startTime := time.Now() + works, err := workClient.ManifestWorks(metav1.NamespaceAll).List(ctx, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("cluster.maestro.performance.test in (%s)", names), + }) + if err != nil { + log.Fatal(err) + } + fmt.Printf("lists works %d, time=%dms\n", len(works.Items), util.UsedTime(startTime, time.Millisecond)) +} + +func getClusterNames(total int) string { + names := []string{} + for i := 1; i <= total; i++ { + names = append(names, fmt.Sprintf("maestro-cluster-%d", i)) + } + return strings.Join(names, ",") +} diff --git a/test/performance/pkg/hub/store/createonly.go b/test/performance/pkg/hub/store/createonly.go new file mode 100644 index 00000000..69eea4c7 --- /dev/null +++ b/test/performance/pkg/hub/store/createonly.go @@ -0,0 +1,56 @@ +package store + +import ( + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" + + workv1 "open-cluster-management.io/api/work/v1" + "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" +) + +type CreateOnlyWatcherStore struct { +} + +func NewCreateOnlyWatcherStore() *CreateOnlyWatcherStore { + return &CreateOnlyWatcherStore{} +} + +func (s *CreateOnlyWatcherStore) GetWatcher(namespace string, opts metav1.ListOptions) (watch.Interface, error) { + return nil, fmt.Errorf("unsupported") +} + +func (s *CreateOnlyWatcherStore) HandleReceivedWork(action types.ResourceAction, work *workv1.ManifestWork) error { + // do nothing + return nil +} + +func (s *CreateOnlyWatcherStore) Add(work *workv1.ManifestWork) error { + // do nothing + return nil +} + +func (s *CreateOnlyWatcherStore) Update(work *workv1.ManifestWork) error { + return fmt.Errorf("unsupported") +} + +func (s *CreateOnlyWatcherStore) Delete(work *workv1.ManifestWork) error { + return fmt.Errorf("unsupported") +} + +func (s *CreateOnlyWatcherStore) List(namespace string, opts metav1.ListOptions) (*workv1.ManifestWorkList, error) { + return nil, fmt.Errorf("unsupported") +} + +func (s *CreateOnlyWatcherStore) ListAll() ([]*workv1.ManifestWork, error) { + return nil, fmt.Errorf("unsupported") +} + +func (s *CreateOnlyWatcherStore) Get(namespace, name string) (*workv1.ManifestWork, bool, error) { + return nil, false, fmt.Errorf("unsupported") +} + +func (s *CreateOnlyWatcherStore) HasInitiated() bool { + return false +} diff --git a/test/performance/pkg/hub/workloads/manifests/aro-hcp/managedcluster.yaml b/test/performance/pkg/hub/workloads/manifests/aro-hcp/managedcluster.yaml new file mode 100644 index 00000000..1ef903e8 --- /dev/null +++ b/test/performance/pkg/hub/workloads/manifests/aro-hcp/managedcluster.yaml @@ -0,0 +1,11 @@ +apiVersion: cluster.open-cluster-management.io/v1 +kind: ManagedCluster +metadata: + name: {{ .Name }} + annotations: + import.open-cluster-management.io/hosting-cluster-name: {{ .ClusterName }} + import.open-cluster-management.io/klusterlet-deploy-mode: Hosted + open-cluster-management/created-via: other + addon.open-cluster-management.io/enable-hosted-mode-addons: "true" +spec: + hubAcceptsClient: true diff --git a/test/performance/pkg/hub/workloads/manifests/aro-hcp/manifestwork.hypershift.yaml b/test/performance/pkg/hub/workloads/manifests/aro-hcp/manifestwork.hypershift.yaml new file mode 100644 index 00000000..99315e14 --- /dev/null +++ b/test/performance/pkg/hub/workloads/manifests/aro-hcp/manifestwork.hypershift.yaml @@ -0,0 +1,546 @@ +apiVersion: work.open-cluster-management.io/v1 +kind: ManifestWork +metadata: + annotations: + hypershift-deployment.open-cluster-management.io/created-by: ignore/ignore + name: {{ .Name }}-hypershift + namespace: {{ .ClusterName }} + labels: + api.openshift.com/environment: maestro-perf-test + api.openshift.com/id: {{ .Name }} + api.openshift.com/legal-entity-id: {{ .Name }} + api.openshift.com/name: {{ .Name }} + api.openshift.com/hosted-cluster: "true" + api.openshift.com/management-cluster: {{ .ClusterName }} +spec: + deleteOption: + propagationPolicy: Foreground + manifestConfigs: + - feedbackRules: + - jsonPaths: + - name: Available-Reason + path: .status.conditions[?(@.type=="Available")].reason + - name: Available-Status + path: .status.conditions[?(@.type=="Available")].status + - name: Available-Message + path: .status.conditions[?(@.type=="Available")].message + - name: Available-LastTransitionTime + path: .status.conditions[?(@.type=="Available")].lastTransitionTime + - name: Progressing-Reason + path: .status.conditions[?(@.type=="Progressing")].reason + - name: Progressing-Status + path: .status.conditions[?(@.type=="Progressing")].status + - name: Progressing-Message + path: .status.conditions[?(@.type=="Progressing")].message + - name: Progressing-LastTransitionTime + path: .status.conditions[?(@.type=="Progressing")].lastTransitionTime + - name: Degraded-Reason + path: .status.conditions[?(@.type=="Degraded")].reason + - name: Degraded-Status + path: .status.conditions[?(@.type=="Degraded")].status + - name: Degraded-Message + path: .status.conditions[?(@.type=="Degraded")].message + - name: Degraded-LastTransitionTime + path: .status.conditions[?(@.type=="Degraded")].lastTransitionTime + - name: InfrastructureReady-Reason + path: .status.conditions[?(@.type=="InfrastructureReady")].reason + - name: InfrastructureReady-Status + path: .status.conditions[?(@.type=="InfrastructureReady")].status + - name: InfrastructureReady-Message + path: .status.conditions[?(@.type=="InfrastructureReady")].message + - name: InfrastructureReady-LastTransitionTime + path: .status.conditions[?(@.type=="InfrastructureReady")].lastTransitionTime + - name: KubeAPIServerAvailable-Reason + path: .status.conditions[?(@.type=="KubeAPIServerAvailable")].reason + - name: KubeAPIServerAvailable-Status + path: .status.conditions[?(@.type=="KubeAPIServerAvailable")].status + - name: KubeAPIServerAvailable-Message + path: .status.conditions[?(@.type=="KubeAPIServerAvailable")].message + - name: KubeAPIServerAvailable-LastTransitionTime + path: .status.conditions[?(@.type=="KubeAPIServerAvailable")].lastTransitionTime + - name: EtcdAvailable-Reason + path: .status.conditions[?(@.type=="EtcdAvailable")].reason + - name: EtcdAvailable-Status + path: .status.conditions[?(@.type=="EtcdAvailable")].status + - name: EtcdAvailable-Message + path: .status.conditions[?(@.type=="EtcdAvailable")].message + - name: EtcdAvailable-LastTransitionTime + path: .status.conditions[?(@.type=="EtcdAvailable")].lastTransitionTime + - name: ValidHostedControlPlaneConfiguration-Reason + path: .status.conditions[?(@.type=="ValidHostedControlPlaneConfiguration")].reason + - name: ValidHostedControlPlaneConfiguration-Status + path: .status.conditions[?(@.type=="ValidHostedControlPlaneConfiguration")].status + - name: ValidHostedControlPlaneConfiguration-Message + path: .status.conditions[?(@.type=="ValidHostedControlPlaneConfiguration")].message + - name: ValidHostedControlPlaneConfiguration-LastTransitionTime + path: .status.conditions[?(@.type=="ValidHostedControlPlaneConfiguration")].lastTransitionTime + - name: CloudResourcesDestroyed-Reason + path: .status.conditions[?(@.type=="CloudResourcesDestroyed")].reason + - name: CloudResourcesDestroyed-Status + path: .status.conditions[?(@.type=="CloudResourcesDestroyed")].status + - name: CloudResourcesDestroyed-Message + path: .status.conditions[?(@.type=="CloudResourcesDestroyed")].message + - name: CloudResourcesDestroyed-LastTransitionTime + path: .status.conditions[?(@.type=="CloudResourcesDestroyed")].lastTransitionTime + - name: HostedClusterDestroyed-Reason + path: .status.conditions[?(@.type=="HostedClusterDestroyed")].reason + - name: HostedClusterDestroyed-Status + path: .status.conditions[?(@.type=="HostedClusterDestroyed")].status + - name: HostedClusterDestroyed-Message + path: .status.conditions[?(@.type=="HostedClusterDestroyed")].message + - name: HostedClusterDestroyed-LastTransitionTime + path: .status.conditions[?(@.type=="HostedClusterDestroyed")].lastTransitionTime + - name: ExternalDNSReachable-Reason + path: .status.conditions[?(@.type=="ExternalDNSReachable")].reason + - name: ExternalDNSReachable-Status + path: .status.conditions[?(@.type=="ExternalDNSReachable")].status + - name: ExternalDNSReachable-Message + path: .status.conditions[?(@.type=="ExternalDNSReachable")].message + - name: ExternalDNSReachable-LastTransitionTime + path: .status.conditions[?(@.type=="ExternalDNSReachable")].lastTransitionTime + - name: ValidReleaseInfo-Reason + path: .status.conditions[?(@.type=="ValidReleaseInfo")].reason + - name: ValidReleaseInfo-Status + path: .status.conditions[?(@.type=="ValidReleaseInfo")].status + - name: ValidReleaseInfo-Message + path: .status.conditions[?(@.type=="ValidReleaseInfo")].message + - name: ValidReleaseInfo-LastTransitionTime + path: .status.conditions[?(@.type=="ValidReleaseInfo")].lastTransitionTime + - name: ClusterVersionSucceeding-Reason + path: .status.conditions[?(@.type=="ClusterVersionSucceeding")].reason + - name: ClusterVersionSucceeding-Status + path: .status.conditions[?(@.type=="ClusterVersionSucceeding")].status + - name: ClusterVersionSucceeding-Message + path: .status.conditions[?(@.type=="ClusterVersionSucceeding")].message + - name: ClusterVersionSucceeding-LastTransitionTime + path: .status.conditions[?(@.type=="ClusterVersionSucceeding")].lastTransitionTime + - name: ClusterVersionUpgradeable-Reason + path: .status.conditions[?(@.type=="ClusterVersionUpgradeable")].reason + - name: ClusterVersionUpgradeable-Status + path: .status.conditions[?(@.type=="ClusterVersionUpgradeable")].status + - name: ClusterVersionUpgradeable-Message + path: .status.conditions[?(@.type=="ClusterVersionUpgradeable")].message + - name: ClusterVersionUpgradeable-LastTransitionTime + path: .status.conditions[?(@.type=="ClusterVersionUpgradeable")].lastTransitionTime + - name: ClusterVersionFailing-Reason + path: .status.conditions[?(@.type=="ClusterVersionFailing")].reason + - name: ClusterVersionFailing-Status + path: .status.conditions[?(@.type=="ClusterVersionFailing")].status + - name: ClusterVersionFailing-Message + path: .status.conditions[?(@.type=="ClusterVersionFailing")].message + - name: ClusterVersionFailing-LastTransitionTime + path: .status.conditions[?(@.type=="ClusterVersionFailing")].lastTransitionTime + - name: ClusterVersionProgressing-Reason + path: .status.conditions[?(@.type=="ClusterVersionProgressing")].reason + - name: ClusterVersionProgressing-Status + path: .status.conditions[?(@.type=="ClusterVersionProgressing")].status + - name: ClusterVersionProgressing-Message + path: .status.conditions[?(@.type=="ClusterVersionProgressing")].message + - name: ClusterVersionProgressing-LastTransitionTime + path: .status.conditions[?(@.type=="ClusterVersionProgressing")].lastTransitionTime + - name: ClusterVersionAvailable-Reason + path: .status.conditions[?(@.type=="ClusterVersionAvailable")].reason + - name: ClusterVersionAvailable-Status + path: .status.conditions[?(@.type=="ClusterVersionAvailable")].status + - name: ClusterVersionAvailable-Message + path: .status.conditions[?(@.type=="ClusterVersionAvailable")].message + - name: ClusterVersionAvailable-LastTransitionTime + path: .status.conditions[?(@.type=="ClusterVersionAvailable")].lastTransitionTime + - name: ClusterVersionReleaseAccepted-Reason + path: .status.conditions[?(@.type=="ClusterVersionReleaseAccepted")].reason + - name: ClusterVersionReleaseAccepted-Status + path: .status.conditions[?(@.type=="ClusterVersionReleaseAccepted")].status + - name: ClusterVersionReleaseAccepted-Message + path: .status.conditions[?(@.type=="ClusterVersionReleaseAccepted")].message + - name: ClusterVersionReleaseAccepted-LastTransitionTime + path: .status.conditions[?(@.type=="ClusterVersionReleaseAccepted")].lastTransitionTime + - name: UnmanagedEtcdAvailable-Reason + path: .status.conditions[?(@.type=="UnmanagedEtcdAvailable")].reason + - name: UnmanagedEtcdAvailable-Status + path: .status.conditions[?(@.type=="UnmanagedEtcdAvailable")].status + - name: UnmanagedEtcdAvailable-Message + path: .status.conditions[?(@.type=="UnmanagedEtcdAvailable")].message + - name: UnmanagedEtcdAvailable-LastTransitionTime + path: .status.conditions[?(@.type=="UnmanagedEtcdAvailable")].lastTransitionTime + - name: IgnitionEndpointAvailable-Reason + path: .status.conditions[?(@.type=="IgnitionEndpointAvailable")].reason + - name: IgnitionEndpointAvailable-Status + path: .status.conditions[?(@.type=="IgnitionEndpointAvailable")].status + - name: IgnitionEndpointAvailable-Message + path: .status.conditions[?(@.type=="IgnitionEndpointAvailable")].message + - name: IgnitionEndpointAvailable-LastTransitionTime + path: .status.conditions[?(@.type=="IgnitionEndpointAvailable")].lastTransitionTime + - name: IgnitionServerValidReleaseInfo-Reason + path: .status.conditions[?(@.type=="IgnitionServerValidReleaseInfo")].reason + - name: IgnitionServerValidReleaseInfo-Status + path: .status.conditions[?(@.type=="IgnitionServerValidReleaseInfo")].status + - name: IgnitionServerValidReleaseInfo-Message + path: .status.conditions[?(@.type=="IgnitionServerValidReleaseInfo")].message + - name: IgnitionServerValidReleaseInfo-LastTransitionTime + path: .status.conditions[?(@.type=="IgnitionServerValidReleaseInfo")].lastTransitionTime + - name: SupportedHostedCluster-Reason + path: .status.conditions[?(@.type=="SupportedHostedCluster")].reason + - name: SupportedHostedCluster-Status + path: .status.conditions[?(@.type=="SupportedHostedCluster")].status + - name: SupportedHostedCluster-Message + path: .status.conditions[?(@.type=="SupportedHostedCluster")].message + - name: SupportedHostedCluster-LastTransitionTime + path: .status.conditions[?(@.type=="SupportedHostedCluster")].lastTransitionTime + - name: ValidOIDCConfiguration-Reason + path: .status.conditions[?(@.type=="ValidOIDCConfiguration")].reason + - name: ValidOIDCConfiguration-Status + path: .status.conditions[?(@.type=="ValidOIDCConfiguration")].status + - name: ValidOIDCConfiguration-Message + path: .status.conditions[?(@.type=="ValidOIDCConfiguration")].message + - name: ValidOIDCConfiguration-LastTransitionTime + path: .status.conditions[?(@.type=="ValidOIDCConfiguration")].lastTransitionTime + - name: ValidReleaseImage-Reason + path: .status.conditions[?(@.type=="ValidReleaseImage")].reason + - name: ValidReleaseImage-Status + path: .status.conditions[?(@.type=="ValidReleaseImage")].status + - name: ValidReleaseImage-Message + path: .status.conditions[?(@.type=="ValidReleaseImage")].message + - name: ValidReleaseImage-LastTransitionTime + path: .status.conditions[?(@.type=="ValidReleaseImage")].lastTransitionTime + - name: ValidAzureKMSConfig-Reason + path: .status.conditions[?(@.type=="ValidAzureKMSConfig")].reason + - name: ValidAzureKMSConfig-Status + path: .status.conditions[?(@.type=="ValidAzureKMSConfig")].status + - name: ValidAzureKMSConfig-Message + path: .status.conditions[?(@.type=="ValidAzureKMSConfig")].message + - name: ValidAzureKMSConfig-LastTransitionTime + path: .status.conditions[?(@.type=="ValidAzureKMSConfig")].lastTransitionTime + - name: PlatformCredentialsFound-Reason + path: .status.conditions[?(@.type=="PlatformCredentialsFound")].reason + - name: PlatformCredentialsFound-Status + path: .status.conditions[?(@.type=="PlatformCredentialsFound")].status + - name: PlatformCredentialsFound-Message + path: .status.conditions[?(@.type=="PlatformCredentialsFound")].message + - name: PlatformCredentialsFound-LastTransitionTime + path: .status.conditions[?(@.type=="PlatformCredentialsFound")].lastTransitionTime + - name: ReconciliationActive-Reason + path: .status.conditions[?(@.type=="ReconciliationActive")].reason + - name: ReconciliationActive-Status + path: .status.conditions[?(@.type=="ReconciliationActive")].status + - name: ReconciliationActive-Message + path: .status.conditions[?(@.type=="ReconciliationActive")].message + - name: ReconciliationActive-LastTransitionTime + path: .status.conditions[?(@.type=="ReconciliationActive")].lastTransitionTime + - name: ReconciliationSucceeded-Reason + path: .status.conditions[?(@.type=="ReconciliationSucceeded")].reason + - name: ReconciliationSucceeded-Status + path: .status.conditions[?(@.type=="ReconciliationSucceeded")].status + - name: ReconciliationSucceeded-Message + path: .status.conditions[?(@.type=="ReconciliationSucceeded")].message + - name: ReconciliationSucceeded-LastTransitionTime + path: .status.conditions[?(@.type=="ReconciliationSucceeded")].lastTransitionTime + - name: progress + path: .status.version.history[?(@.state!="")].state + - name: Version-Desired + path: .status.version.desired.version + - name: Image-Current + path: .status.version.history[?(@.state!="")].image + - name: Version-Current + path: .status.version.history[?(@.state!="")].version + - name: Version-Status + path: .status.version.history[?(@.state!="")].state + type: JSONPaths + resourceIdentifier: + group: hypershift.openshift.io + name: {{ .Name }} + namespace: {{ .Name }} + resource: hostedclusters + updateStrategy: + type: ServerSideApply + - feedbackRules: + - jsonPaths: + - name: ValidPlatformImage-Reason + path: .status.conditions[?(@.type=="ValidPlatformImage")].reason + - name: ValidPlatformImage-Status + path: .status.conditions[?(@.type=="ValidPlatformImage")].status + - name: ValidPlatformImage-Message + path: .status.conditions[?(@.type=="ValidPlatformImage")].message + - name: ValidPlatformImage-LastTransitionTime + path: .status.conditions[?(@.type=="ValidPlatformImage")].lastTransitionTime + - name: ValidMachineConfig-Reason + path: .status.conditions[?(@.type=="ValidMachineConfig")].reason + - name: ValidMachineConfig-Status + path: .status.conditions[?(@.type=="ValidMachineConfig")].status + - name: ValidMachineConfig-Message + path: .status.conditions[?(@.type=="ValidMachineConfig")].message + - name: ValidMachineConfig-LastTransitionTime + path: .status.conditions[?(@.type=="ValidMachineConfig")].lastTransitionTime + - name: ValidTuningConfig-Reason + path: .status.conditions[?(@.type=="ValidTuningConfig")].reason + - name: ValidTuningConfig-Status + path: .status.conditions[?(@.type=="ValidTuningConfig")].status + - name: ValidTuningConfig-Message + path: .status.conditions[?(@.type=="ValidTuningConfig")].message + - name: ValidTuningConfig-LastTransitionTime + path: .status.conditions[?(@.type=="ValidTuningConfig")].lastTransitionTime + - name: UpdateManagementEnabled-Reason + path: .status.conditions[?(@.type=="UpdateManagementEnabled")].reason + - name: UpdateManagementEnabled-Status + path: .status.conditions[?(@.type=="UpdateManagementEnabled")].status + - name: UpdateManagementEnabled-Message + path: .status.conditions[?(@.type=="UpdateManagementEnabled")].message + - name: UpdateManagementEnabled-LastTransitionTime + path: .status.conditions[?(@.type=="UpdateManagementEnabled")].lastTransitionTime + - name: AutoscalingEnabled-Reason + path: .status.conditions[?(@.type=="AutoscalingEnabled")].reason + - name: AutoscalingEnabled-Status + path: .status.conditions[?(@.type=="AutoscalingEnabled")].status + - name: AutoscalingEnabled-Message + path: .status.conditions[?(@.type=="AutoscalingEnabled")].message + - name: AutoscalingEnabled-LastTransitionTime + path: .status.conditions[?(@.type=="AutoscalingEnabled")].lastTransitionTime + - name: Ready-Reason + path: .status.conditions[?(@.type=="Ready")].reason + - name: Ready-Status + path: .status.conditions[?(@.type=="Ready")].status + - name: Ready-Message + path: .status.conditions[?(@.type=="Ready")].message + - name: Ready-LastTransitionTime + path: .status.conditions[?(@.type=="Ready")].lastTransitionTime + - name: ReconciliationActive-Reason + path: .status.conditions[?(@.type=="ReconciliationActive")].reason + - name: ReconciliationActive-Status + path: .status.conditions[?(@.type=="ReconciliationActive")].status + - name: ReconciliationActive-Message + path: .status.conditions[?(@.type=="ReconciliationActive")].message + - name: ReconciliationActive-LastTransitionTime + path: .status.conditions[?(@.type=="ReconciliationActive")].lastTransitionTime + - name: AutorepairEnabled-Reason + path: .status.conditions[?(@.type=="AutorepairEnabled")].reason + - name: AutorepairEnabled-Status + path: .status.conditions[?(@.type=="AutorepairEnabled")].status + - name: AutorepairEnabled-Message + path: .status.conditions[?(@.type=="AutorepairEnabled")].message + - name: AutorepairEnabled-LastTransitionTime + path: .status.conditions[?(@.type=="AutorepairEnabled")].lastTransitionTime + - name: UpdatingVersion-Reason + path: .status.conditions[?(@.type=="UpdatingVersion")].reason + - name: UpdatingVersion-Status + path: .status.conditions[?(@.type=="UpdatingVersion")].status + - name: UpdatingVersion-Message + path: .status.conditions[?(@.type=="UpdatingVersion")].message + - name: UpdatingVersion-LastTransitionTime + path: .status.conditions[?(@.type=="UpdatingVersion")].lastTransitionTime + - name: UpdatingConfig-Reason + path: .status.conditions[?(@.type=="UpdatingConfig")].reason + - name: UpdatingConfig-Status + path: .status.conditions[?(@.type=="UpdatingConfig")].status + - name: UpdatingConfig-Message + path: .status.conditions[?(@.type=="UpdatingConfig")].message + - name: UpdatingConfig-LastTransitionTime + path: .status.conditions[?(@.type=="UpdatingConfig")].lastTransitionTime + - name: AsExpected-Reason + path: .status.conditions[?(@.type=="AsExpected")].reason + - name: AsExpected-Status + path: .status.conditions[?(@.type=="AsExpected")].status + - name: AsExpected-Message + path: .status.conditions[?(@.type=="AsExpected")].message + - name: AsExpected-LastTransitionTime + path: .status.conditions[?(@.type=="AsExpected")].lastTransitionTime + - name: ValidationFailed-Reason + path: .status.conditions[?(@.type=="ValidationFailed")].reason + - name: ValidationFailed-Status + path: .status.conditions[?(@.type=="ValidationFailed")].status + - name: ValidationFailed-Message + path: .status.conditions[?(@.type=="ValidationFailed")].message + - name: ValidationFailed-LastTransitionTime + path: .status.conditions[?(@.type=="ValidationFailed")].lastTransitionTime + - name: InplaceUpgradeFailed-Reason + path: .status.conditions[?(@.type=="InplaceUpgradeFailed")].reason + - name: InplaceUpgradeFailed-Status + path: .status.conditions[?(@.type=="InplaceUpgradeFailed")].status + - name: InplaceUpgradeFailed-Message + path: .status.conditions[?(@.type=="InplaceUpgradeFailed")].message + - name: InplaceUpgradeFailed-LastTransitionTime + path: .status.conditions[?(@.type=="InplaceUpgradeFailed")].lastTransitionTime + type: JSONPaths + resourceIdentifier: + group: hypershift.openshift.io + name: {{ .Name }} + namespace: {{ .Name }} + resource: nodepools + updateStrategy: + type: ServerSideApply + workload: + manifests: + - apiVersion: v1 + data: + .dockerconfigjson: {{ .DockerConfigJSON }} + kind: Secret + metadata: + name: {{ .Name }}-pull + namespace: {{ .Name }} + - apiVersion: v1 + data: + id_rsa: {{ .IDRsa }} + id_rsa.pub: {{ .IDRsaPub }} + kind: Secret + metadata: + name: {{ .Name }}-ssh + namespace: {{ .Name }} + - apiVersion: v1 + data: + key: {{ .SecretKey }} + kind: Secret + metadata: + name: {{ .Name }}-encryption + namespace: {{ .Name }} + - apiVersion: v1 + data: + AZURE_CLIENT_ID: {{ .AzureClientInfo }} + AZURE_CLIENT_SECRET: {{ .AzureClientInfo }} + AZURE_SUBSCRIPTION_ID: {{ .AzureClientInfo }} + AZURE_TENANT_ID: {{ .AzureClientInfo }} + kind: Secret + metadata: + name: {{ .Name }}-azure-credentials + namespace: {{ .Name }} + - apiVersion: v1 + data: + htpasswd: {{ .HTPasswd }} + kind: Secret + metadata: + labels: + api.openshift.com/id: {{ .Name }} + api.openshift.com/name: {{ .Name }} + api.openshift.com/type: identity-provider + name: {{ .Name }}-htpasswd-secret + namespace: {{ .Name }} + type: Opaque + - apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + metadata: + annotations: + cluster.open-cluster-management.io/managedcluster-name: {{ .Name }} + hypershift.openshift.io/cleanup-cloud-resources: "true" + name: {{ .Name }} + namespace: {{ .Name }} + spec: + autoscaling: {} + channel: stable-4.15 + clusterID: {{ .Name }} + configuration: + oauth: + identityProviders: + - htpasswd: + fileData: + name: htpasswd-secret + mappingMethod: claim + name: htpasswd + type: HTPasswd + templates: + error: + name: "" + login: + name: "" + providerSelection: + name: "" + tokenConfig: {} + controllerAvailabilityPolicy: HighlyAvailable + dns: + baseDomain: {{ .BaseDomain }} + etcd: + managed: + storage: + persistentVolume: + size: 32Gi + type: PersistentVolume + managementType: Managed + fips: false + infraID: {{ .Name }} + infrastructureAvailabilityPolicy: HighlyAvailable + networking: + apiServer: + port: 443 + clusterNetwork: + - cidr: 10.132.0.0/14 + machineNetwork: + - cidr: 10.0.0.0/16 + networkType: OVNKubernetes + serviceNetwork: + - cidr: 172.31.0.0/16 + olmCatalogPlacement: management + platform: + azure: + cloud: AzurePublicCloud + credentials: + name: {{ .Name }}-azure-credentials + location: westus3 + resourceGroup: ms-aro-hcp-mrg-test + securityGroupID: /subscriptions/{{ .SubID }}/resourceGroups/networkrelatedrg/providers/Microsoft.Network/networkSecurityGroups/mynsg + subnetID: /subscriptions/{{ .SubID }}/resourceGroups/networkrelatedrg/providers/Microsoft.Network/virtualNetworks/myvnet/subnets/mysubnet + subscriptionID: {{ .SubID }} + vnetID: /subscriptions/{{ .SubID }}/resourceGroups/networkrelatedrg/providers/Microsoft.Network/virtualNetworks/myvnet + type: Azure + pullSecret: + name: {{ .Name }}-pull + release: + image: registry.ci.openshift.org/ocp:1.23 + secretEncryption: + aescbc: + activeKey: + name: {{ .Name }}-encryption + type: aescbc + services: + - service: OVNSbDb + servicePublishingStrategy: + route: + hostname: ovn-sbdb-{{ .Name }}.{{ .BaseDomain }} + type: Route + - service: APIServer + servicePublishingStrategy: + route: + hostname: api-{{ .Name }}. + type: Route + - service: OAuthServer + servicePublishingStrategy: + route: + hostname: oauth-{{ .Name }}.{{ .BaseDomain }} + type: Route + - service: Konnectivity + servicePublishingStrategy: + route: + hostname: konnectivity-{{ .Name }}.{{ .BaseDomain }} + type: Route + - service: Ignition + servicePublishingStrategy: + route: + hostname: ignition-{{ .Name }}.{{ .BaseDomain }} + type: Route + sshKey: + name: {{ .Name }}-ssh + - apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + metadata: + name: {{ .Name }} + namespace: {{ .Name }} + spec: + clusterName: {{ .Name }} + management: + autoRepair: true + replace: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + strategy: RollingUpdate + upgradeType: Replace + platform: + azure: + cloud: AzurePublicCloud + credentials: + name: {{ .Name }}-azure-credentials + location: westus3 + resourceGroup: ms-aro-hcp-mrg-test + securityGroupID: /subscriptions/{{ .SubID }}/resourceGroups/networkrelatedrg/providers/Microsoft.Network/networkSecurityGroups/mynsg + subnetID: /subscriptions/{{ .SubID }}/resourceGroups/networkrelatedrg/providers/Microsoft.Network/virtualNetworks/myvnet/subnets/mysubnet + subscriptionID: {{ .SubID }} + vnetID: /subscriptions/{{ .SubID }}/resourceGroups/networkrelatedrg/providers/Microsoft.Network/virtualNetworks/myvnet + type: Azure + release: + image: registry.ci.openshift.org/ocp:1.23 + replicas: 2 diff --git a/test/performance/pkg/hub/workloads/manifests/aro-hcp/manifestwork.namespace.yaml b/test/performance/pkg/hub/workloads/manifests/aro-hcp/manifestwork.namespace.yaml new file mode 100644 index 00000000..45071425 --- /dev/null +++ b/test/performance/pkg/hub/workloads/manifests/aro-hcp/manifestwork.namespace.yaml @@ -0,0 +1,24 @@ +apiVersion: work.open-cluster-management.io/v1 +kind: ManifestWork +metadata: + annotations: + hypershift-deployment.open-cluster-management.io/created-by: ignore/ignore + name: {{ .Name }}-namespace + namespace: {{ .ClusterName }} + labels: + api.openshift.com/environment: maestro-perf-test + api.openshift.com/id: {{ .Name }} + api.openshift.com/legal-entity-id: {{ .Name }} + api.openshift.com/name: {{ .Name }} + api.openshift.com/management-cluster: {{ .ClusterName }} + containsNamespaces: "true" +spec: + deleteOption: + propagationPolicy: Foreground + workload: + manifests: + - apiVersion: v1 + kind: Namespace + metadata: + name: {{ .Name }} + spec: {} diff --git a/test/performance/pkg/hub/workloads/workload.aro-hcp.go b/test/performance/pkg/hub/workloads/workload.aro-hcp.go new file mode 100644 index 00000000..0f34b2b5 --- /dev/null +++ b/test/performance/pkg/hub/workloads/workload.aro-hcp.go @@ -0,0 +1,189 @@ +package workloads + +import ( + "embed" + "fmt" + + "github.com/openshift-online/maestro/test/performance/pkg/util" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/rand" + "k8s.io/apimachinery/pkg/util/uuid" + workv1 "open-cluster-management.io/api/work/v1" +) + +//go:embed manifests +var ManifestFiles embed.FS + +var aroHCPWorkloadFiles = []string{ + "manifests/aro-hcp/managedcluster.yaml", + "manifests/aro-hcp/manifestwork.namespace.yaml", + "manifests/aro-hcp/manifestwork.hypershift.yaml", +} + +func ToAROHCPManifestWorks(clusterName string) ([]*workv1.ManifestWork, error) { + works := []*workv1.ManifestWork{} + + cluster := string(uuid.NewUUID()) + clusterManifest, err := toManifest(clusterName, cluster, aroHCPWorkloadFiles[0]) + if err != nil { + return nil, err + } + + work := string(uuid.NewUUID()) + namespace := fmt.Sprintf("%s-ns", work) + namespaceManifest, err := toManifest(clusterName, namespace, aroHCPWorkloadFiles[1]) + if err != nil { + return nil, err + } + + hypershift := fmt.Sprintf("%s-hs", work) + hypershiftManifest, err := toManifest(clusterName, hypershift, aroHCPWorkloadFiles[2]) + if err != nil { + return nil, err + } + + works = append(works, &workv1.ManifestWork{ + ObjectMeta: metav1.ObjectMeta{ + Name: cluster, + Namespace: clusterName, + Labels: map[string]string{ + "maestro.performance.test": "mc", + "cluster.maestro.performance.test": clusterName, + }, + }, + Spec: workv1.ManifestWorkSpec{ + Workload: workv1.ManifestsTemplate{ + Manifests: []workv1.Manifest{ + { + RawExtension: runtime.RawExtension{Raw: clusterManifest}, + }, + }, + }, + ManifestConfigs: []workv1.ManifestConfigOption{ + { + FeedbackRules: []workv1.FeedbackRule{ + { + Type: workv1.JSONPathsType, + JsonPaths: []workv1.JsonPath{ + { + Name: "status", + Path: ".status", + }, + }, + }, + }, + ResourceIdentifier: workv1.ResourceIdentifier{ + Name: cluster, + Group: "cluster.open-cluster-management.io", + Resource: "managedclusters", + }, + }, + }, + }, + }) + works = append(works, &workv1.ManifestWork{ + ObjectMeta: metav1.ObjectMeta{ + Name: work, + Namespace: clusterName, + Labels: map[string]string{ + "maestro.performance.test": "hypershift", + "cluster.maestro.performance.test": clusterName, + }, + }, + Spec: workv1.ManifestWorkSpec{ + Workload: workv1.ManifestsTemplate{ + Manifests: []workv1.Manifest{ + { + RawExtension: runtime.RawExtension{Raw: namespaceManifest}, + }, + { + RawExtension: runtime.RawExtension{Raw: hypershiftManifest}, + }, + }, + }, + ManifestConfigs: []workv1.ManifestConfigOption{ + { + FeedbackRules: []workv1.FeedbackRule{ + { + Type: workv1.JSONPathsType, + JsonPaths: []workv1.JsonPath{ + { + Name: "status", + Path: ".status", + }, + }, + }, + }, + ResourceIdentifier: workv1.ResourceIdentifier{ + Name: fmt.Sprintf("%s-namespace", namespace), + Namespace: clusterName, + Group: "work.open-cluster-management.io", + Resource: "manifestworks", + }, + }, + { + FeedbackRules: []workv1.FeedbackRule{ + { + Type: workv1.JSONPathsType, + JsonPaths: []workv1.JsonPath{ + { + Name: "status", + Path: ".status", + }, + }, + }, + }, + ResourceIdentifier: workv1.ResourceIdentifier{ + Name: fmt.Sprintf("%s-hypershift", hypershift), + Namespace: clusterName, + Group: "work.open-cluster-management.io", + Resource: "manifestworks", + }, + }, + }, + }, + }) + + return works, nil +} + +func toManifest(clusterName, name, file string) ([]byte, error) { + data, err := ManifestFiles.ReadFile(file) + if err != nil { + return nil, err + } + + raw, err := util.Render( + file, + data, + &struct { + Name string + ClusterName string + DockerConfigJSON string + IDRsa string + IDRsaPub string + SecretKey string + HTPasswd string + AzureClientInfo string + SubID string + BaseDomain string + }{ + Name: name, + ClusterName: clusterName, + DockerConfigJSON: rand.String(236), + IDRsa: rand.String(2272), + IDRsaPub: rand.String(604), + SecretKey: rand.String(44), + HTPasswd: rand.String(92), + AzureClientInfo: rand.String(52), + SubID: string(uuid.NewUUID()), + BaseDomain: "az.test.red-chesterfield-test.com", + }, + ) + if err != nil { + return nil, err + } + + return raw, nil +} diff --git a/test/performance/pkg/spoke/spoke.aro-hcp.go b/test/performance/pkg/spoke/spoke.aro-hcp.go new file mode 100644 index 00000000..f971e7cb --- /dev/null +++ b/test/performance/pkg/spoke/spoke.aro-hcp.go @@ -0,0 +1,130 @@ +package spoke + +import ( + "context" + "fmt" + "path/filepath" + "time" + + "github.com/spf13/pflag" + + "github.com/openshift/library-go/pkg/controller/controllercmd" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/uuid" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog/v2" + + ocmfeature "open-cluster-management.io/api/feature" + commonoptions "open-cluster-management.io/ocm/pkg/common/options" + "open-cluster-management.io/ocm/pkg/features" + "open-cluster-management.io/ocm/pkg/work/spoke" + + "github.com/openshift-online/maestro/test/performance/pkg/util" +) + +type AROHCPSpokeOptions struct { + AgentConfigDir string + + HubKubeConfigPath string + SpokeKubeConfigPath string + + MaestroNamespace string + + ClusterBeginIndex int + ClusterCounts int +} + +func NewAROHCPSpokeOptions() *AROHCPSpokeOptions { + return &AROHCPSpokeOptions{ + MaestroNamespace: "maestro", + ClusterBeginIndex: 0, + ClusterCounts: 1, + } +} + +func (o *AROHCPSpokeOptions) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&o.AgentConfigDir, "agent-config-dir", o.AgentConfigDir, "The dir to save the agent configs") + fs.StringVar(&o.HubKubeConfigPath, "hub-kubeconfig", o.HubKubeConfigPath, "Location of the Hub kubeconfig") + fs.StringVar(&o.SpokeKubeConfigPath, "spoke-kubeconfig", o.SpokeKubeConfigPath, "Location of the Spoke kubeconfig") + fs.IntVar(&o.ClusterBeginIndex, "cluster-begin-index", o.ClusterBeginIndex, "Begin index of the clusters") + fs.IntVar(&o.ClusterCounts, "cluster-counts", o.ClusterCounts, "Counts of the clusters") +} + +func (o *AROHCPSpokeOptions) Run(ctx context.Context) error { + spokeKubeConfig, err := clientcmd.BuildConfigFromFlags("", o.SpokeKubeConfigPath) + if err != nil { + return err + } + + spokeKubeClient, err := kubernetes.NewForConfig(spokeKubeConfig) + if err != nil { + return err + } + + // start agents + utilruntime.Must(features.SpokeMutableFeatureGate.Add(ocmfeature.DefaultSpokeWorkFeatureGates)) + utilruntime.Must(features.SpokeMutableFeatureGate.Set(fmt.Sprintf("%s=true", ocmfeature.RawFeedbackJsonString))) + + index := o.ClusterBeginIndex + for i := 0; i < o.ClusterCounts; i++ { + clusterName := util.ClusterName(index) + + _, err := spokeKubeClient.CoreV1().Namespaces().Get(ctx, clusterName, metav1.GetOptions{}) + switch { + case errors.IsNotFound(err): + if _, err := spokeKubeClient.CoreV1().Namespaces().Create( + ctx, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: clusterName, + }, + }, + metav1.CreateOptions{}, + ); err != nil { + return err + } + case err != nil: + return err + } + + klog.Infof("The namespace of cluster %s is created", clusterName) + + go func() { + klog.Infof("Starting the work agent for cluster %s", clusterName) + if err := o.startWorkAgent(ctx, spokeKubeConfig, clusterName); err != nil { + klog.Errorf("failed to start work agent for cluster %s, %v", clusterName, err) + } + }() + + index = index + 1 + } + + return nil +} + +func (o *AROHCPSpokeOptions) startWorkAgent(ctx context.Context, kubeConfig *rest.Config, clusterName string) error { + commonOptions := commonoptions.NewAgentOptions() + commonOptions.AgentID = string(uuid.NewUUID()) + commonOptions.SpokeClusterName = clusterName + + agentOptions := spoke.NewWorkloadAgentOptions() + agentOptions.StatusSyncInterval = 3 * time.Second + agentOptions.AppliedManifestWorkEvictionGracePeriod = 5 * time.Second + agentOptions.MaxJSONRawLength = 1024 * 1024 // 1M + agentOptions.WorkloadSourceDriver = "mqtt" + agentOptions.WorkloadSourceConfig = filepath.Join(o.AgentConfigDir, fmt.Sprintf("%s-config.yaml", clusterName)) + agentOptions.CloudEventsClientID = fmt.Sprintf("%s-agent", clusterName) + agentOptions.CloudEventsClientCodecs = []string{"manifestbundle"} + + agentConfig := spoke.NewWorkAgentConfig(commonOptions, agentOptions) + return agentConfig.RunWorkloadAgent(ctx, &controllercmd.ControllerContext{ + KubeConfig: kubeConfig, + EventRecorder: util.NewRecorder(clusterName), + }) +} diff --git a/test/performance/pkg/util/events.go b/test/performance/pkg/util/events.go new file mode 100644 index 00000000..d4da1365 --- /dev/null +++ b/test/performance/pkg/util/events.go @@ -0,0 +1,54 @@ +package util + +import ( + "context" + "fmt" + + "github.com/openshift/library-go/pkg/operator/events" + "k8s.io/klog/v2" +) + +type eventRecorder struct { + source string +} + +func NewRecorder(sourceComponent string) events.Recorder { + return &eventRecorder{source: sourceComponent} +} + +func (r *eventRecorder) ComponentName() string { + return r.source +} + +func (r *eventRecorder) Shutdown() {} + +func (r *eventRecorder) ForComponent(component string) events.Recorder { + // do nothing + return r +} + +func (r *eventRecorder) WithContext(ctx context.Context) events.Recorder { + // do nothing + return r +} + +func (r *eventRecorder) WithComponentSuffix(suffix string) events.Recorder { + // do nothing + return r +} + +func (r *eventRecorder) Event(reason, message string) { + klog.V(4).Infof("[%s] reason=%s, message=%s", r.source, reason, message) +} + +func (r *eventRecorder) Eventf(reason, messageFmt string, args ...interface{}) { + r.Event(reason, fmt.Sprintf(messageFmt, args...)) +} + +func (r *eventRecorder) Warning(reason, message string) { + klog.V(2).Infof("[%s] reason=%s, message=%s", r.source, reason, message) +} + +func (r *eventRecorder) Warningf(reason, messageFmt string, args ...interface{}) { + r.Warning(reason, fmt.Sprintf(messageFmt, args...)) +} diff --git a/test/performance/pkg/util/util.go b/test/performance/pkg/util/util.go new file mode 100644 index 00000000..e5a124b6 --- /dev/null +++ b/test/performance/pkg/util/util.go @@ -0,0 +1,115 @@ +package util + +import ( + "bytes" + "context" + "fmt" + "html/template" + "net/http" + "runtime" + "time" + + "github.com/openshift-online/maestro/pkg/api/openapi" + "k8s.io/klog/v2" + "sigs.k8s.io/yaml" +) + +const clusterNamePrefix = "maestro-cluster" + +type Func func() error + +func ClusterName(index int) string { + return fmt.Sprintf("%s-%d", clusterNamePrefix, index) +} + +func UsedTime(start time.Time, unit time.Duration) time.Duration { + used := time.Since(start) + return used / unit +} + +func Eventually(fn Func, timeout time.Duration, interval time.Duration) error { + after := time.After(timeout) + + tick := time.NewTicker(interval) + defer tick.Stop() + + var err error + for { + select { + case <-after: + return fmt.Errorf("timeout with error %v", err) + case <-tick.C: + err = fn() + + if err == nil { + return nil + } + } + } +} + +func Render(name string, data []byte, config interface{}) ([]byte, error) { + tmpl, err := template.New(name).Parse(string(data)) + if err != nil { + return nil, err + } + + var buf bytes.Buffer + if err := tmpl.Execute(&buf, config); err != nil { + return nil, err + } + + return yaml.YAMLToJSON(buf.Bytes()) +} + +func NewMaestroAPIClient(maestroServerAddress string) *openapi.APIClient { + cfg := &openapi.Configuration{ + DefaultHeader: make(map[string]string), + UserAgent: "OpenAPI-Generator/1.0.0/go", + Debug: false, + Servers: openapi.ServerConfigurations{ + { + URL: maestroServerAddress, + Description: "current domain", + }, + }, + OperationServers: map[string]openapi.ServerConfigurations{}, + HTTPClient: &http.Client{ + Timeout: 10 * time.Second, + }, + } + return openapi.NewAPIClient(cfg) +} + +func CreateConsumer(ctx context.Context, client *openapi.APIClient, consumerName string) error { + _, _, err := client.DefaultApi.ApiMaestroV1ConsumersPost(ctx). + Consumer(openapi.Consumer{Name: openapi.PtrString(consumerName)}). + Execute() + return err +} + +func MonitorMem(ctx context.Context) { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + printMemUsage() + } + } +} + +func printMemUsage() { + var m runtime.MemStats + runtime.ReadMemStats(&m) + // For info on each, see: https://golang.org/pkg/runtime/#MemStats + klog.Infof("#### Alloc=%d,TotalAlloc=%d,Sys=%d,NumGC=%d", + bToMb(m.Alloc), bToMb(m.TotalAlloc), bToMb(m.Sys), m.NumGC) +} + +func bToMb(b uint64) uint64 { + return b / 1024 / 1024 +} diff --git a/test/performance/pkg/watcher/hypershift.go b/test/performance/pkg/watcher/hypershift.go new file mode 100644 index 00000000..70566a47 --- /dev/null +++ b/test/performance/pkg/watcher/hypershift.go @@ -0,0 +1,313 @@ +package watcher + +// Conditions. +const ( + // HostedClusterAvailable indicates whether the HostedCluster has a healthy + // control plane. + // When this is false for too long and there's no clear indication in the "Reason", please check the remaining more granular conditions. + HostedClusterAvailable = "Available" + // HostedClusterProgressing indicates whether the HostedCluster is attempting + // an initial deployment or upgrade. + // When this is false for too long and there's no clear indication in the "Reason", please check the remaining more granular conditions. + HostedClusterProgressing = "Progressing" + // HostedClusterDegraded indicates whether the HostedCluster is encountering + // an error that may require user intervention to resolve. + HostedClusterDegraded = "Degraded" + + // Bubble up from HCP. + + // InfrastructureReady bubbles up the same condition from HCP. It signals if the infrastructure for a control plane to be operational, + // e.g. load balancers were created successfully. + // A failure here may require external user intervention to resolve. E.g. hitting quotas on the cloud provider. + InfrastructureReady = "InfrastructureReady" + // KubeAPIServerAvailable bubbles up the same condition from HCP. It signals if the kube API server is available. + // A failure here often means a software bug or a non-stable cluster. + KubeAPIServerAvailable = "KubeAPIServerAvailable" + // EtcdAvailable bubbles up the same condition from HCP. It signals if etcd is available. + // A failure here often means a software bug or a non-stable cluster. + EtcdAvailable = "EtcdAvailable" + // ValidHostedControlPlaneConfiguration bubbles up the same condition from HCP. It signals if the hostedControlPlane input is valid and + // supported by the underlying management cluster. + // A failure here is unlikely to resolve without the changing user input. + ValidHostedControlPlaneConfiguration = "ValidHostedControlPlaneConfiguration" + // CloudResourcesDestroyed bubbles up the same condition from HCP. It signals if the cloud provider infrastructure created by Kubernetes + // in the consumer cloud provider account was destroyed. + // A failure here may require external user intervention to resolve. E.g. cloud provider perms were corrupted. E.g. the guest cluster was broken + // and kube resource deletion that affects cloud infra like service type load balancer can't succeed. + CloudResourcesDestroyed = "CloudResourcesDestroyed" + // HostedClusterDestroyed indicates that a hosted has finished destroying and that it is waiting for a destroy grace period to go away. + // The grace period is determined by the hypershift.openshift.io/destroy-grace-period annotation in the HostedCluster if present. + HostedClusterDestroyed = "HostedClusterDestroyed" + // ExternalDNSReachable bubbles up the same condition from HCP. It signals if the configured external DNS is reachable. + // A failure here requires external user intervention to resolve. E.g. changing the external DNS domain or making sure the domain is created + // and registered correctly. + ExternalDNSReachable = "ExternalDNSReachable" + // ValidReleaseInfo bubbles up the same condition from HCP. It indicates if the release contains all the images used by hypershift + // and reports missing images if any. + ValidReleaseInfo = "ValidReleaseInfo" + + // Bubble up from HCP which bubbles up from CVO. + + // ClusterVersionSucceeding indicates the current status of the desired release + // version of the HostedCluster as indicated by the Failing condition in the + // underlying cluster's ClusterVersion. + ClusterVersionSucceeding = "ClusterVersionSucceeding" + // ClusterVersionUpgradeable indicates the Upgradeable condition in the + // underlying cluster's ClusterVersion. + ClusterVersionUpgradeable = "ClusterVersionUpgradeable" + // ClusterVersionFailing bubbles up Failing from the CVO. + ClusterVersionFailing = "ClusterVersionFailing" + // ClusterVersionProgressing bubbles up configv1.OperatorProgressing from the CVO. + ClusterVersionProgressing = "ClusterVersionProgressing" + // ClusterVersionAvailable bubbles up Failing configv1.OperatorAvailable from the CVO. + ClusterVersionAvailable = "ClusterVersionAvailable" + // ClusterVersionReleaseAccepted bubbles up Failing ReleaseAccepted from the CVO. + ClusterVersionReleaseAccepted = "ClusterVersionReleaseAccepted" + + // UnmanagedEtcdAvailable indicates whether a user-managed etcd cluster is + // healthy. + UnmanagedEtcdAvailable = "UnmanagedEtcdAvailable" + + // IgnitionEndpointAvailable indicates whether the ignition server for the + // HostedCluster is available to handle ignition requests. + // A failure here often means a software bug or a non-stable cluster. + IgnitionEndpointAvailable = "IgnitionEndpointAvailable" + + // IgnitionServerValidReleaseInfo indicates if the release contains all the images used by the local ignition provider + // and reports missing images if any. + IgnitionServerValidReleaseInfo = "IgnitionServerValidReleaseInfo" + + // ValidHostedClusterConfiguration signals if the hostedCluster input is valid and + // supported by the underlying management cluster. + // A failure here is unlikely to resolve without the changing user input. + ValidHostedClusterConfiguration = "ValidConfiguration" + + // SupportedHostedCluster indicates whether a HostedCluster is supported by + // the current configuration of the hypershift-operator. + // e.g. If HostedCluster requests endpointAcess Private but the hypershift-operator + // is running on a management cluster outside AWS or is not configured with AWS + // credentials, the HostedCluster is not supported. + // A failure here is unlikely to resolve without the changing user input. + SupportedHostedCluster = "SupportedHostedCluster" + + // ValidOIDCConfiguration indicates if an AWS cluster's OIDC condition is + // detected as invalid. + // A failure here may require external user intervention to resolve. E.g. oidc was deleted out of band. + ValidOIDCConfiguration = "ValidOIDCConfiguration" + + // ValidReleaseImage indicates if the release image set in the spec is valid + // for the HostedCluster. For example, this can be set false if the + // HostedCluster itself attempts an unsupported version before 4.9 or an + // unsupported upgrade e.g y-stream upgrade before 4.11. + // A failure here is unlikely to resolve without the changing user input. + ValidReleaseImage = "ValidReleaseImage" + + // ValidKubeVirtInfraNetworkMTU indicates if the MTU configured on an infra cluster + // hosting a guest cluster utilizing kubevirt platform is a sufficient value that will avoid + // performance degradation due to fragmentation of the double encapsulation in ovn-kubernetes + ValidKubeVirtInfraNetworkMTU = "ValidKubeVirtInfraNetworkMTU" + + // ValidAWSIdentityProvider indicates if the Identity Provider referenced + // in the cloud credentials is healthy. E.g. for AWS the idp ARN is referenced in the iam roles. + // "Version": "2012-10-17", + // "Statement": [ + // { + // "Effect": "Allow", + // "Principal": { + // "Federated": "{{ .ProviderARN }}" + // }, + // "Action": "sts:AssumeRoleWithWebIdentity", + // "Condition": { + // "StringEquals": { + // "{{ .ProviderName }}:sub": {{ .ServiceAccounts }} + // } + // } + // } + // ] + // + // A failure here may require external user intervention to resolve. + ValidAWSIdentityProvider = "ValidAWSIdentityProvider" + + // ValidAWSKMSConfig indicates whether the AWS KMS role and encryption key are valid and operational + // A failure here indicates that the role or the key are invalid, or the role doesn't have access to use the key. + ValidAWSKMSConfig = "ValidAWSKMSConfig" + + // ValidAzureKMSConfig indicates whether the given KMS input for the Azure platform is valid and operational + // A failure here indicates that the input is invalid, or permissions are missing to use the encryption key. + ValidAzureKMSConfig = "ValidAzureKMSConfig" + + // AWSDefaultSecurityGroupCreated indicates whether the default security group + // for AWS workers has been created. + // A failure here indicates that NodePools without a security group will be + // blocked from creating machines. + AWSDefaultSecurityGroupCreated = "AWSDefaultSecurityGroupCreated" + + // AWSDefaultSecurityGroupDeleted indicates whether the default security group + // for AWS workers has been deleted. + // A failure here indicates that the Security Group has some dependencies that + // there are still pending cloud resources to be deleted that are using that SG. + AWSDefaultSecurityGroupDeleted = "AWSDefaultSecurityGroupDeleted" + + // PlatformCredentialsFound indicates that credentials required for the + // desired platform are valid. + // A failure here is unlikely to resolve without the changing user input. + PlatformCredentialsFound = "PlatformCredentialsFound" + + // ReconciliationActive indicates if reconciliation of the HostedCluster is + // active or paused hostedCluster.spec.pausedUntil. + ReconciliationActive = "ReconciliationActive" + // ReconciliationSucceeded indicates if the HostedCluster reconciliation + // succeeded. + // A failure here often means a software bug or a non-stable cluster. + ReconciliationSucceeded = "ReconciliationSucceeded" + + // ClusterSizeComputed indicates that a t-shirt size was computed for this HostedCluster. + // The last transition time for this condition is used to manage how quickly transitions occur. + ClusterSizeComputed = "ClusterSizeComputed" + // ClusterSizeTransitionPending indicates that a t-shirt size transition is pending, but has + // not been applied yet. This may either be due to transition delays on the cluster itself + // or from management-cluster-wide limits to transition throughput. + ClusterSizeTransitionPending = "ClusterSizeTransitionPending" + // ClusterSizeTransitionRequired exposes the next t-shirt size that the cluster will transition to. + ClusterSizeTransitionRequired = "ClusterSizeTransitionRequired" +) + +// Reasons. +const ( + StatusUnknownReason = "StatusUnknown" + AsExpectedReason = "AsExpected" + NotFoundReason = "NotFound" + WaitingForAvailableReason = "WaitingForAvailable" + SecretNotFoundReason = "SecretNotFound" + WaitingForGracePeriodReason = "WaitingForGracePeriod" + BlockedReason = "Blocked" + + InfraStatusFailureReason = "InfraStatusFailure" + WaitingOnInfrastructureReadyReason = "WaitingOnInfrastructureReady" + + EtcdQuorumAvailableReason = "QuorumAvailable" + EtcdWaitingForQuorumReason = "EtcdWaitingForQuorum" + EtcdStatefulSetNotFoundReason = "StatefulSetNotFound" + + UnmanagedEtcdMisconfiguredReason = "UnmanagedEtcdMisconfigured" + UnmanagedEtcdAsExpected = "UnmanagedEtcdAsExpected" + + FromClusterVersionReason = "FromClusterVersion" + + InvalidConfigurationReason = "InvalidConfiguration" + KubeconfigWaitingForCreateReason = "KubeconfigWaitingForCreate" + UnsupportedHostedClusterReason = "UnsupportedHostedCluster" + InsufficientClusterCapabilitiesReason = "InsufficientClusterCapabilities" + OIDCConfigurationInvalidReason = "OIDCConfigurationInvalid" + PlatformCredentialsNotFoundReason = "PlatformCredentialsNotFound" + InvalidImageReason = "InvalidImage" + InvalidIdentityProvider = "InvalidIdentityProvider" + + InvalidIAMRoleReason = "InvalidIAMRole" + + InvalidAzureCredentialsReason = "InvalidAzureCredentials" + AzureErrorReason = "AzureError" + + ExternalDNSHostNotReachableReason = "ExternalDNSHostNotReachable" + + KASLoadBalancerNotReachableReason = "KASLoadBalancerNotReachable" + + MissingReleaseImagesReason = "MissingReleaseImages" + + ReconciliationPausedConditionReason = "ReconciliationPaused" + ReconciliationInvalidPausedUntilConditionReason = "InvalidPausedUntilValue" + + KubeVirtSuboptimalMTUReason = "KubeVirtSuboptimalMTUDetected" +) + +// Messages. +const ( + // AllIsWellMessage is standard message. + AllIsWellMessage = "All is well" +) + +// Conditions +const ( + // NodePoolValidGeneratedPayload signals if the ignition sever generated an ignition payload successfully for Nodes in that pool. + // A failure here often means a software bug or a non-stable cluster. + NodePoolValidGeneratedPayload = "ValidGeneratedPayload" + // NodePoolValidPlatformImageType signals if an OS image e.g. an AMI was found successfully based on the consumer input e.g. releaseImage. + // If the image is direct user input then this condition is meaningless. + // A failure here is unlikely to resolve without the changing user input. + NodePoolValidPlatformImageType = "ValidPlatformImage" + // NodePoolValidReleaseImage signals if the input in nodePool.spec.release.image is valid. + // A failure here is unlikely to resolve without the changing user input. + NodePoolValidReleaseImage = "ValidReleaseImage" + // NodePoolValidMachineConfig signals if the content within nodePool.spec.config is valid. + // A failure here is unlikely to resolve without the changing user input. + NodePoolValidMachineConfig = "ValidMachineConfig" + // NodePoolValidTuningConfig signals if the content within nodePool.spec.tuningConfig is valid. + // A failure here is unlikely to resolve without the changing user input. + NodePoolValidTuningConfig = "ValidTuningConfig" + + // NodePoolUpdateManagementEnabled signals if the nodePool.spec.management input is valid. + // A failure here is unlikely to resolve without the changing user input. + NodePoolUpdateManagementEnabled = "UpdateManagementEnabled" + // NodePoolAutoscalingEnabled signals if nodePool.spec.replicas and nodePool.spec.AutoScaling input is valid. + // A failure here is unlikely to resolve without the changing user input. + NodePoolAutoscalingEnabled = "AutoscalingEnabled" + // NodePoolAutorepairEnabled signals if MachineHealthChecks resources were created successfully. + // A failure here often means a software bug or a non-stable cluster. + NodePoolAutorepairEnabled = "AutorepairEnabled" + + // NodePoolUpdatingVersion signals if a version update is currently happening in NodePool. + NodePoolUpdatingVersion = "UpdatingVersion" + // NodePoolUpdatingConfig signals if a config update is currently happening in NodePool. + NodePoolUpdatingConfig = "UpdatingConfig" + // NodePoolUpdatingPlatformMachineTemplate signals if a platform machine template update is currently happening in NodePool. + NodePoolUpdatingPlatformMachineTemplate = "UpdatingPlatformMachineTemplate" + // NodePoolReady bubbles up CAPI MachineDeployment/MachineSet Ready condition. + // This is true when all replicas are ready Nodes. + // When this is false for too long, NodePoolAllMachinesReady and NodePoolAllNodesHealthy might provide more context. + NodePoolReady = "Ready" + // NodePoolAllMachinesReady bubbles up and aggregates CAPI Machine Ready condition. + // It signals when the infrastructure for a Machine resource was created successfully. + // https://github.com/kubernetes-sigs/cluster-api/blob/main/api/v1beta1/condition_consts.go + // A failure here may require external user intervention to resolve. E.g. hitting quotas on the cloud provider. + NodePoolAllMachinesReady = "AllMachinesReady" + // NodePoolAllNodesHealthy bubbles up and aggregates CAPI NodeHealthy condition. + // It signals when the Node for a Machine resource is healthy. + // https://github.com/kubernetes-sigs/cluster-api/blob/main/api/v1beta1/condition_consts.go + // A failure here often means a software bug or a non-stable cluster. + NodePoolAllNodesHealthy = "AllNodesHealthy" + + // NodePoolReconciliationActive signals the state of nodePool.spec.pausedUntil. + NodePoolReconciliationActive = "ReconciliationActive" + + // NodePoolReachedIgnitionEndpoint signals if at least an instance was able to reach the ignition endpoint to get the payload. + // When this is false for too long it may require external user intervention to resolve. E.g. Enable AWS security groups to enable networking access. + NodePoolReachedIgnitionEndpoint = "ReachedIgnitionEndpoint" + + // NodePoolAWSSecurityGroupAvailable signals whether the NodePool has an available security group to use. + // If the security group is specified for the NodePool, this condition is always true. If no security group is specified + // for the NodePool, the status of this condition depends on the availability of the default security group in the HostedCluster. + NodePoolAWSSecurityGroupAvailable = "AWSSecurityGroupAvailable" + + // NodePoolValidMachineTemplate signal that the machine template created by the node pool is valid + NodePoolValidMachineTemplate = "ValidMachineTemplate" + + // NodePoolClusterNetworkCIDRConflictType signals if a NodePool's machine objects are colliding with the + // cluster network's CIDR range. This can indicate why some network functionality might be degraded. + NodePoolClusterNetworkCIDRConflictType = "ClusterNetworkCIDRConflict" +) + +// Reasons +const ( + NodePoolValidationFailedReason = "ValidationFailed" + NodePoolInplaceUpgradeFailedReason = "InplaceUpgradeFailed" + NodePoolNotFoundReason = "NotFound" + NodePoolFailedToGetReason = "FailedToGet" + IgnitionEndpointMissingReason = "IgnitionEndpointMissing" + IgnitionCACertMissingReason = "IgnitionCACertMissing" + IgnitionNotReached = "ignitionNotReached" + DefaultAWSSecurityGroupNotReadyReason = "DefaultSGNotReady" + NodePoolValidArchPlatform = "ValidArchPlatform" + NodePoolInvalidArchPlatform = "InvalidArchPlatform" + InvalidKubevirtMachineTemplate = "InvalidKubevirtMachineTemplate" + CIDRConflictReason = "CIDRConflict" +) diff --git a/test/performance/pkg/watcher/watcher.aro-hpc.go b/test/performance/pkg/watcher/watcher.aro-hpc.go new file mode 100644 index 00000000..8df37e4e --- /dev/null +++ b/test/performance/pkg/watcher/watcher.aro-hpc.go @@ -0,0 +1,624 @@ +package watcher + +import ( + "context" + "encoding/json" + "strings" + "sync" + "time" + + "github.com/spf13/pflag" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog/v2" + + clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" + workclientset "open-cluster-management.io/api/client/work/clientset/versioned" + clusterv1 "open-cluster-management.io/api/cluster/v1" + workv1 "open-cluster-management.io/api/work/v1" + + "github.com/openshift-online/maestro/test/performance/pkg/util" +) + +type AROHCPWatcherOptions struct { + sync.RWMutex + + SpokeKubeConfigPath string + Index int + Totals int + + clusterTotals int + workTotals int +} + +func NewAROHCPWatcherOptions() *AROHCPWatcherOptions { + return &AROHCPWatcherOptions{ + Index: 1, + Totals: 1, + clusterTotals: 0, + workTotals: 0, + } +} + +func (o *AROHCPWatcherOptions) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&o.SpokeKubeConfigPath, "spoke-kubeconfig", o.SpokeKubeConfigPath, "Location of the Spoke kubeconfig") + fs.IntVar(&o.Index, "clusters-index", o.Index, "The begin index of clusters") + fs.IntVar(&o.Totals, "clusters-counts", o.Totals, "The counts of clusters") +} + +func (o *AROHCPWatcherOptions) Run(ctx context.Context) error { + spokeKubeConfig, err := clientcmd.BuildConfigFromFlags("", o.SpokeKubeConfigPath) + if err != nil { + return err + } + + clusterClient, err := clusterclientset.NewForConfig(spokeKubeConfig) + if err != nil { + return err + } + + workClient, err := workclientset.NewForConfig(spokeKubeConfig) + if err != nil { + return err + } + + clusterWatcher, err := clusterClient.ClusterV1().ManagedClusters().Watch(ctx, metav1.ListOptions{}) + if err != nil { + return err + } + + go func() { + klog.Infof("watching clusters ....") + + ch := clusterWatcher.ResultChan() + for { + select { + case <-ctx.Done(): + return + case event, ok := <-ch: + if !ok { + return + } + switch event.Type { + case watch.Added: + startTime := time.Now() + obj, err := meta.Accessor(event.Object) + if err != nil { + klog.Fatal(err) + } + + cluster, err := clusterClient.ClusterV1().ManagedClusters().Get(ctx, obj.GetName(), metav1.GetOptions{}) + if err != nil { + klog.Errorf("error to get cluster: %v, %v", obj.GetName(), err) + continue + } + + if meta.IsStatusConditionTrue(cluster.Status.Conditions, clusterv1.ManagedClusterConditionHubAccepted) { + continue + } + + conditions := []metav1.Condition{} + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: clusterv1.ManagedClusterConditionHubAccepted, + Status: metav1.ConditionTrue, + Reason: "HubClusterAdminAccepted", + Message: "Accepted by hub cluster admin", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: clusterv1.ManagedClusterConditionJoined, + Status: metav1.ConditionTrue, + Reason: "ManagedClusterJoined", + Message: "Managed cluster joined", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: clusterv1.ManagedClusterConditionAvailable, + Status: metav1.ConditionTrue, + Reason: "ManagedClusterAvailable", + Message: "Managed cluster is available", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: clusterv1.ManagedClusterConditionClockSynced, + Status: metav1.ConditionTrue, + Reason: "ManagedClusterClockSynced", + Message: "The clock of the managed cluster is synced with the hub.", + }) + + cluster.Status.Conditions = conditions + cluster.Status.Capacity = clusterv1.ResourceList{ + clusterv1.ResourceCPU: *resource.NewQuantity(int64(32), resource.DecimalExponent), + clusterv1.ResourceMemory: *resource.NewQuantity(int64(1024*1024*64), resource.BinarySI), + } + cluster.Status.Allocatable = clusterv1.ResourceList{ + clusterv1.ResourceCPU: *resource.NewQuantity(int64(16), resource.DecimalExponent), + clusterv1.ResourceMemory: *resource.NewQuantity(int64(1024*1024*32), resource.BinarySI), + } + cluster.Status.Version = clusterv1.ManagedClusterVersion{ + Kubernetes: "1.22", + } + + _, err = clusterClient.ClusterV1().ManagedClusters().UpdateStatus(ctx, cluster, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("error to update cluster: %v, %v", obj.GetName(), err) + continue + } + + o.clusterTotals = o.clusterTotals + 1 + klog.Infof("cluster %v is updated, total=%d, time=%d", obj.GetName(), o.clusterTotals, util.UsedTime(startTime, time.Millisecond)) + } + } + } + }() + + index := o.Index + for i := 1; i <= o.Totals; i++ { + name := util.ClusterName(index) + klog.Infof("watching works for %s ....", name) + workWatcher, err := workClient.WorkV1().ManifestWorks(name).Watch(ctx, metav1.ListOptions{}) + if err != nil { + return err + } + + go func() { + ch := workWatcher.ResultChan() + for { + select { + case <-ctx.Done(): + return + case event, ok := <-ch: + if !ok { + return + } + switch event.Type { + case watch.Added: + startTime := time.Now() + obj, err := meta.Accessor(event.Object) + if err != nil { + klog.Fatal(err) + } + + work, err := workClient.WorkV1().ManifestWorks(obj.GetNamespace()).Get(ctx, obj.GetName(), metav1.GetOptions{}) + if err != nil { + klog.Errorf("error to get work: %v/%v, %v", obj.GetNamespace(), obj.GetName(), err) + continue + } + + conditions := []metav1.Condition{} + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: workv1.ManifestApplied, + Status: metav1.ConditionTrue, + Reason: "AppliedManifestComplete", + Message: "Apply manifest complete", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: workv1.ManifestAvailable, + Status: metav1.ConditionTrue, + Reason: "ResourceAvailable", + Message: "Resource is available", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: "StatusFeedbackSynced", + Status: metav1.ConditionTrue, + Reason: "StatusFeedbackSynced", + Message: "", + }) + + work.Status.Conditions = conditions + + var jsonRaw string + if strings.HasSuffix(obj.GetName(), "namespace") { + jsonRaw = toNamespaceJsonRaw(obj.GetName()) + + } + + if strings.HasSuffix(obj.GetName(), "hypershift") { + jsonRaw = toHyperShiftJsonRaw(obj.GetName()) + } + + work.Status.ResourceStatus = workv1.ManifestResourceStatus{ + Manifests: []workv1.ManifestCondition{ + { + ResourceMeta: workv1.ManifestResourceMeta{ + Ordinal: 0, + Group: "work.open-cluster-management.io", + Resource: "manifestworks", + Kind: "ManifestWork", + Version: "v1", + Name: work.Name, + Namespace: work.Namespace, + }, + StatusFeedbacks: workv1.StatusFeedbackResult{ + Values: []workv1.FeedbackValue{ + { + Name: "status", + Value: workv1.FieldValue{ + Type: workv1.JsonRaw, + JsonRaw: &jsonRaw, + }, + }, + }, + }, + }, + }, + } + + _, err = workClient.WorkV1().ManifestWorks(obj.GetNamespace()).UpdateStatus(ctx, work, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("error to update work: %v/%v, %v", obj.GetNamespace(), obj.GetName(), err) + continue + } + + o.addWorks() + klog.Infof("work %v/%v is updated, total=%d, time=%d", obj.GetNamespace(), obj.GetName(), o.getWorks(), util.UsedTime(startTime, time.Millisecond)) + } + } + } + }() + + index = index + 1 + } + + return nil +} + +func toNamespaceJsonRaw(namespace string) string { + conditions := []metav1.Condition{} + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: workv1.ManifestApplied, + Status: metav1.ConditionTrue, + Reason: "AppliedManifestComplete", + Message: "Apply manifest complete", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: workv1.ManifestAvailable, + Status: metav1.ConditionTrue, + Reason: "ResourceAvailable", + Message: "Resource is available", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: "StatusFeedbackSynced", + Status: metav1.ConditionTrue, + Reason: "NoStatusFeedbackSynced", + Message: "", + }) + + resourceStatus := &workv1.ManifestCondition{ + ResourceMeta: workv1.ManifestResourceMeta{ + Ordinal: 0, + Group: "", + Resource: "namespaces", + Kind: "Namespace", + Version: "v1", + Name: namespace, + }, + Conditions: conditions, + } + + data, err := json.Marshal(resourceStatus) + if err != nil { + klog.Fatal(err) + } + return string(data) +} + +func toHyperShiftJsonRaw(name string) string { + conditions := []metav1.Condition{} + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: workv1.ManifestApplied, + Status: metav1.ConditionTrue, + Reason: "AppliedManifestComplete", + Message: "Apply manifest complete", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: workv1.ManifestAvailable, + Status: metav1.ConditionTrue, + Reason: "ResourceAvailable", + Message: "Resource is available", + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: "StatusFeedbackSynced", + Status: metav1.ConditionTrue, + Reason: "StatusFeedbackSynced", + Message: "", + }) + + resourceStatus := &workv1.ManifestResourceStatus{ + Manifests: []workv1.ManifestCondition{}, + } + + for i := 0; i < 5; i++ { + resourceStatus.Manifests = append(resourceStatus.Manifests, workv1.ManifestCondition{ + Conditions: conditions, + ResourceMeta: workv1.ManifestResourceMeta{ + Ordinal: int32(i), + Group: "", + Resource: "secrets", + Kind: "Secret", + Version: "v1", + Name: name, + Namespace: name, + }, + }) + } + jsonRaw := hostedConditions() + resourceStatus.Manifests = append(resourceStatus.Manifests, workv1.ManifestCondition{ + Conditions: conditions, + ResourceMeta: workv1.ManifestResourceMeta{ + Ordinal: 5, + Group: "hypershift.openshift.io", + Resource: "hostedclusters", + Kind: "HostedCluster", + Version: "v1beta1", + Name: name, + Namespace: name, + }, + StatusFeedbacks: workv1.StatusFeedbackResult{ + Values: []workv1.FeedbackValue{ + { + Name: "status", + Value: workv1.FieldValue{ + Type: workv1.JsonRaw, + JsonRaw: &jsonRaw, + }, + }, + }, + }, + }) + + jsonRaw = nodePoolConditions() + resourceStatus.Manifests = append(resourceStatus.Manifests, workv1.ManifestCondition{ + Conditions: conditions, + ResourceMeta: workv1.ManifestResourceMeta{ + Ordinal: 6, + Group: "hypershift.openshift.io", + Resource: "nodepools", + Kind: "NodePool", + Version: "v1beta1", + Name: name, + Namespace: name, + }, + StatusFeedbacks: workv1.StatusFeedbackResult{ + Values: []workv1.FeedbackValue{ + { + Name: "status", + Value: workv1.FieldValue{ + Type: workv1.JsonRaw, + JsonRaw: &jsonRaw, + }, + }, + }, + }, + }) + + data, err := json.Marshal(resourceStatus) + if err != nil { + klog.Fatal(err) + } + return string(data) +} + +func (o *AROHCPWatcherOptions) addWorks() { + o.Lock() + defer o.Unlock() + + o.workTotals = o.workTotals + 1 +} + +func (o *AROHCPWatcherOptions) getWorks() int { + o.RLock() + defer o.RUnlock() + + return o.workTotals +} + +func hostedConditions() string { + conditions := []metav1.Condition{} + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: HostedClusterAvailable, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: HostedClusterProgressing, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: HostedClusterDegraded, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: InfrastructureReady, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: KubeAPIServerAvailable, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: EtcdAvailable, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ValidHostedControlPlaneConfiguration, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: CloudResourcesDestroyed, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: HostedClusterDestroyed, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ExternalDNSReachable, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ValidReleaseInfo, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionSucceeding, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionUpgradeable, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionFailing, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionProgressing, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionProgressing, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionProgressing, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionAvailable, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionReleaseAccepted, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ClusterVersionProgressing, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: UnmanagedEtcdAvailable, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: IgnitionEndpointAvailable, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: IgnitionServerValidReleaseInfo, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: SupportedHostedCluster, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ValidOIDCConfiguration, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ValidReleaseImage, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ValidAzureKMSConfig, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: PlatformCredentialsFound, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ReconciliationActive, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: ReconciliationSucceeded, + Status: metav1.ConditionTrue, + }) + + status := map[string]string{} + for _, c := range conditions { + status[c.Type+"-Status"] = string(c.Status) + status[c.Type+"-Message"] = c.Type + status[c.Type+"-Reason"] = c.Type + status[c.Type+"-LastTransitionTime"] = c.LastTransitionTime.Format("2006-01-02 15:04:05") + } + status["progress"] = "progress" + status["Version-Desired"] = "1.22" + status["Image-Current"] = "test-image" + status["Version-Current"] = "1.22" + status["Version-Status"] = "equals" + + data, err := json.Marshal(status) + if err != nil { + klog.Fatal(err) + } + return string(data) +} + +func nodePoolConditions() string { + conditions := []metav1.Condition{} + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolValidPlatformImageType, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolValidMachineConfig, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolValidTuningConfig, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolUpdateManagementEnabled, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolAutoscalingEnabled, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolReady, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolReconciliationActive, + Status: metav1.ConditionFalse, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolAutorepairEnabled, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolUpdatingVersion, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolUpdatingConfig, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: AsExpectedReason, + Status: metav1.ConditionTrue, + }) + meta.SetStatusCondition(&conditions, metav1.Condition{ + Type: NodePoolValidationFailedReason, + Status: metav1.ConditionFalse, + }) + + status := map[string]string{} + for _, c := range conditions { + status[c.Type+"-Status"] = string(c.Status) + status[c.Type+"-Message"] = c.Type + status[c.Type+"-Reason"] = c.Type + status[c.Type+"-LastTransitionTime"] = c.LastTransitionTime.Format("2006-01-02 15:04:05") + } + + data, err := json.Marshal(status) + if err != nil { + klog.Fatal(err) + } + return string(data) +} diff --git a/test/performance/result/aro-hpc/resource-usage/cpu-mem/db-cpu-avg.png b/test/performance/result/aro-hpc/resource-usage/cpu-mem/db-cpu-avg.png new file mode 100644 index 0000000000000000000000000000000000000000..0380ce62051b2ab3cde6cae63f4cb87e8e136a92 GIT binary patch literal 95890 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%0D~(e6d+p?K zOCrAxW@$ zzAKwTG;PTB#n{${CzGh#pU<8E(RQYuUPSdv)Xlng3|`y2mG-J-$D6YkPP-w?bTLqc z3i-8+>u3fWE)QN~4+VU2%i@LhkAImM7j~$var9apqPfZ>`z=CnU?KyX)NJi2J{~z`>)<$6W?p! z0?7xW|JnTh*N^${2mkLQ|J9KGI{tqH`)?=I{~yywG!}8_LyB9<%b&ECPquxF0dq&C zTl>XZ{^b?^lh=D5Rc!B=D#}ce;hZ$fJ3)3 z8hknU@RvmPKe^0b=b#1v>@i=k5&7?>^gsPeUoGkPexJ3DUmQ#Q)p`AotNY8{z*9*` zs!+xz2L0X9nZO1ZH4~oWjo`m~u@a~purbOzs-+uw27mug_ literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/cpu-mem/db-cpu-max.png b/test/performance/result/aro-hpc/resource-usage/cpu-mem/db-cpu-max.png new file mode 100644 index 0000000000000000000000000000000000000000..f247b60a89067ce801337729839f1063c31ea13c GIT binary patch literal 95991 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

@bKyzE5 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 literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/cpu-mem/db-mem-avg.png b/test/performance/result/aro-hpc/resource-usage/cpu-mem/db-mem-avg.png new file mode 100644 index 0000000000000000000000000000000000000000..774cd4bce6087b3875e8470e87cdf8621a9c9632 GIT binary patch literal 94199 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 SfW!yDkIXYgiBho_{{Ii|^gKKO literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/cpu-mem/db-mem-ws-avg.png b/test/performance/result/aro-hpc/resource-usage/cpu-mem/db-mem-ws-avg.png new file mode 100644 index 0000000000000000000000000000000000000000..e98b6fb2735c5304c8ae58daa69a67320bc2f1c4 GIT binary patch literal 98253 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 literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-cpu-avg.png b/test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-cpu-avg.png new file mode 100644 index 0000000000000000000000000000000000000000..89042bc483457d34572e8203354a05d514c606d7 GIT binary patch literal 96770 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 literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-cpu-max.png b/test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-cpu-max.png new file mode 100644 index 0000000000000000000000000000000000000000..20f06587b7382c95c1f61e93156c09380df3a22c GIT binary patch literal 95575 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

7#yIdggw`NU$`UNZyu>DaFE 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 literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-mem-avg.png b/test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-mem-avg.png new file mode 100644 index 0000000000000000000000000000000000000000..6931fffaa8408ebcf88bb1b08e6dfe132b83ee6e GIT binary patch literal 94553 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


<$4Fh@tFAxY&yTt_l?<4Ux;7W$ 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

m&) zQxlTE0ngu8(`y%bIF9DICW_#Ks2>Oy{q>eBjbFv#e$IooP*+Lw3??^2rbML7%hSg+ zmP=IoC?X^(pkf4}LKME%hKG(pP-HrWq70Z^ekAnz?sKH(e$5x$U;5!b>=5h)?i^-8 z=zeR+z-$EQ#(Cg@Z^?Nq=?9c@#KDqnk=wqo^fhEfY$G`j0HC0_-B_+8DX6(JP|N*l z{qwPW&9lJ5aW)yuOEy?tCFp+Lo~^N%6I%VV(~^~*i}D`HDLvPgFLQ39pkq%{`v5n3 zphxL2K`jzOF#j!*o%WW#5#vxt#&7QN#an@pCOPB}ugsw1U;KLZ))D&cD$DJzTKULA z)+(%bV}1)vEy*pCWR`E6OmuO@tw3$;Ejef7z{v~Fs$^QX-9*qHk3#%C0?IMuLv`M) z6Y*VY8wdvxwKsM#OoONem$7gE*ec}RBP+iTo&?^V;WJ*H!Ii(%5J?&^QlZv3lfn@~ z2@X3IX)Kbl-2V3YCP+fAClrB?weu{^Lk7#(}3n2*Gn5nGCCozlQ?*c;>-wc!2GX=q7UxwuG z3#ls;s*_y?jQCr30*-s^9HJuw)vLWvE?-DQb*bShNUJ@h;$Hm{e;CN1ku8#!)V&ec z4v5LzuZ2nbt+`QVSdqf`-%+I=v&ri^il+-li!n5{$_3mH{>A_uw{zeN4sKK}8u;u| zN_6!S(?s%P(@c4fC44Gm3zwzkzK_k4<~|Lvk!kiKO=@8o3{jA&Fin2S@4xLGzdx{^ zc;O!Na2$HP#1z05T}h(~G(9pz-7(@z2mYSVp+7?c@?c_=(vPT08V>U-_9mVwFf9o9 z6G8Jn^&`@(l7f)$yC4d!UQym}f7bWo4g@QX!?FD5-Vi?N-paf6q;Lk@<@E~!*YUTj`NRK9pYlV85aO(c{|X}bXTZamCfLQ1fS|H#7g>CwLJ^vcGWOeXU z_?c!^BG6f+B{lqLo5Ji#C7Uc3gxg19mRQ4Na&D30Y`ydi;>h8Wzdg|iq&xv$E1>Z4%8uHk#T5^1VU2m zAE$Eqx06aIu*3kJc8Tw5U&w)=O~i9`CP1fA23@Z=W{I=(om-qkV&L;k(!$n@(3n0_D

Cj#vWDc5#T?}Z%yivd&S-jQD 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≀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 literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/mqtt/conns.png b/test/performance/result/aro-hpc/resource-usage/mqtt/conns.png new file mode 100644 index 0000000000000000000000000000000000000000..d82b52319fc99114e9d10b4d22fce02a769bf665 GIT binary patch literal 147274 zcmeGEXIK;6+6D~MiwcM!2pB+7iu5iWX#we=B3*j#y`!io9Z_0nO7FdfuJk5^9ta?v z5CQ~tI-=^#92!bgp zsFNu_-O^0Z!sEJEhxfEnOyL&m=bMC2dftC%BH)htKsNg`|HB(6d~4nhoDIsl)MeLe zI60A)Po6zP5Wla2x*>uvqr+*Kp@GxOrPI9yw+$1#{=>V8oD9jNtjei;lqbH0U=?MU zhaw)uGd$v1LK{kP%^x>z9Fcw)>Ft2`k>aICVTTLqE-$XG9Ir`-GScI5-duTU#wbp_ z0{hVME9%EKUJm8`fW_zA-?&`CsgG0`m74sbR_*+)qpS)UC<>euA`Hp&@jH_q-}R8j zdm#C#(9V688uW>&n@%B1{zDa+Mat*T&zQS8Zi*>5Cfs#+noWI1pZUAPq4%k%M20`t zScc8~KJyz9T_L-XtJBAqjrkAMZLtFK8J}5C$W^}GKO7EB(!0pxi7~w^Fhqdxz7XM1 z4eqv0gY-sa*)aEg*KQFDsJ`OqBX6D6%k=i$;=#bA6>SYO7_pa3-uD^aWLZ{Pd*u=4}^}PkPl^op3a+(a=%iaDd2dE zQym*kLuT_^k2(}6KMh(vkdfYW?9My>=Iys__H9kxK}K%QI9+>)EU`ipY}Vgg|9ZkM zwf}%3!={s3O(dGHOm04l~AMZBHFyFvF97!4U3rYVz^16}xyy zia8GuEb0^{Y z8u_VWmkup0VUMDMDnWUKnBu7p^)nLC8^^ENUu%Cp+>)FmmU)Z&YOw`6B39{okb2Fj zlVqPD6<^pw?lG+yN#A$w6^+NF2+EZ1FZ+T`)a^t|Z=ox)zeT0r6L2!nQsl=9DGKWF zJi~j$csue|u2{~Y&cmXo&tyu7r(U;2?kL9Q$mUktUrUb@QImu7+ahOkqE|<`SdclopB{ zq?jp?>6}TDS=gdv`rb9ewb~W3SCo~ExZmaz=o1)!M2@?0L3AO51L0Ol-jh(17*nL* zcz@&hjk)(}?|t5D$MmaIsBp(Virr(fie>0k>phD>r*^V8u#>Z|vo~s5=u7Fp-j;<` zoTi>qV%}l6H?gUS!>P6mwm!BO8zNp|7-tMSM*R8_of7|SbBu5H*c;4H* zA-uJ`#ym@gX)is>2g~=2lgiu5#Ery_JL(1NSKzyi+x7Xgd^L-XaNDzyQG}MWft$E< zr5%fvxy91=93cV*;ut5&JEVS*v6P#4Wu@jN3Z$~U&tU_@Tm#!hu%8Ow-<`h$(@{P~ zKK9C>lE60qG_^FLY&mLngnF8An`T3|TMiaV7R-cV(>@Mc4U6y5?O9@l_f~np(}6Ea zNe92f*~W5V`s2dGwZoXSlsJP{gUp$t#&WC?`UOi&eD;`DHgf|BWT?U>9yfnhfpx*M zoxc1175;BqdU0A!<-tors??T+eKQ%f~C9JzHxrz_k6O3>xbw%>b@!3 zus8Ac_kMmfdu!|=H01_gy=gl1s7vU(O=*g$c}0VC!0G92PwvOuT0O5U?_0+82Coyj zKa#Mj-kpt_)#ZzZMxLc__Hu7fU@}jY&r>``J(N8Z4@M85zanW&XrA6uA>w(Gw(Rmv z``7Cq2YKOnJ9z_ZAJ*Q}20zspH2nHaKy5awB&|iVUfuf9;O*mbZUXbI4HhBBy!J+G#@mk7S81FLO!te3Jz6lnN#y%G`PaXF{ z2O(6kX|+phCR0@TnsS;lA(Rf~$WuVSc{^;j%@TWj3-XCD=tIzhAl%anbqIC`wOEaH zGE^}1YYqxfd>7c$5OomJ8sdkAqAKNbJXo(fQzG6(v_-a3iN0WbmVCFDdGzu5FV)|P zaoKm|rd||3UpELTrF(&$BATh2nV*?velBP9l5|FG=Y2e{jPGVs-@!&;El!c5?)^E< z^4ql^rP)@Yq3#oCYdBYLF%E_+@zfC8qAEc1Xzo?UGzZ-BG8l)4ndAoyqrXtX^ZJ}$o z$$#W@z8M)eGlqDzVBg~4S9_3*Di`jUzYHvZRn#6dT%b0jDE*9D=zL9^kb&3QV%^WrO`<{h3R84V<7YU?X4Lv zk8fk^k01w)$>`9fY>fg9t*FPAqeqW9{S||Arikh1);&=rr-*m+BjE&Vpd`~j7V1+lLgRAd)r+st1 zZASMya%6ZvZ2K&mTBCSAJghei|J^&1w?P)Fg8+VwvU#aytEq|i2skFgBf@9IBL3@z@@Hz1a|8brG4=>UIkLX|bXaV~_p9En0ljfg$!cXt$(5;;=d9~^Z%*)|7nYVHuOKv0xd0jO`89IdQJA)$$0EXpd;@(C}}?f_P{Xv z^TEdfU!4Ek1IPHr8j`NBRq*iS@zj)_JoCrjT_nw*>0$0XkW&t%R|=%b=bY^#pp$=g z^Li99El&~cf#JrEVM61I^phvWw^X*6raZbwNmZa{mXLsqH5~81`I1l$4^PYR%$w8xZ%Xy2^xX2DH*VwqSCzOa&k82LDUg&) zDJ~WLUloUp70BJ^zpd;4m-~O}hW}SuhE<;!k$Kt}47E-fHmTDuVa_%mEirsq;bfxc zm^_wUyl%Pr?}u4J2r*geKzm=ZjN;$A@{`f4p568JR5V7$d+QUl#< z(WhjQd_d)k=Bsy{8to2J7;hs8ywo^f4v{$ck+k-eS*A7GKf9N}@ZzpfjrGSHVUDSH zy)nHhS^3=ITx9s4faj*~);%0q; zJ3j1VG0xZds-V~E?*U&4P%eGpIc;dCJU_$JxLe)F{G~1EWZrWrv=5}0|MW}h$x44B zn~?XGRgD{37HU?BXv>#>O+bx#+2~t-E`TL9Y!7bcxjHs5#GIk^iY*@&KZhnyih+hU z#T_5m41QKi?8}Xp{k5bO_0GaJBY2Q&qCk@=;0)Dhz5OZQLhoIcX`X7L2>Rw!&bzs# zQ0}2nQ(J7vT#dQS<|s(7###+JW+!gXstFNe`*82*o?30QA_-M;BO*}$>6b?jVFhCX zp!B{xL&QL8VjQQ}nM>n9hQ!j`uiHE?b?VxJt|F+&HdG48tW`l&s88SDm;Zmo&qkTG5O(9Y)1-MQNJIJjHV`6*^dTaLe9w=XVp zq=lfo!k&xUpyG2hL?lr+H!C^-ECfXa5n5^$8~u#o(N`-;mSN;s_3eeIMA&*8wOeG1 z$mSQtgyoc63}5{Rclx@Hw*MBsaCX>9+6_h#oy*hB?5eYh*LQQl9d~^LUYNLReJ802 zIrB9>Lb^3Q!C_f$!d!!0RJOO~>!ZUmSvE##C`8Cb9SSd+JXY5nU~~S#0)AeA8~Q$aW{|4lxcr+nKepnJ#m)GJI%hgbLr9 zTfH|9bz{>U;ct7U5_5-vi+t$Y&DoBy4ph;NFGq>@BGyO5mp)sK2wn!xA33uKU@p&S z^4zjzzr7X;!JQ-x@pqVbe+E&ws`Ga8erCbw(f99UUKFD(Ml}*+@P!lSTgrkz*We^R z&%GuzJe}Q~tl{|H9Bfm{ZQT=fTg?9~%`Q9kRL9!34NKBJS!w&mM$#a8(B|;n0;!vk z=CTT;*icrWiG6Kw_&-4mOIlT2c$x#OK&>&TB`WSx7wQX=x<8;+?>INQJ^~RR!1*9; zCi1BA-!c$CkRlzn?`w{0_{z4UBvtP;^CC1uZYf*Zq;oiV1d?wz#%!C4MZ3(m_#g)Z zHnaJCkXbypxnCqaFAYty8A=|UYZo= zXsC`lkVWfB+OqeSM$;cIT?vR=Ye}{Y#%#m#%`R|yfYD5FsDTX!wfKt0=cHRQSG#|e zz9NVx8TeoYnUXpa?&jonWlJNl{pNtI`Bu&C^+GOENZ7rT;V@m4DD?LVX~4?qrt|*Z zR*Lz+q{0<2K!s*v2S5k*Q86G2;@Vty-yAPc=pX#m5?&p$LEHs(7$acI4 zHSLIhm6jSW#QpERntU078jAqz{F7~s>!Kt)?fgi1>^;aufd%%g+Op>*R<0NZrM7jP zeB4D;UiSHHuftr@w^g`Ah~KD5r=p`hcCyS6hKMcUes?|9b-N#QZwumvBNJfSJf_ASwr zay@tQJejit*PE4nREcNiWdq-6EY0*o1RVC~#t(S(f#`*pK=15Udt>#!D!fY=N=s`A zC$U+a|Jqh=9!+=k33p9`Re30xcdhYxY2M~{sv+LSx-tBqj8kappO!WkkWf$1z!#ot zD+jEMjx90egUvL>;``+G`zILoR|OW|y{w04s}n!5U(^g2VG*y=gtZ6NdzK+egAWZ^Wp}pU> z$6lPm1f)WHTUGgWw5+e#Lp9y1h7CnEt29!c>NO|<)fY8BQBT>N9{f~KH1wl#H2p6O z@E2V8=K#A|Dz8U694u!Sw-D$=3e{%O!l`OWAN+WU&3iTa$IFddncXiGNc&sG5%Mfop_pd^a zUa3SD&E%xK1c#2dsL)K zL7PyQ4MCq1B`-~n_$Ew&+FG0Jpw3ud?8Zxw(|j(CRuRL5RHBRj%muQtBj&qjkV}~% z=0_@=*UjuJqA)p3g=kpGiBa3Q5paiwE#4nPL~^p=)h0>bBq|ls-lx-R8Z+Z%ID^5aV_IJjbI@+}_}&Y7$&1m-;}=8En|R(#w=@-f@ZV&$#kn*jFynxE?8=tOjvRvCaz!TsxN!jUbqWstJFDsxIUDBENTGP+M_oQRvUGj zT_&Q zqs*kF(zVdQluqx9plI04B>^=R19*1ghjXo8cKbcT`H5~M0AxPXoBMYW(ee5~>Nj7L zkjdDVX-T0(uFl=v+AmIwxBdH2D|FFW(0Exfkyp)ecSJqc$b!o16ycgZ(e#aMYKuNI zi}wg=_nI!m#z$AQG9`yVAgRF!ss%S>am7-Dsnqr&G=AvOuTtN&couOp*$eL){}G@3 zXukHBxMLK(ko-@0oFnOe*rit`N_yt_NHAz5T@=>n8-;CZInE6^PF91rAqw`!PWPbU zIQRw*sR_Aq?{64!*}TAV^sDo?+ebt$2#$NTtHd%+R9@jpTpYn%CYA#WyHp}bC=&pN zC)(E^nTIs>Us2wuc8`AwxZB-U|EofmzEr`=L8i(MzOeIyNI517t%;m8aYQhTec@NCIrs*PYX`*CT17E<@04DlqO$LKM3PUsDAJhgHm&?u7i8_2 zG@G#PaMhBH2|MG0*UVyOo(sIeHTg<3%gNWs^!oWb0k?1E(0N%$*2ZLGEVy!fg}rTb zySc3Ec^68r4(=5|+Spbd+$VW;j#27>zk?hdXy8)W#T_!4E++-j1Xe=kn!O?+E*)1? z%+f#1#J^89FE=35?6Q(mM%WZZwJEYDASB+0%-@4rd@yd`+XjjP(GB!_Q%pQwTBzJE zq5P=#RLOJuGf%dKcKi&hfK{M-!SLUg>wg)R*GDv}JK+qAE~sbIqc$MXZ+_Xbp5H0N zRgPyf>bAT+Knn5FheguZ1x~n!(bc5B3+WowQW$>=1;}*ef{K0c$48d_S1|HiIp=K8 zr!wQ?902YMIs<$72vlc8~`Jm2^8n8m`6f-Jp9oyd42PVmG zrKytVD0}XXRJ=Pf?2>x&{4}XQ3p63&ngLQ?h!D3o3!!iq_Mf>;_A+p{xW(20j1pRM z#^Luqwdb}?O8z!3eXg#uL+rIV)knlsg`bcUM@O&K@RdiqJ*i{Y8{+j-db7_Y6pTd9 z#&Y)iKjdLwpQu817pjkAKVKVmX^gLA{q){Udi{#Mn$a+Ldb@#~cL4XtmywQyx zB!zImQ0+awhS<8!FU>zDhs}^_JgPvp_-H3j*gPE?yv>c;x7YgR3&*@pSfQRj=yDuN>%C-NLR#S}w+cM)|u^tEVRrLLCd zD%!t#CJPHFh1qO8hRV}X-0?38@=Ft1=Z0#4ZHiq8s1MVZi9r;qVAr49p97EAh`llZ z&|xD7y$X<;70FQ}JQIl}@vUz^F}m_K!MRt`i?~|DWqAu5yrxQL63UGm(@z4DW$30f z6Z#*(iVL6IMhw*FR<=s^lAQCH)%BB1pF0ppypO-LjTX^fYYJ?n9|>^O$kC~nq8Ny>*$$=;Mj{Wk1<6u6z8xwlX6lE{T%*?Rm z%QKgYnbnG1y{QsYb>Fm;R|B6O`Wi2#;=T4)0snOQksj96z&4I1tWE_i*0$`<)@>uK z4-;dsaiJ>+u2$*N(J)}df(YI0;JRT7(n7UPxF`uL!;_({3nu_x^nZng{32YWE4e5veyL1t@2NIw%8W;wjX(Ij@B=MME4aU8jo71 zymaA{5RISjNiJ=DJ7eM;eIN`dt@wHpOh&*)TFdnU3L}o|bmu(c2=656b9a8Ju?v30 zKa7=$gk?F@XiQW$ERAV8 zFLz2S-!W@>LiQo$}7@{+u6d3@p{nRIVu-4W(?bbWO4toC? zc-;umkaVL~s8Ky6(WX_P^*@-f7#aaNEskSrX8JYg{+r(R`FgFItND5tq_E$5p^+_S zwJr< zChjcNh#j^*~g68KEP_R?|068>sc4m9HQeT;1M;w zZ`M){(<*nvgaS*#R!BX%Uh_AqaY=7j+ocy+TH0eWq$Q35L@a;n`<`wWX6`^93;xu{ zh_NA3CH)IDVU=!6v=Hb;gE6Wm4usx!0O>1cdWVU*&40ch(!^l&!stL1(L!m~5Yu*J&|zqGLo!S74S_Gh$ckuZd` zu`kWfW#c+~U3sxU3gOoVvanNR_7cE6h_y}E>Lihu9Xc$+R?h%}>vxhp^Tv3v@1;$O z7}cz~W*!^|fK7c9zjKDXL-wrm@AaUMp)4P!p84^nH)zE-w>XB}aOKu~m4uE;=H2xa z#%WyRHHc)(G~jx1O_(jKVZmi7W|%gilpJ@M#%gNpO0$MEu5-8O^lWQSOEf=sc|T2! z{=8K^(Mm#b*S@h5^(~a@Kx=-(dwXJz&mgFck3)zeY{&krY}31GK>FKwM_b36b~gL7 z-1VPmAB0oKMtuOrHk-WSM!#6%KTJWL{K2Ftjq0A<-kv0FmDfhZUS;4`{fkO!*C@N7 zmWoDH?50%m#@8iOy~bWp{pj^9z?C_{wnQ!F>m2Z-H3ed|$Mi=Ouilk-RiIjSO1MMV zw-&KG+?BtNjPf>y)F5yq``a(dO9%G4hp)w@=H=* z4Ou+L;+rG8N}U5uwP)-U{uXEW3%KAD2^q=mn0p zbSEBZOG^f^#T_~L2IPgOy)dY&a}b?<0Jsg7I%&qLTaJSt!qar%v9@Lqv6;CVCsM`x zN!KkWUcJ%rQNm20wwRQQs18U0Xkys@DMI-YYaVt{Z)z|z6DJOI6OIZi&3GqgGsSn9 zNSkqgHLjM#)}NysV^na`xNz6g)XfMho33R&<3S4)YqJiyfQCUEhlF}cefgTb#2@SM zQuCu*y1MMRu2FxFQNzuEy=cv6Z56E4-2Q;N1-OdE@tyR43Ig1&yrlN`&G+tBqXE|?onzBz3^CIxdk?wg*H%TY_^%pGQy5OH#ZPjxVZypB`4E z7NK0f5V&Wb^VZMP=kY?ox+Y})%zxgq@nShV4a=cXWi!3*G*dwV-EI%T&3ZH5&FM;W zeR>3iWQkWecL5Oxibcf3E0U;p*Ua3vzXfPMc%{<8WG~;qY}Gaj7JleCqE+hjdS^P>y|00*7J>w$D z&G|c~%#XsCY&PO7+&eW?W`Ycu(WT-q3ofdr+D(J5Sk6(Jn~1CGiyU;zJ))t0;9%#?Z?-J8FY8 zk!?kY7V@)rRWCe^X5nB+!tjO4x0pr357_#3Yuq;yM)VlNjCd1uxx&+Rxh(^RaCN))qai_HFI@g&!9&ip- zv50npheCR{3+JdGb+e!Qy(STCK2ffu?@GG)x@Op1iV{~5 zwkxiZ>=E92|8J4hzvxc+f@^CN<#r2%Ik%QRZQn^&V+rNVRf+usL^tMcXcrr3n+2@j z<}#{F4I?aA)g8`+o?zZ$EP03RwA+`~LCm>4| zxrFgt^JEN@XpNfY%_#4dGuPTm<#ned^Of#*7ltMwQ(r7q78CIaNuENGm5rFN%TqhS zcyJXuELBPy;2?i#hb`8Z_bj;Z8$d$**T(zKF}VS`eNRG;eE_<6U_GT#wR#>P>wm;l zS#9zgw(#^EstRlLeN62OpM9{}+re&^9pam}CdlvgV#ahvg@lrk7K3YfW8@?&IdbV5 z2XMUI?NrBdUf9aiSNzbeX#S2*z$$1CTM%J1kMPb7xf&^RTc5Rxr>JicarJIb?UR{X z&FdS|{8-lEy?x6eWJL56hcUStI&%) zK>2cbN^ee*7k|_hlgirYYwy?Z-Xw6Z0)Uh9JVW{Q$BHjL0K%|`n=E4x zc6##%5HXi)0n9$oO=iLPpNS1F@TX|m5H{N@9V}^&G_$HveT&|E*~=!ma&rHKxmr88 zmT&1X$U>>gVFKP2;WNm6OKLHgQAI@yX$j-2;LWnt0PmDhFo5c zhbY@_zkzwkm-}v+xbf^DY{#NeWQPab9eB zp5^~b%^{%YwyWPnray*i#`gg(gq0aKIo|?AwO#|iRa+-luT7+#-*Xghm5 zUzRD3LROAQOdA5sD2E*X%R32t^MNJYv3F!m%t8a|OuWaH4^8fPm1Ar_OF&}{Hzdsm zy)wn)=|0bxF}bBUzyS>J_w<-iba!+43h;o_t@ll@TRK?XDu&_~M`PY{+J0`J^;xSO zll?*pM8tsT*b`Z?86ok9H8O5+rZGPr-UtR|T@BU}5oiCn7zU~7+e255Z#YoL9Q8== zJisefe0r!p*jU?v*#w>Ug1!UnB)nmfS35coeHeA@1L$7<=qN1T*yhbS^jJSj8T`cW zR#7!~UVB#M&0PPY-MB?vt4yb}pwdwG{FuvGh3DToO#tpqJZ07Y?sIFl3E@zhJG8Z! zisS$7dZmQcoBs9=8Zm!6Xln4wCCUxnFfu~v4-k|CVzIK1xTd)#$%F&3C2_2|XXiMl z%G25mnKNT4ZLrpXETYq!?)T80^E+vg%sZ|rY2g%Mvg7UJ_qH-an!qN*se+5y?DN5< zEl122z236$ns-5;lexip2B7CE6r-}pVby_MA&^A(qGlzVW79wowwAo#y;i@qCGiWp zhClx+!~00c^0li2k3OM^QokScumQW7DR5kmP`=pCn~n9ox)WFJP2>k+BU#u$F$t9l#nWlL@a)sttLNHOjuvH|#R5p-E0jW7UJ zKlJysxhDQAya2saS-HsJ!m*g=QZy6+V<>EgdxoExFshSk63QHZ@n@XVISHO7uT>{AXwS%xQXP{M{FaD^-;l~ z9`@vcSlM5^&>(b(vqkG^q?1%@=t_k_3k#L3d&gp>PQ22`DUtey(JB7MtKv42c+Qm_ z_ae+->^v=>HqG*eoby4$y6YLjOO+*iyTRd&)H$3C+e?I*KMK5T;TpH{0pk76Syp{< z9)|COeP+l)9_a1Uy2wl&o4{$%K*xu8#`}8vg65ZQ9a3w4G^wpGOROL^^E04Cmo~<# z)$N_2m&TZLm(i#_>VnExmdc)E?T^l5@RME)Nd0=^Jejb8xzCqH78iat&BUDyC#YV~ zE=1~m7wU=8Kf~TTT;ejT_+&P{s=1H#$1o4y75*OMvGqF>!MLg?uapIOkHZro>8eXoT~Hfb}Us&%Nf&`6Jf{6)9$nys?bpCw6WG*t~28 zK~-dTnVa3&X5onnM$UW7z2Ca;u2)PLQQbd0R$dPlpVynGpt#D14PSx(-C_k$%lbu-bc4+?ywV*P<{erB(u_r7usM=C}uS71XnmihW;}V zeHQ$F`h!zF;8R`*B9s0Y24QEZQjCxF6VSk5y*V%=MLQ-dh{qcQKTey1o~VN-CUh&k zC+R__KZ!EoiFQXuG>;^8}#qPqZ?2ZSYTo%029-dNFG$K1LnOUu3X}^GGDRW z+70?%SA^|?KSkC0S*Hz+^0&80Om0Ro;yCTJ46dNr^Uk-)$uRgGR7Sz94e< z!OL)vRKpoq+875eOx3G=rd=}p2X6a9~V@AOL}xTyKvWcMz*iLVD2 z5DvMjH>S)Nk+{mBo${z{O%T8Wq{#0}0@~*REpG%O7Mn7F4&v)zXH;wDMtf{-jp z@gus`m=$31&Xn2VEdyGW)>S4%GkSGrgg+fyT#rhRWSWvUUCcY%o6eN9iGpPAlr|!W z8^3pPLs+?-ihUmQvh!kq0Pcz~s9S6)2|0bh`*Pnas_dAt=(x{Y3vMHM?PKUPjzL=J zJC)q|tCa1-$@z9#rYK95fB1-rUuWTsv*W1+)6;GH=a^}MNr~0P7fsj-=J!&S-R1Ps za{m~l^;ugVc#ZhKNyzcF?h`;>fVDjIzx55qQs%NfQck}-Te_NenW^-9nrB_i=an13 z;OPaeaySmwr@6q+WQV=iEW9q}y0FD0ZJ%&;R_eEwu2eCX?)PnmU_`M{30bi*4v?7B z--+|J|`?8Oy!epv{)DRV}3Hcw?`ou(r;{CBzV zUv$>%Vfut&euZBTAD@-g?#BN_+*=hj@aoIYyc*9_vk;%C8|V=m3CF+C&m*6@x2E~o z5MS7c1Qcf~MZee92tj}Bi=4+&VRu(}vqI1mJ7iP3rI~{1@r;+4F*&YjD$&*GF}X&h zeU5TboI#_O5FlV<0Ep!)bbEH1BS$iv1C2aE!BM!K!uXpXMMBOG`Yv4pU=QchlKOFs zO}RERVe{1VLu<@npZVhB5Zs+O`@%`dMA2+_5ZFBAIG?xFx4&R|+g_!k%0bF+k5;En zsg*$JF!*O*-nQ?g;56R-5q7=Kn4sMZ*@7pHG_DhI^7JyYXrHwMlnJ#~?uV0IsPkOEc9jd? z7`?b>Qq#2Is%2Dc|dOKgN`p0DM9Z2F{atll9745Q(Mi)?mhnJV$0bpdMA#CbPxpUh%SVlP= zuzFim*9>dcQo{2--Ywl*WT}JC`0`JzjiQwZZ4n_@`{j{`DI(XQ5){`wX6EJe$x}Vj z02|ob5eH}yZZ+E?aUadDi%@0WDu<@`l~%S|Vk=icjY#m4&rCx@_T~u0NiOIrrT?VW z#VrtEOpw`ddN;tFE#?*}Of{>zq=?76_X*@8+mg3GnGIe1i5BT^j+zHA@h-0OR)ln1 zEmJQ6guwot0$QQre-Er*TT}lD_F{fV)8>97`p#?CI=fVygKkS=B3^GlyIjpgg~^5B zM6Oy4c>#5a=@Hlu^t@NPWneEdj_js%KAk{rZ+g7%Mp25drEF`#+bOo$Z6N2336rlFw{Goti)s;di%}A{(YR;>z?iEaH*`q((+i876n!|C7 z#+Q^Rw*xxvp0ni;;ds}5QD^rCQ-cWoZ<*dobTb}z9)+u8$Y(tA*bFnS+!kSRh3>HT z6imATU*Y3k3sMhv)<=fULeGDD_;z@EC%h~KNYTJc$5-ilLu&(9Ebs35GgT-alnIYj zWtJe;S0ra!9qzYb}W18e>$L4+T}q?wcuQK@o%u zw`WiYPX6M#~OAeTAPsiJ)z8g{`s!f5I!oht6 zP@7wVGxsYhbKRQ4*(kEe_in(XzC!^TG(Ks1eHqO1#~^Ou5PhBw%j)i@N3$Jr7H=wH zi+%xq@b)ltn;$CFA@k=r(a}qPjy5JU^e3#Aq)?0zvO_IN_K5GW!>{kb??jDsd2sZE zj}L?~*n7DX|0)otBE_>v#yXz}l79H>7>Je4_mOV1jkhK>NV$5aEH7VkYjH=j0kxJ4 z3B)#>1#d7EMvA~1Mq+F7UrTlAH&He$d#}hky-Jcoi~j!URM90g-(3DWDA42=dFnWd zJ<#O)7ny}~_sk2#QH7%1@6;W8){znWTP+=uB|paG3WHk{kJfo;TiZu11{F?e?nss>>?1{VBL;@Of*~*&F>*9#b zsV3Db7rR`d#N$=bs{?X+@Wg)XYk!Sg2V`rPfm`ckV3bvZ(+r<6ze?QQ#5aR;;A^<2 z)q1H62X%kU?Edl-b0ADvd;D@N36L-nJ3p`F!rkEvu`am0PU$`Un@-sMy+u;A%vTq)fY6rstBqQ1x%%}XXl zp94nSnX%l9ad$0q0ecI}Ii=&nrw3mj;a(6N-U_^0Vt_k$4oC1`$#J^=Acde>Tl_#2 zWir7(HlY}YH#V((@z}q(*S||m6EX;z>t24!OWHn4B4zRKG;gV~8G736x&Fgjp}$}R zVgol1o3jDlfJg-7Q|gbNm#k@*x@kmarm|G`crT~}vh1}wn0Cs}RLM|_k5kY22R>j$ zA>wc{1dy7K#25T?kB~ERuR<`ZO{pwjZFXlpCUPvkhuh#*fCZ-pGw<%Xn_U>kL-k~h zL={XZAZu7}T8&HE7Pc*T$?Wi++>9Fb^*-mCPqmmse_PC1nk?o`1G2!fGLz;Bqn6Wm*Xff# zvS@t*vS~5AXKpu|anEnbC&jeEdb=jUp?hS~%5JZ{F}g1{OmkHBY&St|Wc9(?+)c^Cw21%I{L3$oaQ+z%kI?V8X zGq5&$xhI<%e#5ZVHueUykdjej`}9b%(#%W@GmGRijmWAIePmT~he`8c!}(Ck)gwSA zT8lwI_S-dAFAFun0F(Q}yB%(ruVD%-HRC=@wP$c49R)%8dijpe(;govHb#ZGgbj@d z`R$pUUH(y4{#m4N+hyF#l=7>_s6bkrB|nr;0q>DeS5<`G5%RAB{&GPIAd)8voH?S~ z)3vw&(Q0vOIHkn#q`u7>Y-|=Y3VCwh%slio|9lhSs#j+(So|FMpja=zBvtBaB$SVq zhL*MEs-+j?96OtpS z4b%b{uUz)G%=*vyJjThNxHt!V?T<09xY;he(k!L6Gw-Wj$H?EBNDjs)De+1GPEl7t z=SOQP-CyFd6~mPCGZsS}09dJk1v-RZr8T%7CyWz+@g)@P;O&I(hwqFtT zIzJ$+?a~kuU^A)hyxz)GzWlwe(59GN-=C6V3T93+-C7*q2j#q~i6vw}KqHV(s6t7` z!<{V&Y%~h;*a&^0pNz)b$|}Lf{S{sd0PPD<&}fWqsV`(bdc~-w0pQHJ=Ji`LzuN6+ zZQ9fsjkCCEH>y)#ay=kV%!h09+THEo4FDc$V7wtIR;$udo^Fh!F_4A~yvnz<>$*_e zeRv=DtQ|Pmdr)zNzD=b{&3Efv9UZ#G*(|nB#At02vW?xq=3-x}Kvl>A!DA0=Uya#sg) zOgCL4(d9;mVHn=B=icG&QCAt+1T(PevEqBx!|N3_-SrpZ;H!<1%o#r^<`4NH+Qi31 z&?iq-V5P1R+Y224_gR65ExrAZJhumP{qHPC2ahIe*La(=mibEh^=d+YK(2Z?x4bj` zq{jJXy1!Ok@{5=L;ZM91=L=hAD|GLI@|p$Txo>fKR?C^T-Btd2poqg6oUr`FTp5;s_D&y{e5#>ej1Ay_FcPvB@Vl7z^V^h6 z_vgwti;6yE-(4v*0@YX@eguy9hB+u^tdv6$ZLel>v)!KW#NExq6eS`037l*saRm(K zzS&U#AmuY=IKnpx9^+n!{EiUZYk>rm(&rHwp2w@625zt`vV&bw_m! z1}e&OnA6Z+*nn{vF29~u=}i+sJ?4x1M~!pB-{MS9%d?AJ`TDB0s8 z*UsWEbnmq}0wjeZxtZ#>NW&J0We5-pA`Cr``-_>4lr((;3@e8uL|8RW7!E8qe`)6S z9SUy#RZe9jZILg?WQ}kO(NPrkAQ5zTI}7jeJW;U)%+AM$Kay{>c&r7PaaXO9Z@dO1 z68LVHP!j;3E~Yun>>T-e2wu4?F0)aHqk9z=H(+*{Oy#8xlt%GRB*%9P6tJIx_(te> zHTXHb#n2|nNCjdBCU>tVQRQm(dHW1-IPOljHJ}*K?djqjFGoYDycGAZZ+|4yy&j{4 zq5=SltllohMHu(F0X}A2Pj`%XB_q8^n9!b80(vLdG=<)JfG{h z^X=wD!T0DRWB!dUE}{^3=Z?(H;%4q5WWK0kOz*R(Enh}kPpbv)g7pF1IALb1?QU)h z!bVE{;AVh-NB+Zl8d^ks zv~oy8tZ()G(cA_sfyuE0bHKKX2kW_>B0?-W9Kme_erF@xFx#=k{7dj2E57a}@x7Dn z0#E2;9W<8(yQr3<_6yE{v1qk7TXhCp0r!!#;cXHR(o)I)&;od^zdonuu<*+IeLVw^ zshcWtuhHW|e!p$WFT4!zZ0(SoX_L+F|B;ca_lwj!cFg%<>Yl_6nW z4`q+@u60L(a%HnpL*Be3A}@G6m)f_W!H5`7c*zkU3U$N0D)8j++zjF1lMP2K*x8}* zn(+pX_=7h@K*HlSfbngCpNHWeU*z=#V7jLCk%-tk$VhxfVp{U;(0Q4P0xDwdJ&g&R zXxU8viD}NmXOoy{RW(Edd3N)Tsj4(26Vh;E9LN%aO}P5dyI8Zy1Q!=^_=_nVtH$LJ z_NhEHl2EbWUoLpj4(=%>&ANwK(+Q@RM{^9E3PSU5LCZ;Q8+NR{$V9B4T??ExW$E}D zrW(-s>QkFd5zz3H0cMIN9PXsE_i|^GpT)h9&+mA`rq4MfguNXCRm@*MJj{J%7gH!mi?XXs56!o`?ia%y|M3;QeD-@^f7+UTFt-q7Rqqe9FxMpl&%@n zWrq|*9PDrr8K~!p1ad6sXl;>=0Uo!4u_aKeqdOZQ=YO8n4Cd34G4oN6EMihRd{&W( zXk_I(4YlEO(r%o=8{y9}-egKT8dhfik{z4l_63EuaQ{LBz>F^LAxH4#OE=DNcBNWq z=M^kkE__~j<)ZS%q8RX^CpO4zGoq_I2)hJb$Dft_sPJcB;l`Q;Q+{c(U)x&*aE`VH zWwGg{l(fa$c-82ZbtCw%u7;_*Qsur+UTbXEBfU_vOg8RFP=Pf*_W+xUFae)5f(TMq%i{l zw%XtaKH0!0mpgtLw#!@4hV%pPgpk@tvKo+TiM#m&lVD$E8o|~Fc{DX>%7s5E@+>|^ zGH;dS>$dyJNtl8$c&cB2r7aOJ4zSg!CVB^CB_{d_I{{eKFZRb>l_FXETWJ#CMOfUY zXt(DPV8~yC5uiYBFEEQHFRs#Nu0E7lz~g-m@nv$O#RSFh^K;?`(FcC#Oz<7E$ksV7 z>Y(M8{>bSrcOuBYpi}fuC8U332!X2TdqBs6;~N#je~nYn6Rn?Mjs2;kzVOSQx3-ps zutw(}ih7d}hh3n{x&+KRnhr&eh{(H1v=Tw|K= z?WGI=;V^}y*Ez{{d1Yc42uU&&`maoZC7_NWPeh)G@YJnB z*p?-)3ZKV&;#VBFLe8e#+g7ftx*rjl#IBd5!xQi}5a&%*rw{ui4# zux!x{%_#qJAphx$!KZPpCq^0iV-x>dFw>uV9{>7j#Uiu6`m3Gu&kd9&0LC?OQ~EvT z-<>-2r>PT5pF{qyRr*gY{?|W6>Yv7yQ7XvkUxxh8ZU67?nM43nNB9LI`Ol60=Nb5i zbx3@YwK3s+o(%VQr%nu*xiP|6)s!&%|c)`wl9<{M*JOK*S3T*s9B4Hsb#Mn*NuyAFuMXEq<)!vHr_f|Gk_4 zyp?vD0E^~@mL&YQx=kJ+qWmN&r4k-QD50M=udN&exl|I42rB|{A~Ntpx_ zHTduLdKu_-VGHXu3e!#e{3$I>86ULYGE0umUXNlQgGjV|eqUj*gfW5EAmuK##=eYVIX zJj7&6z$3HY(`hr4H2LZ1p*JZOv?yi@N{sJ}srxC-J zRu7cNN_PZcfX3-VDJ)|HY`b0norM9_q(6XA5ECdmvSp6EVF#$RSOpM34@L&`ALk*E zkuiQ3hJAko8TUpbwOqC0iNsvbN-ZHp?h9XU-4kuK`-Z(jy@tS-So^zd$|O>}&VPI+ zVE2)q51a>pIExz=x6fp%w3?^@l?Ku8>y)s_CfflZI3&ygAkR;wUah0tq{WHJ^`A%f z$;EtXXodgn$kEOqZ7$=}8i~&aTqzUkzyo4d=Wp=COaQBrG}h`zg?Z7}cbb2ro%OXM z%79Bhm?X9Lvnn%`kd6;_mo`2d&dkN7Oaj>A`kSxK|Fc^Z7!NCh!&*QM43pjfEE{fM z7W30H&S%^2jYB|LdQ)@$|M4N@>rV~|k9Bj1hz=}s9#scoO4~i90ZsK@uk7Dg)Q*6Q zg^NT~K^~s~{5m866s=;e{WpF$rwKSt2R<%yEjF(KBiPIneE|QTCqv}`9BTXU;R{CJCOJVYZ727fgDp*rDg+-E%hKqpv!Z>;dPxw zSvg7;wSOdxKh6#xlFJ^thTA%U2{d``u{H&^bwu47VSQPw}y1fN25O^bRX5!h`yY>=P!9l>nZ z7;VzlL9)B~VSMl5&;Xt23J$?zxBgA{LwKX5ihQ+=h6?KD7=9K)E-p6EFBkze33AG( zKt>l70Gf`GPVj*}>R)&+aXJ9`oRU-%ko@%A{~6waFR(}U)#C1fc_48FO|rlZ0*$Nw z*Os@_lGo-lYv@cCGH2f7+DpT7p~h!sJ8p9?VF&3QzUN(>-u?^*DR-V0oepgW)0+-8 z&%J>~-mnS8e}y%mJ>@=7a^^O;3?~JLcma*O@=8q;@Qg+LPAssIR6(lAa+57l5_Ih( z^Qj?fAm#;L5|H!WwCUlP_l7l_L{7B9mSzD~mU0?3Fin)oRJj4SC#eCT4SufwX}dI5 zAk=?pf2_GzX0dm#e-#6EmumH4ON*ymOGn#be}4#moZFiwU6tYSc4W8S1hXO=9-d0U_r$#eQ(L7136Tk?Fil|8eswhB0gsD=L&F;o=Q|Q{{i1})wdwHTW z#KNT2z5TK?e>tvG3J`o;Bnt$>#XUoV|CV+X2}5ax`V%ppoeK7w&$`WF!}6;3WILa@ z1+-moYDn_8qGSw~aYo*c9>HReYEXJBl>A5wW*9svHWs2RR#?E4IrG~u^!U7ZI)bap zW|U+D7g+ehVPd?{zc{8%YUZ2`QWlFAa5ht`(XXa&0)|Q8FLik0u71}5nGDlw(cCjP0d$RZIn(@sa%wvdI zOC_l&wDQ%cm9D25D?lZCUbm=XyU`$Wh9^OfG3 z$bSO(RT9ArryHY8CAp50kWgKK6mziRF9ICi456qKA6~H=@Kph4goVZx0^j*$va|EM z9tgnhF#)n=Pdbfd9||O8Ly(;t?|*Nm>D%0X08~6E3(>(AfEF1WKySVVG?NN}isj^S zmh%^ypB&)FhYo=M^sZdJhLlU!O*1|Lh8<~SNn!tykLt$|X_D@5qxrZ4wU)bWvm60s zu-|<;qjdEDjv)rAp9b_(0O+1Z!|X1Isot(1#`68=Qexg;N!OX~k)8>-viQlLDhSeK zzn@aS5FucSd59_Uw^psx_z=r~)XLcYg12GzC`;~B03kjEMU;JQ&)e;mpTRr_=fIUG z&|@J=E%@hfMir86^N%=TNgvd{i67!I|?oB7aBA{-F2jSfk zSKBHjuqK(eItK-SbO8)k?|xQuUIY2`hXatL`R;g?9dI-2a3l1w43j;DS5 zHNy+`U35!F_i-HHb7lYTBpTm0ahQY@F)XbjPl;@QKQ~`?=Mz0b?u*=jrOXzi-1{tU zC1&0xuhrx0tMrJ~DXVV}QuoQZ?sB;^kMV+AylG7gn`!1yW`=(JG2GfE58)^7*Tc=3 z5}itGtx8#9=h)1sovSsVGdg**R{@B7Qn0zsp9g$>add|&o!k>ny3{comBMhqOJt3$ z2b*cC`d>$MeO18iE1HR?UF>;L!c=cL1H)Tl^r7u8q`*Dt9>9akYu?8(&bMnra$hMI zn7~*nSBWnMvID9sX)#;wVL@AA8Rc8{snf-6&i?VDaEJqd`qPl_)k?0`DPu#YKDhhz zyLs-MZ~IzbX1#nHT`84-S1`YM7Yz3@dxU!fb1vSquF_J9E^2YP&TyV9OumdzX6Wa`#nk;9kv!D2Pbnj~eR4P*M?X@}pv~oV!uDZGlKJZJKBHhyxZvi^ah z#rh`oyJQo75kPUc=n?U8>0RN9-A4xT&XpSFVQx?w?L1Zr}mxi4Fxu4S3#>s&y}BloV>Cl{jM zrZj{%%#?(rf+{^0J^)y0@k^POq7HXxs^oSq?d|1Z5}=tgFzdLEyG#JcAmiS!w{GoK zn9kJ~O*UGxdv48{-=DFs$Dq9_0|E_|O#7wwCZFS8Brc0zK)FHbip7NJ{70v!Gl&!?njANtPRj{9J+Y! z#SwmP$sH3loqJ2-16Pz`SZVIdesTbAi$-4&L=T|TP(jQUBM|y*dCd_{%Ax&H zUi%(7#s$}XDXr}gr|XU2Wqb?{nndp)7}pi%76vTw_Ph(Y??Ay}*QP$^ePfx|-~Sc)TpszV6~UIo6a&0i+dvAf6e z)7Ar+^W}htNja9GWI&fqEF81w*>vV7aK?>m*wSoP{xe<+L>P9>b%X8c01z|{ni4x^ zL*N^-e&j1<0)=r79|nJvnG!zl3*IbJ-tCz%Up#fF0cSoGWQJ!N9O;JN%b;!zQ-`8$ zqzbzer>aAlXw82_-xu5XoADlCz_5c{dR#fe{CscctM|RXZdyMcLm-o4}eUv^b);cR8hX+DuWGsS)ypb-O6Z z^-E@vU;XK7TaD!*uTn_1z!87Uezx9;`0MC5#?#(Z=i3H0<7vBP- z$=e&_rT+Mu7gt)=VDz?7b&fX_af>>AzR|a?hx1KNy8G65`&Wm;*Sm4qMVM{PY~vz(VbUtg*EbKH9Esayl3D!DRcI=G7S@YNNy zdzzLN$8bC*Ee;dXe@OZU?jS5)fh}OowruCAKlF?lIjoYbqIDh$JxZNkNZOyI= z*s1ns8m!#A*?TQ6t*UmcqK79!c2tXhEd6D0!x!8BLpgyOkmeOidgOKl^&{VrPTYl# zpT&XNwa<}a! z+HU|BHB{r>O#mfGVundHRZ_9qTl-hltg0LgIy75q-)bWiOZgBGo5( z;U9ZHz=JbW=7qNkBfCx_?@Ti0?IT~S4c2M`k-$sWcdv%Z0FBZph&d3U4)6~TeZN4B z#6-?3_{zvi`D4jhqAWewbWwC%icj!%kc+oT3+5IN?hrTI2=Qg><0jMOuLFwHbV7{) zIzAvq&3BePQ{i5A=wj5U6>*^o(_HZ}K9b#`T54a)9Ct%b=N)nfuvP~av`_Rpor!YQ zcg2IX^=NM*xeO$SiHSMbO^5JqiU7d{CI!lUBhHO8g{*&HYV%8n zM&WM;N0LdV=&Q+ZJRqaLV4bq6^(1H}OdM0du*OfG(2a8^``Ecxdpm=n%QDP;=bxP> zf8z}Cic}nnBQhoXICH${Y#NIaKehcS*6%t+yg?!Dg7Qa|%bWq9IT4)!&15kYK=?tf zkND3bx<#FKH`Bu9=XW}t56Mo*GRa)nPUpH`qkWbCFE_?1AmH{PO{)iT^~!CCmf@k9 zA~bH$HrNc6EJ;f5p7+LpkY&4_1Zm@ws{b$v&2O4ix}O0cjnh$C%cQ0xx{|x4WNBT; zZJo;O)d@THsx$ZO)iI%~tSn!*-~gi?dsZOToVX2HF_RmiBy*YUX*B#Q1z#w4F4lUJ zBkyl+YPJNhASQ@Xv-bPFnX&w~l|1c#Dt3J2=3u7jniuaLr1OBTFI8JJ&}XcSoO1^c zYd0o8Y?(DX;KH!4nM}Gp{61M1_ZPPQu{TuM0mG`ZkkbqsxxFL8KCklrKmJ~1i^=B>WGdJqLK zEe`zkn7SNOQ`b_Gn;9syCI`u^xum20_V8%0{NoC*l#}&0!qj8N_4Z()Yjy5lu3kb0rIb>E_R)k@Y7=5GuuF870=scEjT!vhbk>Jz_&+cmV zBN-qwWKKK1(DiW?FToy~b>oQ9$06~_Qmel*jW^g@Gv^+P~E*FZP?$>U-njhc3j)LS1 zyA74`DkgtChbs8rL*Y=mFeKmmrEhAer2=} zHLBY_RGL63Pn1sEUp{`6(fE$vdm0a-@jUXr(12#$=a4-CAD&$rtg@Dx8546pCzG@Z zcnc#u0gUhA5ZHHFlq;LHr<3LHE6&YR(}7D4LB?IVZx0Ky*?u=MO=|TESJ`7NsRy(c zZ?<04A6)rv!Q!#R>pGR;jy(Q6;`Y~9rYMoO(AH4or#_#xJ*c#0JLx){Yg+V4HPotD!a=IjRcTB1L`Ab#3;k_3C9Vf(fq)8Ne_j>}sdVeof z8{>xxP&P)Yum%r~r7)Xm>3uen|i%UiR}lx(`wm_>jE&o@NikG2U%r=doK?6$(?AMg;bV*)#Cty^`XX zdpn*wOn)S8&dc4;uat;GY9)n!LzuZvCuHUt2t#W-9z%(^?C-K{ox;OL#F&SiQM0Mo zg_fwlW)LK!MHRp3MfcKOs0CvU_IQs?PwUw!5I%Nm2vUm zUCAsUkwse}-CjY{a{X>(0H?`(8E2xgg%$m=c!m&~el{vBe6h4C7yu!)SZzJNTfL9G zY%&>4#90YOo@>|p+LGh{fDl-AW<=s*>J|b5G;I2H76AUfT;y|V3ZsCB9w_*c+5i3` zZA+O2-$S8mCfz^j8A?3x5mBQy=%*G90x78wv#Wo6v#Ek3dd7e%_xYnzBDJ;qFhu{O za-Dc$7+sFdbEb6Bm)_@}M+L7s;m;wn7v2{Kug|td zIgKm0%{mFWLd#bKP4=CH?~mN?atPNMZ*@Xnef;JG{d$BdmHW=BgF&rQW4c**_)S3& z$k!@Pv(6~g3t)9xR*c2WB8J>UXY0gLEAA(n;O5p*FWOY6JlAfF?|cJei=4|bsOG;k zf61M7rcd>JC&B&(YlcVcs3LvF|9e1DUGwYaDv`#$np9@aGxXM)lCINo=tYbqYlGvu zq^Q=>ukT~BP27mYe#OjTOwK?+*$1isM00M4v+ym%S_|e6gU&oG_f(oVbzXX85%Q{o zxj2`D2peBW4~FxmMoZG7SS@rp7_?|tH*>#yVOSBzd6?U>EdAI#Ca#7J$-~k={eZQPYJ@yvoijrrswqmubTe3#9 zOu4qK7*Zns+|X>MTDM*;w<5d4ZBNI*(RLd(^bj}1J1$?aRJS3l?vVLz_3N~8zlQlp zMpK{K0k={Ve(;TY!ff7EAEe44be4_WW1lPm7L zG*e%3lu%%+eqZn7p2@Du%&t=cs>ypl%?AB2r4LOg{S8Z&wx)LoguG74=R3=~lpscq3uAIOAYhTLS@v~d zJNBWJ-YtXkD$EPwK|lyz?Y_SmJZw>C_XjR=S+hDXO*oymt|_t$c9l(IrW6au_;>lkpg|+j#HD3240rs_{>R=f| z`(8(dm%@5_o)`Fm27Rf3PK9g?5$6*m-t9w}a8(`^K`*-75nvmk8sA|~2!>aGA6%P? zvj%&;OR3Qp3 zoeeSZvo$HQ1qE2)iMcABx_7J4^&BD=^%MqLQ8+g6=<0NuUgBHh9OO#eT~K`SAVJ7y zKlud?)=&!=1h_VDs4bO3CZ`;?Arv#c#cr8moi;ixSG5zyPg*945y1##zGcU~o2FBA z++KxLxX%8{)S!U9i85E=f%mv3OP?xS-ow4aX3q1y7k30$15v)+D)YJ*iEMx}PJrGO z+PzSC9rzONaDab^Njh)iw66zYW-lBH1|Xx#(-W;T8Jza7{XDamZi~&T=Gnxd*GfVU z(&Ttzf#dZ?n?qhJ?n>MqSIgS1+*UtYhdWo^2^zaO1g~eDEiXpUux@qVR?BCcXMqgf zA{9T1-d&O@=yICOI&{2QT1Apf=KjHeH%2AP#VHO*D18rVG-GvY`%d~IN7a2i)Ky3E z;?<%tSI2JHX&Ka`h15sNs`$oz=0(J1kSvyO38fEflsAShWm1Pe?oFG!{q;>nQQ55o zxUhuzEC0`$Rb4@s0qiOL02pM1zT8Z^c1^E~UCN8SpKq^o^*v6g>2!;u_3?EiVW~u( zKAMRE+3?4>kX9oQ5;F^x#3?b3j2K6Q;gw%ofr>+8ulTb_HP-dR@HyktOLJDz+`R|I*I!*1&H) z)uLa)ZfO~cebS|fc5zbf(FL|FON{0h) zr2C-#67@Vbsc}->*=rP?pTHr?%8?W-6X~a z_j%i|z@hXB2egxKB^s}UY&4XFPC_7=+%pm9hmK$D9IQj5PLC9X}9m0N_%(32H0zMo+vw58h zT+qqwoOxQjd5$-8<-m|#uu?NVa}4E*{*(&}948a5?27kjG><}1)$5;J-)tF}!JU;H zRvvM6avV0(((^4)g9@elXmM6{^Gn90Q`@tx`*1H0gx);4DxgB z;JKLMgErbNC}!;VglZdnsw~9paL5Q;qPBpYTS9bOPb=x9`b5C=oM(C-cEU2#?J$}I zp9{YQzKP#0TYBtAHT389m0noVoRKTn8AHN6@eUW<`axJ7)`b-Yr;tT1azT04gN#FmV_=EV=#sZYhu;+d>9-}X^W-T- z{*mg8aiv@NX#0-?=Qzbolcnf;R2n#=Z?y0lgMD=ry6^#?4L z?0&&z{232GMO@n@2McN_;O_B2!8CD>We(f{gFbBy*Sozy4>?(ey5+{aT4Dg--8Ibr zm=wx9*%2#$F>R^RQP%>FnFA&+Kp=b6o#*n)_bp!VrOmXzTfE5{-~iZ>$uy3leor@=zZ z2Z~O`z2kuEf^G~n>8gFF5<6=!WXc!A*Z7moyyJLdwjgwrh1-&z76=RLD-CFNzGFWm z8|%XvAunL}YYpFKxRvR4G&>pYPM#JkKIG5hDPY$yPDWaJEZ?RS$$^vIY!@<6#Kg@+ z(B|WJnjK$0+oBhZn|vx;+zkenCSt1l^P1^ndUfY49j|xU9(g zNURV-$dLYYwZ~?N4eieAq0*uF3cdH^GQ-*S2s^0?461DE(qqxndoTL&K(?u$$HZ4 zbB#LJWL?55yl}!?>FdW+p0y<95eM4FyoQU=Y)pvfv05Jsr72J4DZId>=~8zr8;yGZ{^4!1XF zfl5;jc!L(R#`RvsM7;J>)}RTaF_wfNP~1a@I-mR^InrZHoCTs`0oX6!M7{(waFJn3 zFSX+pM|?P`*X*?6M~*d3&yym$zzd@e+G*@CMN-6X$QK^(!TxO3N78h0(RS9e8D2Sxa0Fk6FmOew|8nCl5$gmUD zm1$Jyed#-xMDd>d!KLQalC!{tN9rR6*m@t+Mf&fphVx#FDbVxZ#q@p|e;tfKYB8{& z*X}}S3+5VpXKUod^SyF${Zu8~DHm$hHoa%{1t=RctnPmJ}_!&yKRRG<4Zx_ih1f z&P08cS(iiC#}B%HAGZ;!Eqg&6%>D%x&Lc zs^~_RS7X^fxsYw6Rz zb7J=^2WAhy4?RSXrTPzo6=c&7J@hdy;p^=;^VTsf(_}=JTVnWTDL*>LBBLk=EcLK%SL(R%5UgtjfRPd!HuOPdFlA1ajDp*&)An&NZM23DM@BU%`Ey?kQbx zfJu6uzFT9A9??At+e9K#3oFJJ0=xWNZe>L~9EcK26yM?o&$9F}z0}?mWU4s{xCg@S zr+c}qtXsd>nB5AEWVW#S=7OhTc7*8_MOL-}K{rlVze*mhek+Y5g2G=CV4S|+pH#_p ze`O`sTYi-U6&SO4IDTC#&Q$d3_kl(;D+#u&U_ zKc>ThYmkr?r%Sth(UG+3LHZ@7n2)f_X3l>~0X?)M{C$lsZD|cO_HAu9fAL9d(~0+c zl$KnJKD>#=+jI_}jkRzH58AK9iXmO1%VAJ204H-E{o;4}i^Po>JMadS53OX9(r%QXwsg(wRPiDtV>+lZE`-$x7fMMd-D zuluqpxt>R#EIn6bWw%%rIg9?<{Xx_g?4hQ%+XY*qF&n_=wnv3=WNA_Ujq3Ot3a&go zPhp5NS_rE{b#T=YD#=2ezgPZkgJXtG^%*XpPZc@ul%sT}Jx=C6Q(=986yc>KTQK^9 zQD=Y$?0YvMWrm9^#X7T^n&*bJFYa93tf;L&?(GS|jT^pN@uhv``hYM&Le9Y_N0`6r zO=VlW(5L6{fM7P+*{CNqE4hk?yr7v6&yFo7aQB|JfyJR)%hvtT;?bgR-g|shr1a#p zQ9XLS!8EZHIEy_fAyh{GODe2WA_(kc6$Zt&=s|?UQ_>2Nm-7rYFJDWSC}PQEdtJaH zFdgyEUcIBb7lUjss&jn9(jB0i~3a*khWq%QHwd1)L5*HDdTTYHY+L#{fadE*tiL9LO z8Q0#d&HuC4XSdC&Mel5zD4RChx)0!VA0yZ{YA>1#Cy%^5i&xse2xnSkBHV?V6#8OV zVL95=jf#;B-=jOsp@(mmWyVNj`L8&}@V%@sZq%NS(PtrJT3~>l3(3h6$k+Yo0I&1c zqw8D^(6?Prel(FEZglQk(qE)%NIl@nIdOJ78}q+RS;nH$^#a1 zBlv11O^V+=0np(Sc7UWYy(d;K0SBqX@o^%-Sh5mh22aZseNTI zrhCbFbr=G}tA=K1e*MkJ!sx+_`8KU(8k6CEG2GcMXItX$yKmZO2}I(ra^1fO)ed^h42@M%CreRs7c*ef9KFeqVhb4?H| z{&4?roH+u@~24HUg)+No)Bfv8rmX9xZ-E+vmNt%^9fzP~M@h9uk_V%ecX(F8f-h z>KTI=>@A|RhY|`V52jv+)r(&aNJKy11hRH;9(8^_K$}=X_5M=$tF8Wn1*=2vGa4NL zE-M|{AL7$w7uR_)Ou#EciM(861o~A%63K{r z)G0jPy&*PcmrOkOy>LoYD?6{=8VXL_-Wc~B?ON#5W(|%Mh~A$Fcb8~N|Lyypun>Op!O|Sx8FPpG^cJyUgi~`#&vxVdYj54dI;N`Yjj(@bK4_|jB|pmijCk) zCeOA;eD`fGUFF*bDNVb>Lo@j=u?{X<2%86*@vmiq1tc_XI}~oa`U{EEU7}K)U$>eu z9P5%D(S@;juGr5zH)mZzM4El1pM1AsRePfkwY?=C6BfnXfS}Qj!`NeZ0m{DUXGHih zq~pqPp|!@5vbVL)X_LP1^_Q3p_2a*ro?)ip`zmsQ z+5d8oDME`+gc7NTIq-6`9Yt|K#1vEv#mI!)FrL&Xu;w>a4*_6ci}%_%F)It?MOS1AG@! z-v<%$EMM#_k93}~5_+fN&JjY(FNwY*jEzONEOW(nM2!BFrd0hJd8HdOebl|cnh-Pa zJ6%lFAfH$o!wf&B~#}O?nf0a1YGi;`0%)uWO4_?x{ zx>BC0+4dpS(< zZlUypG43^HvofA|L?5x&BigrrXaS()>u^qZR{jjnP8f+pxfv6})s$d`lg#F8tUTv>bGcc}2E`LAJX%cb63*#6gc~F4t&_v&9`& zE;tiI0PXHr-HA<3Jj%+w>RbdH%87%K7BI+o=|^s#J2U8ZxNtQ~+pIU?i?N=~8p9zN z5pc_*#cqpc*GTw3gU(hHS@xw`EEoKA`*exzwt}ToB4qPh{Re$=HUzRj|Y z@y71OwV&ESot9I1j+xs^Tvg48rVLEl3TEA8f8uUgXw*C zoPYo*$|2}z6?4D$)qY^Hfhu5Ipl8E_PxUZWA*NNS-xhmgByd&hV@`#j>E!7%T2xZq3sYYJ7CjXu4%t}UNX z04YKqPmv=@x(+>dFh@Thfqga&BPGhtpRpZ;tHQ|6ELn$s`Pdz`*>1Uw0hgoBF_Nxb zOAMym#86)G_;gtK8p1u91)K(ySKMu5A$sRTvSy_{C=(j2I}+1q?&CK5gq&7|o#n7i zmE`H7=9t09`y9$Y*W*f*)=b7;EN35|Hh#x+c>U5_^Neo+Chz{%4L~jvy(sW{YJD#rEL7lIyt*6mR(p@|^dIufn7X(x!I>0aLUFMt+k6!iNQNKQU2M_L<*%EmeXvcUz{GGg9Ef z-lYqOH`Z0j#mm~@YH6Utb;Bmc3P;I+*z$6^4FPV1t4gcbT8W&>D(?!T8h@T*2HU)) z<&f&3*q~2&jrNbyPEXyt9!1#JAP@pW%P^4jNG(o#k=&5QA-^^{Cpi(KVYVV1&Y`u4 za_X}1ZkJ-jX36zE4a@9j5h>lLJ+u3%`1KV zwQH_$xx#Ka65(j>?r0Lb_SfwfxI@!^yO4bq5+AD-GdLw2MQYaHQ%~za&*=eNNMyX5 z@K-G%xEQUsQ5zlBd6IiG+x(_F9B_5=Q*ZZ8=AfXout7ofTL`r*>-rG`>B>D#uh@@I z$e@U1&lJgc5^leDd*yD71bd|Q`^2`r@{Pu*SthOCkFHHE(JzG{JgtTlORkHx@#N7J zx)sGZU4bMoC6)7WAO;lpn34dvm5Pps^%|eQEn=_d6KIGk^BEyGIBx@|Z0XM@= z=pO3@Qi85@iKxff4x2RZJPNpDdRi) zvP;p&A*%M>v9)lo3%v~))ZyNLa!9EuSup#z`4^5_2U(l_@ zwFP$P%r}eD^yC%9umWG)bXGg(JuXkNTz5!AU_d)wn3I2`Y(IIG?rsx50#Cv+)uC6Y3iEwzK>^&)kI21ZD zA6>GmLpM*6EPmlmVW}THFUHT3l;BxvT$gLeJiGSzR2tgD)T7+C+zR0K&e?pRQdMDX za9;tRPK-adO!a;&owjb0EKy)dFXKH{((Ha9!|f`z&SuYdOFuc<_PEUq0?Bv&dM`-H zgpeG7oV!K9@s4}RBN!*>H;S6p?k709H(sSL+{IKKZ&O&N3s7*kc6wTa2s>7WQW%EU zVf1h#Y#cZ7P2sMfEy9cqIA+*tw#8dpX9UFTu_P=q#JDuVOZB2irPw&18!ncvgbTY5 zs>X|T+MJ5d4(*J=Vy&<+!`O$@qHVTvg+U zMHmgWYq`NC;Q#On_Z#DO)Jj9gifFqWzo5<^=@9DZE<_;yqQQ2ydL*!s`ho8oXekvV zW08)Kzvcc%gkvmWA8idYQwmp;)0Pb25?~CK%zKK`4lPsI`_#U&xxEo6x?+h@S~ROoTf6bB=iABa7yen`e8>AucfLQQjjeYTg!$U^wE375}MvGNnD?sw%p4k|e?Q6?9ETJAy%9 zsNCrlzKvozr5jA#ddWQH)I~9S+tHk`2KbxKq~|nubDu#7W;WV>HE}}|F@xnR4HW+H zWkf0qG*vU^l#GaGOlY}l$(b>*%U*7g?}Iu&;4k3}Y1hcvP9HS*WMth2Z(~WU*Gp3U z?DW7^$gR~(X-U~-!tl0eYz2I5P^(l}l{R+@O!g;uoIRM(kj0P%k}^#qm%1zZREkw> z0>BqKz}z(XN!E4^bCAh=IUBMrWMvDU;o0V^9G$Z+l&*X;ZRg5cNY83qNkEs~ie(8Q zoFMJC266*?<}3bGuMbqK!2>{Pr(joAdq>Cx$Z z45|lwVn03&%TtcA&3dnlr|X*`npKSWmD}))njH(pI%bENN}4M%1$a&71-6TpMPoS< z^*AWy&@L)BCzEpzw21}es(kA&3=Y~>o2)@;GuT<{%D6>Mt~f18;xzr3$8m;awp-Ld z=+O`WLpy^DJ(TR}OVO+aC#{6iIEnj=^r-Gy7fwE1Ms$|Y>v&mw^Bd$2nAUGtIxd#?!lMVOR`w2 z4TZ1bHxmc1f;d1q@f2Ul!YOsRbu+=_rvz|f$GGn5RNfw+H%N9{s-cm}4Sy=g1`<{n z`?`{0Wq7l2m$c&KyTfv_Eg5*{zIU9wM%Slk9(#UIqCCUqfhkkT;8XJ1g3aZqj1^p* zHMfcAx>wP&p3ph3JCe?eT#m1nqbb?Kmqq~`*ND@bOjcV5y}8PB+VW&INNF7VPQhbbX(H+Sbft+|Wi zM6iWMiy<6NtxHsCboLWJ2kCm58BR0u@4Eut@s9cMl%^^kjur&wuM1XXaD9cl!?16c z1M2N@S7_89@a%{fWb$PLHW6B(Z$_uV%JX?Sp5@P5O*@E%UX+qsind*YvVpT3MEKGz zyvrc`@p9gNJ!;vP*O+xi+~x#n(3XsMp^hfiqHT)ofDU=Ww#S}LaxoTG5eVv7()y-v zgE+k&gsF$p`|zeKoHe*9RUCzJ6yAc6u|)S@ov= zg+e?W??%k$;YgkB%_)p?Aqz}F3vW4TR;|-dGFhva161|F`}|VcY*+`0P)r?*kSWFw zO>^`C`)~z4dBKQbEB-D`G=%NQ#D{E%@KR*qp97G(ixNNn*wRkUMk!p5*(5D&Y<5Ml zClPba%<#EWCc)RnH>U#i6zLY%P86s!%GWsA>pmG$@m!UW$tpuHSt4c4`5=$`s4@e% z>7PjLWi7XaaktO|{xF<804eZF_9i#Dr&hbxhI{nq0_6H^M3~dEN|z`&t)>UWwl9sY zWdJpo_vWeY=LUwnVF*`>fGiD%0r1GO zkg{;;LkCO{Vi+!&?ISwsru2r|#ii94SYM=30EpbWJqIniUn*ga2GL-!2I(ccmxDLYk(X`pvLP43yT6W3DipeQLI3fV0LABb~<-`<9p>!V~h? zr)q0jx%8wZ`B>Ol=wA&m-OG69mTIJGhqmhY#^6((eJ$ebuU zINFH%%J{Z!(m7ghnhO!ndW$L62$oYipWSu8&N;;ZU0bp9l7e@||I<-Ege0K-4Xey- z0%M|I0||x`CB1a%=(oL?g@_m=Gk)u>CYd;hx7#XRV!O*ruNzaz`p5)2N=g&SO8;1Q zBr}Hv^dYrT1UP{8#PbUUlq@F8h8<#RSGNkMm6r~OpE~kW=1c(1t!@zM{oM#)bdk)? zRb;2}c={UOxCINvVNI$CHF$JW4j9mlD5f*5Wyn5;Uz0p@d>7?$Dt%5BBJz&Qt8M*z z2A_59GOgJxllm>%&k0*Q;WrE5?cVJB#4K?VUi$)Vj318Z=b{e5*qo!-^L!~K&<&pj zZG*X4q~ab0znl!@4Tqjzqq9tS_Rc&%{LCsJ^WsfHWKCFL8F;(ZH>p61XtHf=WwU9l z$#IDbqFujAruFU7^+@RD>$41Mjr0s2S&ihcXpgIT9{!q}C_`F^>dBYGhTN~yB76}+0jD@^*(Bj7(HXQh>g>I1#pky7Vne{d zu0_cGJUdDH(>40Q!sGS3o12mQIlAGxGa05HdvGO?`14OXsRs95yMgB!#C>YZk`>=+ zyda_AGJ#De%fT5WmuDL5@}y(l*JPRyGMPS!oc2GwlJ4P3S4ASmgFEP16yB~!ayjaR zbG&z%PBv%xf&v5a021YcZ|u$?9_p_A+`5R6jfhALt5%1Oo%u#EpHB%q z{I?gwBKl#4stPAY=6zr2SqYRisr{2QM{pqD4@?VqaQ3=@5RTVfh;ojyZUZJTg!6iN z^GPHA7*tY-sd-ph`^!1Hv;rB4A;L96*Gm3LwYKk4+!Uhpn#W86E9U1ELq3t0e1zVh%kVM7gZEKL=aQif z_m%BvR)p*|_1dJ7wR@q)l-Y<`Rgx|?By%Zgy58>OrwDtn+e$g6rw-KU>a`)s?~!v2#2NB-HMZi@-7*NqV!DP8 z+GHB^J2@vQHhVRFj`wyEN+QRmzw&7vJa5NnWg{iJo-<2oHUaOXgj*)@V4@s0gTC}9 zt61F|nnQrMPy>L-_xh-mK)z=QB(0lUBY|`EB36topoXB@ zd<0jnd(qc7ETMUs-IyR;;oAJ^lwP*j0PEQeK{QkH^}r!rA(WqVCN&+1|K2FKoe!MR zfviQqg9`jm2xWlGd(iV+AkjW(uz)krlpT=9|9nU7*ZW_WcO0s00c$~E(|mKD{$PY7I037AQe`IEB_}ljL6|N1t1-_b?@2Q3 z=`}}WyOFK=`I~0J>Bh%p0O8KPl?&KTCb%y?G!x`_d-K-Y-e%$l(}z7Hb+!_p zf*Q(ZS~{3{Q?4+9g+MDJ^OvlXA{(dc6i?Fil55<9S)(MTpgimdGmm z(rE}{K3Q(8sQZO9U9a&0WCl^zJ;il&set!cXs}5Y@i1%G;TcezE-Z1SK1kO!A}8=5 z&J{}V+3j1HRd+1|6R#d-hSF9RZF}=HI+l1Meh19yJb!IFD2iF^-W?(!954k?PXf~I z!3wQMqlZ1Eo%V8m%bkmmw?MtDaC2B@?#cMM?_Owb(|*f27=trku_0I0Pp!q>}4_oLvZbd3uZ5d~k)?Kcu zpH8<(oUX1^N32Y2BorK_aHst$U3?6oH#MrO?U3a4XG4lvZ-qPv?3`}r5We0NcRD!W z(;CGeYYfL{A7i<^54=ZF_*y&ThW~@4!i8K#M)dqhlp0d2}MdYmu z(y1}+(SPh8Aj`{TuN=s}8FbqXB_tTue;KkJ8B!9AY3WNb<~@JT)yp%w=O7uX2??Ib zZ*BqjRTvBKXPcJmINse>dkZKqGqu#&XtsN(rf+I6$`*QOT?MYNl<~BA?CprhY_S=x z+>Wj^^5r>|y_%FSn)eJ9Foq)lSN>=Qa@05i`da^%Q?l*m;dFpiF-=jYZ9Fw zlq1z(olCG+R5$-ryRgk818&ND$ydsSCHWCE%OFPy*wbyJ_#gFZ*q zGlK;`3dAgp(uA;O_8aEU&L8){2cw#o z^9}c7J{@p3P6K`uiy}H_&KKCj3Af;@7vW$8#Qk_pc3Ql>%4>=!+4|NXdlWWtclC9>#>7XTpJh zP4+t*#0~k{Ea|jV@02f?J^bE9=#pLl_k{}@Y$=v=>pZ*s&sPJaDOa3x_jU6SA&qOH zRD*8MI^#jVN-3qC9QysyVVC_08N!8eHjD3E15Y*)Q4BOM>b1rXssCE0+=Hs)1?qYI zMF;y;ep}2lSY>FP$}}za>((dJ7oCUNg%lbFoj(d||7AUnP)m zHU!Ox=0-?=PIJHb{C0ItmI`CgWL+m6GtwRNO`{ufa4fQ4vWlNM2lf@;9 z=q(=})G=G02e3N6Hn&nmR}juk2{AG+*Nk5+^K>d~##BT=EoUu{+a&YB2jc@WBV)#( z>PXK^zN?laEa0eqERJYag8m)AHgJfJbHaWFYOHA=3%~wB31UIgSXoD*6EyjNKvPke z?^F;1b(m*T71_IeMuo&fDb&z4b%1Bst&6rCu#}T!1Fl6C*?M+o2GOXT3FjPJ4mF2Z zjbLQBe!x2NC@5JPnJLU}Jx%jX;8YY)ULwQR+KinRnWf2iI8R{GZq~mn)Xdwj=Tp!1 z4V$=CH1XfkZn&qQGaaElgS!TMAG&;=b^|RD<-}Z7?fJ|vV+fz>Wlu+4HoZ&?1s3C; zMEgRH7cUmGQC3kw0GxCIVSsQhn>aM;YvcFoN;&5f#NM2FiV2KdM+aZ%Rfjl^eBTcG zAzPShWRLcFTi5r_;&ku^3#fy~;ZY*65mlbtC%&IUIhHyWwpLfE3wI zjVe}gK4?-grw3?o;c*|nu_ws2gkvu_CbT&a?QC4IvxiS$+r_3=QR@~wac{VvcQL;C zu<}5=se8DITH6!obwk6gK!M!~9`wG_T{{V|&>!daP8QmFvSNJ$XfE>>ENHby$n z7C8DnS+5>E>t&Jc1vWi@X#y-uZ? zl*=Z`d9C8rZu{|yHFIm2WG!!18#j5$(ztG%v;NXYyc9fh>bRAG_l&Y9|u*M+ANb^|?=Y=8lB96h?Yy8rF)rm28Deffnd($Z7ENqxbr6+j69-G#uT;8%E#16 zvjU|`9i&%ugob(Y$QWkPsEDJn;zJiG+tV7+{6~jyDC=3lq&$t`-+epI@O{g&{S>l9?I_00hnyZ%7{scCASEMMWjo%?J=n_M_ z%!sXh>6Q+Pg`_^vI+8LlUU9bN4Xn$b9%?jhgyMc$$0cFByY3ObaqSYmvAS6vlO1o; zQ{sYu`?-O9avUU2=QRmizwU@LX&~(M!0Q#xoRt>#_MIA{YfGf3dCxT*_Mk}ztX=NS zY0IruA%;DWtSeji22JVg@b0^vEumWpnyJZ!6_}{}0yR0H{2QlI$7ds;3I~VfnA7IB z9h^afV-0z*ZfRVsk_#G{a0e)>vgZV#Cx-_PzVt94+!A)>?TufP8il56y|)>MShH8Q{!`UUD&Az$eYP ziOc3|cuHOWMo7mdne>iy=h<}Wo`uhH@#;rw!OQ#-fz&Gu!y9-DPa5ZfyMErede8mu z%%|Z&>jGNvkq|C6dA&v2Iga-oFk-<(P)M!M6TmGPok2;?AU(18jfjgz=L6dBR?`ZL z*jK+oRy)JdYYei)IdpLz?4Y5wG z#FD8ORNJ-!iT0FTxsd{qfTk*GCNc*cPq7A(iTFWzttUZ<5yW2}Zx20POeg!lCR4VF zTzqW~I>8*w%y=Gy4bnPh+AGhdV?^$_p=|YtB3<0bynOwWEX$yK3HFZqH#g$#6E^|? zIx6*5bE$NFkqXNTGu^)-6?B*G9$KPR6<(lGtYt_nG$J6D05)f%1BiBzPX^B?M3tyZ zGB&oM8KgZbU1pyELlPRbjDeEO#~b;5Z8W3lV*I^M>4*vZ5Z8cTX-o*a0ZCue9y=mZ zQq?){aNu_1ji(X2U*2$2zXEa6xSS#a#8cXwX+%ns^a76vDPGpZWLc(8fnfvK-xhtZ zl6zAyeNPG0UpP9;EbTV6_f6gmV^CElv$4{3KP8gRknuY#*1dy`PSIs!gWIw#@!`JxsxaWjv-4|3vQ#|#dlY)ceJY3vC5`NTg{DnQ%#j2VgmzHZh`C?4p7$c*-?2u z1BB)aBcbWcOH7vr)AqZYJX^7b>YEpMLD(vF09=9EmZ^*a)QUdfLBdd3q8f~Px)wDs zC_t&wjvNT8Fcw=0R^w)N5$<=<30%YFX7el zc11Z~LARZANp}n8u%S5Up6`Ma01l{;4#&?_d$}cv_@-C-Qts9=Vpm&DG8k(tmKbTycF0AR)> z)kyD!ctTOI>WijA(lv|o4xC&?aY7no&&3d~C=uazv_)Io{ojgine!tct?-XuSzE5f z=`tR;cHXjuhEL$XX}#qivO|9l+iF;a)PJ<69_ZMxiSrtiqKL;D|8NiAtEw1*o$)c7Ggr_!(j> zdV_8kfxU$}vHfI4PaJ;DjvL?PZRH<(i`~rYtJD`6=|U{4{rex`yDy zIAA*RC_j)OrGMpN_!6K(6!hiMVt8om+d$$uvve_RfZgPLaX;2>`?DAV{$F+k7> z4JqPh&nsw_Q(T|PE~!>q((OjC3-hIfdzh!xl)5(PXy1lZqV*tFB4^VG<&ZG$eI*_^ zF(%hp8y0{~mp=aR5gt@$)C{ReA6PgIdhQ6&gp0xbrpZ*79J4w8wD_`szJ}qFMgaE_ zi(_v?7op|qMeTK5RK)ueLY&aF*gX?(`}<7FiSlqI*unvWSMLGry*PoRR5(5h{&gk@ z^QNzqY}wENRJR(tl}eSM;~0uP>b7visFCzi{#fk?=PMnFuy?FjUUF=d2lrm(CF5?) zk>%2>l#=9-o2?9jHJqmCAQZB6T2HM4v4o9vxGcQ@2j6AQ-FW}g4Pnqb?9p|Bw&x7NGZ)``3GtS{uH}--LQaU#ug+d zLQz1@PufjYI|8umKkbgp@CStVUJJ!Pg`JPEjEjK)3KK#*>dBe9##dGCp-&8#uate1 zD+lp1d|9NILw!hP3xpF&mlfFpd`2V~_WP9&m>{&27FW zEG@^dyzVcdY5dlhCnG^HQTI`;l^@n4#jQ6?UJ6>6SQD|s4!?&#TPfF!;%6q@-0A|&y%C(fJKsMe# z)NMpa#Ti}F@gCw@&&o+2<@G)B-9c4@_<~q#5xp%D=ZZ#9tpK@BqE22bQyFJ(nQeJ*p1m-Fd+4lu<{7>7R>!4SYgTFX7 z@+*0xhi^@D8ayTXbP^LM>^h+}5#KE{l*niwSXH&>FG=QM={s1Pj>TP8Zl&T2qFI2Q zZ`Wh5l-G17nqpHo;Ig=6E__6djujNBciD+1Swq0mMY0@ zKn*go==r_z5fJRnn3M4spWjSbr(hHg;cwynaUNof?1~2sOBj-A)n_Qb&Qa~)YdF{9 z%ME{MtTSP8ArvwR^ag+fZ)mM==Pi)B4fXe$(6f7W3NCCX3f>X95pz8v6_JBgBRI1Q z59{;+IWm}KsHiAX8Z2&4=%(eE4!T(X;mIN1MGL~SP^^s6;YpOjlx9GYs+;pUB_=j< zCcE;2HeKUrfku&LJK)5+JQkCrvgq=s;PE_2iqRElRd05mwPvH{#mWF#!uiZ!i9qSk zesczu_b4#i=%Re{C0d+kMn4+t2!Mjjh}@xm&t-*B#6m6DUS|DZGy8-v<(GiuNFq`A z!k$cZ9ktxo zI9*qgPvlH18C^Y(dR8MNoe|)F32jK!Xfb^DVa|tqft7!zk37*&GcP4CwmRSi@-y^L zKLG5>-L_Js#@e$ciUt4Fj0i&Bw-lgBF1R1k@O5^&QfrMk1A?0O&h*9I8sPo67bnn) zB?$^{X=NBDsC^>0XbgrSrT_q!*fG1Slx|yq7Jg1-X4oNx&r87|-TCMeJxUY=6b1Jl zyKILa8eutF=CYd8ydZCbpumb_B2e5~Xj+9RG<9*0QQ{cdU!-=54&W}pqlw&w5Qxs0 zUXG)3HDPgIx_zJwBNE(G>J||iMd%$Q!*~FDoS6{_I~NGgFXyLY@q9YYk&H-&qKG2G z=n=|W@*JK@8Eu(94wp!UIf=rVosmG~-ge}hw2%J9YzXe$vLN};a@)_frW@F5Jyk-l z+j!Ncq52cIEe@(4h@rI| zNCY^!0C-A%K&QpFIZJpsm0cn&mNqfesWII}VS6ekpIn_*R`OPO2L84^gdxD6eaU6_ z(}I25Gr;MLYAPq)Ccqd3aoBMPM2`C|moCsTr>l*IdxAQ!P6wN2H^AQ^ub~HekMm&T zWSIg~Yk?rXKS7{mxrj|^miogl)m-hxI~5&O7A<402RnyxOOERcW)55B{<=9N3nn9` zo};qp?g!jMK&z{9uYI=Eq|eEDK}|*E&2FI5H?C2JMVEuCOrItou`IR+vv?#n0@lu7 zzOuMlo5HY?!{}>{k`Vwc1*IG ze0;rIfGUs$7Ja6yox=oZB6LCGevFAYGm15E>l7z{w@NBlIJ93n0w^KD)ig$r?yec> zY)h$h>Au=*M@nML5@{28L=l>kc4(E1w<8X9oz)+qPRwas_z!0)<7D6iuSyw#*%^ZU zkSNIzyf}|LLnPqr+1unBBRmWcRW^l^V=5yd`&7D2`!)K$_v%(Dc>QKJBQ)_33Y2pi zUV_(h6M|nBrQRNx8?a!C$EVU+Zml|0(r*ziCTozEZY;;ox-@5mWPXxW(fIvndgFO8oii1_-ns>j+95FT#~ z_>PA@=+bt{8eX8bi?XVxpJXGAA#WWCjAK zuY%Vthhh;`j_N(juo-rR<&qVLR>*I<{lzE`1&{^b6kdteToHp_rtsKuS?!X;dUB-l z4x=q0L%8H;JP0wTaLDU=f)!SeZcB2YL$}cN-fESShu_G|e$UATQvgieP}69Nysmc4bHCf(@-bAje-xtX@-zln z)ggRmMR@sm=ky)>RrN<~bw#08$OOsVOdpjy-ebuUGEnzfHjbZZqQ&S2#h=50HTy{3 z-QgN16&e}5Rfwl$hA+C$PX6Uq*4x$a8oU%C{UYQ;FB_@vdEc*sd0uVaKhYS{w^*X1xzW{P941k z#3G?lFKq_bGBK99DqM&TGWZ%`3A)X2#v&^A!U5wr$0>a>|<4r z6C(BLP7uunw3}YK!-4GOzuqD*qAmDjc|B9T6bcKA@` zN*;okXVpOb%C?PSOuIrPH>cO>9qD&1T*bJzOO19-kHfOIuS>QfUvi=kXBt!$rOi1h z*~}Y0^ol>_nZ!0!uz)?jlBkC43?n1!^h@mL38ne^H+z9johAB_ObFLi)@cjCk~X6BHOR_ zy#!(rI0MvDZ^OdO$Q`X+TYBQTKUp$`E^(=RWN0pX{-` zA0w4M|B~5mfbL-8CYi<<(4g(Z7qOFvLVQ|R9T+K1Yiw5auto$SW}4FEqcA#0KeBJC z2aJ=CNGY!U!}cyLrU@oXGS!*{J;XEC>HuEIrF*CMEuvY6E!NOc2s&JpC2zhh*Su6? zS%v}a9DiiOMeEI`wdG{?CyY$WX6P4xoUNWA62F1jr+x;@*)ygtBs|hZSa7w+#;?`I zQO5zq;apGW2r~{`C%G98$aXPq^&WqzoFhlP;gB4w#qFWQ#gxYPt1Z<|az?(#ps%r-3_PHl3aggY#@M?t6dkKV3+~k8`i^M9ULH0adU2hBL(3sH2i+v97?awg8x6bt)5af++ChsWC$}=~gD0LF9!pw5K>I>l z)zE~h#c)4dX(W?msYc?Vyg;OmZ3F13lhK=&0>ag|sWj$z2$7i=A}AhuUO$t$f-g*p z#U00Kc7Q{`+x~TtSU}=vBH&_of@g`>-n!_A11Z@_n`FD(IyQh(VOjQpL~xCv?;Om5 zqdrKK$^1(g?jzt@^k&dC>gY0PlBX4@5_tOhfz*dQqa>h2O6KUSYYSej_pf6fHYRik zJ5?&^J)Um))E}1+)50DSeRh-CE4s;b`Tlb$#i?b1Syz9C+NErSs+lM^_rftMbXkU6 z4<_E{=G&9n4u~|kx_vY}6>B%ON?aRb_nPWvh%q_z`%tKfzD_Vqq$w2E@;r;N`8SYl zL*7Im$6Kl%Q7(!0!O9Pl9(L5x>`+?G8Sir>s}>$dT2JdF6D!YRysk)M1>hg(iE2rr zc^hyfRG50o_3Lh`R!>g@Qw>FK0wircQA^xYG|Ujr=LNx8l&%9n^f~#i@sQ)_>iIa&z@Amb z>%!a^Q%S49Bojt}Xd%`+e0ea}@3!o1?r2UG>}rOMWEQDJ%CXH}52)v?H|#yc(U!2P zP=ph+>j2tS2FT6!gYKNFouA0~#C@p#bnkv(RK#6{&P!}3^ZDT=qxlM5BFvbxB&q;`N$)Q7?t0l& zCFd=39BI#@`%+Uqht&@RF{GthG~t&KM9W(bgGW++9|70KBE<u53JHu50PNbO7e6;8DOEo%DZD(c!ZFU!8vF@Re>XutG``=L=P&vGtL zoWD=7pt9A0IPM^-HLXfSxKYpl3EWH`19N%jE&VP^n{K&GPNwmT$VjNlS;In=WsjH# zl187kSW|2~}I0v3R6mOu-D4Lw8Oq(K^nq3W}wDC*~Z8X5B!hU*!Hghe^9u zE*kz4P-6a?PbW1<94uqWbk@+UZsm|b(k(znrn4; z<%s(DFm-lJqeqf1-8~y9ETA^b53!kT++w}Ck6JdJpZe0b2qa(Q4uw2T=4RqGXt*s0$dO^g&44*shw4F)BeKs5#f{KDSXQU=BnG_s?W689DHxk+T)mIu&LS7AP6@0|HB}K zE5-5>SMs<>0Vstp8jaZU_bK{M<6B#Vd7VbnNE7Vpv%45ARYi6PL*tl{r0fN5b#?#q(lM>U-&OKlJTYoEE3KY?)4dE&w+f%Tkr< zOB0A%E<)7eIZJah>0J?XT#MlCU&-pktcog8*^&B;n`C_gsG{|i>C!95DhOSu(U)~E zGnO~VlDcOSPz{)T{oJ?qJ9!k6+!p2nQ3dxUKz>XdC0)R#TQE^O2x5ff8^A62+!<$h z79GX1K7uu-?Bw5jRtSDhkJ0Vdb*LgNJ)dzD?NIR!`+hi96h7T;#}jmmp=>VBdLf5)iFbo+Rhc-lD>ol zt87LZm(eAo&?kll;ZD;$#|+_p4odZaoay?jRRnM)zqOP{*~1+)z67W#hb^mI^=ET} z;V;)ZLOb1%%zizKQ3p1bC#_rQh7w>^t+-QEctc#p)Ue#QDyiZ9fO_{yAtE6ho#KDm z@!wpor|XL1O7t-PlZdeb-v+j1+=`d zZ*%nbSHHF3r_Ffe`(~1vGQd7G8GX^yN&ENr{N-EecfdW=2j5oxVnmUE*Knu%Gl=>- zl=}Bq(GNg}VCkoqM8Nz~_~@ThM`ily-&*#Y+xtIUd!Fol+k&S5yw?JOduX%VwfGQCQi1*>Fz+S&Eu!;} zu5C}I?o9x&ogzL>i9ozh!Jz+Z-2aDWQ%8S8r2b?;3sA=ZEzATn%VBj{nF?bB~Xvg#w%BMXg z3#A35A6_QjY_&a~t@Z-n0kxSo!?2m($~kThCc&1Yq9y&~(I98Ue6{OOAX=?#79Ic1 zVYS1tD9@}vYgr5EX;370dpOQOi8gpR*Vx#ZU}@u@ue&69a(V#hy8{T64J@@jaBO9; z>I?JTpO4G`2;FB$?aO;pZQA(=80kBVSGX{o@MxsicM_n&Qf+WDmt0*eU4~;AMjwf< z##eK>e>~?MxDcr$4B*gha+7ip10jHY>LrE>XZjCK-8oFGEL%XQ1WcH&fLs5v@8i=( z5dBooNyLf;SOC3_Fz7T4z)-{jRc!m5<}7Lb)#3#ZN!k89y8Mr`=D%iE8@m|!4h&}x zjCwlEKfdYr-J)YpCdHB!1ugs^5Ah!a3TbkTC-VoRKJ~9Nz&{anSmQ)FUOAC{>gg(>)&9C0Xqap$u#Ysw(ei{Q|1kD zV{S8-AlpAS@4x%O4}=bk2!@*0Z^fPe8sz`q5C2a?Sw%7y8xr;(Kl2$PHPutso)jG? z{XF8OS|vg8IRC*0^m~>3?@<2Tye0qN zq5Qj@^M6<6->%dDU6p_5$B6#F7}%;@gUz2=5{S?pVgJpk=SUE(wVCB`3tk}lTZ`ZJ zUh&C+!tNx#x}tvmZ!ap!4~0FME71Y__q!AUc{H{^L6`}L18hD0zdeiC9Oh*@-!RK7 z#e~1xJ1|983XsfRevxUzG5z{)&vHmb&ve*)RsT~^{_plX>1Td9l!>8|FR_Li5LY@G z{##c>Lit(zU>hy*!dCdy`1c1^X>q6|mPAClkBC=|ruaLauHHWX&EcXZ^8@IFt5Ywo zyiU{jqC)aHqChA0v7~o19g9 z!U{ilKhM+h?q?n@*RHPfXp+vq$||IQ+l;7y@~8 z6VxneVknL);^kh|-r3g0Slz>Vv)sS`pi~=L({_{gP2dReeHH&;+@lpX;ogP+h>Wu?()6$Q^%6i?!fKsvjgVc4 zy3E3wE&z??^C>KsLV zxEfHHy*RQf!~E<0)JdX#cQ?6emHv(op^(1sc*IQR35)tj*e?w_IaxqC)GYXGdBUoi z8LjCae|UGO*+@o1#o%z7z_+dN4AaYb-`hsEfA8a76g(29 zMIzh;f7ln8$*ULtdiDRSO%)?hvzUqR{qP@0>xFq;#0b)?Oq1esS`*w_t}_-l;u*ta zFT&v8)EkE-K1v8?_~LJ3{N<&{5n)^p7nrSEmTBL_-_wulFWF?g-%!0wIB_F0W*n+x z;Cx_{Z&21$PpW94CSRwg{GZ+|u5j2|sarih>1_C|s$+BXx!qfp z{)DBG<+Ok68)+jyR^B_RMOs@fiQ2>H+plP0YRT^1)_z{Ru z=L|NKh`iI1?Bp0|xqXw2{5Y!TM}I{srAh0d|M}l$p%IdWMcz)Ei|hS_tCUO^7Ftaw zXT2;Z3p!S619XEAc<}FLWEB_NS_ivu;oe!k9X_pw?&gl$BPL1EPI^Pvy>61!Uk3R( z3?)>~=A%updBZ~obWYJ=-Oq5lZGUz7&}08Uw@c{;cZKJYThUN(B4bykuEI6FAxiKiW-RZ#jf51GYXe+eb*@JWAjKC;)T(C8>?x5?sn@^2)@Ma|q&O&P-IN>FqDcgJ; zyMcoAcfX{w0v_iWO1*J7v_YJWyQ)|B(uScy#6bY{#Exe;Z|&V*RMPEyC37;6uwZVR zsYM3`xW*OBv*dg7t&IWtxCg_f%l2Qr6MFe#T`Ownftn_euI3J9CCT5LDh4McbJdnxe6P;^2ErbdCT$yZ%ao z=UAYAAwQo=is~0W$!25%o8RTR@7?J|a!dKEmQvcjXd7V7b1l`K2`ny}t1NZ}`nZLK z1AXnx1W=a_fMI{?rT|yBMN!(AU*oyInTd9t``^UOoXq_qs%}M0#v5o?FgKf(4Ai|F zHaBr*z!f57!PdZ$VoUALR78^8Z?c9IFI}Rv4eKRtzZz%x?*RV&>4xtmV0(FtO*+EC z=HaX?(E6V(nWaF@$wEI1eeBtVe{~61_<-{<)uVQR(85IlaX+d%_S?UI5q19}?5qTw zS%0PNOSXQ1^z_^a)aM)Y)~fZ&~w?y8idoS)#Ue1|};!w@A8~A}+3fcw$w0l?m)| z@-bZPj4&(ZP?%dUrU(CU2~Qb`u)RdxkDuceO~99Q9iCO({~hr^q2H;$ONcT^-ew3* z`HsBsiu}x2=b1yTt$7ePQ!b$9lS+E#9-aB$*(LZT0`Ld2mR+Bds$JvnInY-Wor|#L z7M)xDx56sAco3TMGfwN|rIxVZTyb|@k*v?liCvJ&Uz(*?rwy&60*5J!SrA&m0)25> z-CJRECjXW-VbL8QTn^u#{;EVO*FK&-XlJH!8!&On!EMDTKy$1ED`GApnjv&X)tK;u2$pB02D`xWO;?f4A}9#(~y^0hM6UVE_dLC&Er#91xu)r24D3 z|NYH{dB$^!fN-S%G&^b(;IM4gps7ig(z^`i{e0-y&d|Ti{02SOIWo|e`=a2Prf$Sh zkdcEc|A|-r+lVfxKRgdIwS#G3g!aUmq>AN|Z&6WS<{DRPF=3c{j>fg%51rnQ2sRJhPGPe( zO9G1VkUr;E1+0<-i1ygK{GG}2Pn|}aErm;h6IWxj8gZEZCbi(}CjEHS#RZ+ua7vhw3|>SWL@x^YJ%>BGu!IH$#A?`o)Pa#NK#a5+PtV{P%qjsA&I>=Mrm z1y7&&K$U8of%oc?#X314ArKMdwiBO0LzLMMaTaQNX!j46*vOc_h~fMVKnkVt&*$eO zA6oP9TBU!E6&jq4IY*~>7cG(s3A?z|)wQLsuh42fp5QPX6}OPzic&m1)^)P<2>wuD zRi}Q%&*>Yr2lQg)TLjjvSYWlqGVS?joEm3>XMf`jl~XJn$^VA9`x#f`qVrXFJo`cQ z-o8(QGOfH|WpPjmxU%i7h8VWT=)QK#aiAU8H@O?M)a%asxsPySBkT0CFeH}Bw*3gw zZdiaXF5pX4N5KSXiKYl**{ zPi;{vEWn8i?tC9cA6Yz>Mh0MX4p(+`ZFiG1dtut_c5}WslgLl`8jpcDffw?&ndZM= zvR7{*la>lpvF72kYLIjMi`9Rlm*N7-R@!k!?nY?Jl(z)~$HooOgmH|f7&-V^-Qyj@ zq3Q(-zKY})V$u{wGVpF?MJwuaXGhmaC#Saiml2tmyQW$l+9|B8pYFmbz!@ouY7umJ zAsKN4e=P7$m(VS)0J-M0DvNhYs$`&Hp6Fy8f9TU}y$6*cbtErC*<}wM;fjmV=b^-uAQxPfw0+&&oo&D(MvCLbP@ZM<#=b z>%2^8dENf9!1vdU_VPv~wYy}R>}tT zj!~JPMB2C7-csXIUH2Rr?CiR@pf?k!a0GoZ54>U;J1KdKSlb9syY4qK_>^exGn)*Q zznQIKG`0diGEV3Moc0jqi^P;eIPyfpGSDac_@F(bQ`?%S>Q}&iuevpO)3RG0(=Z|A zb4`LYohlj>!+Pm=+!J~ZnA={0t~xF|R~fUk+i$noBn&E0%=pzTT((rE960UOTc-Eb zW3*Z_diBT{u-U>iLx4gUmXwty$@B)led{;9<(Yps1wAg%L*MUskEPj^7zN$LL5_85 zTuy!jw(o~{e82J|@8GFgPyLcnQdsz<{8x_}rr~BaP>3c=(oiQSiwV+uHFJA)vF~Y6 z!!}wmxK`>F2D$@WdF@kEaw<9s`C&lzQ?3%CY9AJw!ojna*X~^^j&nn2DrO4dthSD+ z_2o+`^CeRu0U^7i{D;et+8!f=cjm|EdNn2(_GjeA*oV?i*x7!L&*{=PKiz5HPqSU< z>|MZmTlHSF)BQZ$FQ@i_%g?rWNyB*o4jyL;T1%5G#mL_EsP+@=OqPAxbKSRTdUuH{ zBu??m<2GvQ-C~_Rd<7Y9nMNZK zti}VL<@Y+x8^MW;{Kj3JRe|C93t4aWW^P9@Z5Sgr*omq4a~z&Z%h}##r=bZX_F?u0 zKZ`1Z){v*?p2oVQ9jYF6_9}|EOS!}$Pmc9t#H9{36BP`-?z1*OK)7NR7uiXxcH0Mo zIm%OCUTyPv;FOzlW1e<2MNp?;DxKMKhCRzIck4?}7uf?`cfH*^CYbbJMKmiA?#uSA z1}6Avb$%9P@^`8=((0|=Zzh4bN3X@UlKJv{i>`IhE zxo(ok$CcrIU()rd<6d;-)aA_G!vZes{{5gS1K~#Q6@RsL2WG;~UX^ZAugnhT?z)uo zf|cj-(Bi&!tlxu$kHdkuLG%}0MafKQT#z%a$Sh#={Kx_>nU$1{5KYEX4^KdHeau@vrbcU zBqjM7YZ^g!cx5%t|II?jF`~#mdq(!NpqNu0A zdczR1^L&mJnB-%VSiG$S59V_-Uy-y5+v~zq5694JG`KH-L z$^Ls*iw}Yp_oQcPgxdKHkq~FkBIgS46R%1q!YXI3Umq!G6bxGGV{GIAhw)3zc$73V z^BKa1vZdyEVmR(p*~_`X8<9nZzr|}qT52MiP5f5Z zeS2Jet78a_tTYGWqVT7#Z&YKYZk9LSEKIh1rPC41_K90G3(G8(C}f(7DWCbrZTOer z`iBWvziFKm)V7T(h_gXNg^6~$zRl5IJ$WN2hs@?=^~GLJvh5PG(RSo#OQp*)anB#d zYWI{<;Oa0|*VP!Q5 z$d0nLs`A^TR1ahTDY}~)w(_`ikqWGEZx&wTJH?DBir5090u;oX4yM}b#R`4*3)l5a zia({aehm4IT7xIL!E{sTrK2M5S_TTp+`nqVDps|!ljvbToR&L=U+VnMs*8Q8GI9wr zE3o62w;2v76Xs>oD!fe0ZJyo_d@`I9T3KN@mntLqg|YOKM`xMTWLz{>&8pXEw84;4 z?l=xl{EQQa{{EeHrDi*N6=U5uY9LUrBD?-F#CO8&VNfjVEt=EA^|c-T$M6$n<&p&a z=H$E3X4kG!TxXxNb>8rK`FTQBzq>^|Fp-SFz)Dn*lRw@*#;tHO(-*OP8+{FFcaQ&; z3atZJxY$31z$vcR5pzvYS38rY$E;^nJiEKvXw;7pqQUxH!RUlc8}x6t+gqC`}(NaqUqWNHfR`(8mRX zEFn!RwOd454m)MZr@Wdk9+ccbK^vC9l`{?)h~H|^6dWZ*#H98}nHD`d&%-2OaRW2j zgc6o=9MnjysT24S?~V00vT)+cjnEZ;o1vYz#eKbKdMeM|B+v#L8(-yc}_p zlUz@$p=Ih>!*EP#61?TO&Csf@<|JCLaf3#zVqaPEb1wX1^UTUxZN~YC3CIjw!oWjj zX8K|9>AI0wO4jy|SQZ~riG zU5HE5x~ml;g`lV%R!|fL5xYC>P!$g*IUId!mhVbQIn;f4G3W zWM1S7-@G#iLw)`eX_yea1|3AdL83POOMmut7kuG=QP3Z?#>EVk9uIVLZsj&?+)Co{ zu*d2=Es3OgWz4LQz88Q9=8+e3PyH;#^xb?I-NPL1Rsq+D{F>)MPNVs* z0wzZ@*snV5%a|3PW-6N4BP|+AFah!GMo1|18#~G3mB+W8_!YaOMl4K)VNle-w5)%Z zCXWJaquoFk^b zgvMdn`N4T@H7@-j!*|1&f|{s6aQ>1sMeU)@93?}}hFzo*O?fY>(on_)QtZ!RA?72I zjk+!cA_A^^6dUocksxx4Pr`rVPG&2cLVWPh_e)j*y!cPg>+Lbb`N5~{IY+!`=q(B7 z(f2Ewt`8u;o#?ZA?j%p#c#SNZF&|NSOB?#~B;3HZ^_|+S5)11NZ#+G-fpGm4t^LNaZqZM6cjEL@w@^}PGxC9hJQx~Ggv^lYaFJ>0vj9sM#^Qh zzQ5A1R}(-uR1^|P9P`o1$>S?xrgl8zGk$Xt%ahBT>@$8I->CQemcMQ~`Fsp?d`K#`;nV?k~R_S1f-RmyOd*F^#ei~ivwC8X~0Z--qqck>^nvvf_ zY4GOfZpUd8@q!*I@5j*WIYo5N7nX&q&=WP?Tx9qDzi3G`H* z+``B(x0JJYkdsh}7Ex|QrMfafA*n@K4U41mwd5#&BtVVdwEw-EI?)<+q9f6;!6qvn zO-nK2-1>xQ>bW#B3zoqR4@H!0J6Wp=JVm8R+`5`EaMLa#HeK)}AU|Ss#T?UmnT3#- z`xOZPGB8J6lL6;^agES_KUz(e)Iv*wjm8{TM4BbD15rg2=it`TrPs52o*nXVf)*8F zg$J!zb;D_RN2E?&{Pbci935ndMrr!U)IVB;Usgivh)((V!5JV=D%7 z#0o_A?9&1oi4&v$iYcr|AfOlWW%-kEV6Tg3$>n?JSiPtESHERmO9erj@b z62M1`t8q1Bz4siAd&_5dg1O?HwxgYOun1-?skpX!oj9ax4YnfuJ@3+b@wSCEtbN+I z>oQ0#43`nGAf(U4y+@-r?X&WIYg?(HCccM;H&gEcB`v!v8F@ei+3(ooi9=qV7|?9| z;9f_`%xmwyY4S1l)@TS)nQeMZjK3laD?eUe*0g&h;G_O!d55{c7>=zQ(5z4B>3uN_ zb~b8A!x}+e?Q!g>f0!dapd=+BgRxd=v{pIoP`uP|0ouX^X~W^8S0@7b^)sT# z-%cqsH~1v|2~t7AmbG8GYBDR{3TnhbmUeldGnc8IHx47psP~o!jI`YfT_d-Po%!YQ z(L)um&@7U6m%0_NiS+G+nI~l?yMe?>$nbJ-5hlxKe0iPbx%Y6Ap|$E8bvE^(xc4(z z^1oZ(=w0_5oSG0D2?SXRDD?%{p!>W}ce86a0PYGpX+i}f5jGlc0P}Bew40-ptQ#zH zrmJ6^T-E>44pBbF-c87H{HU%{3m8m5o7}-e457AVglv~AhcMv9O(KN zKR7LI?#{uQN)3OKA)k}S9HMf$ktW`=dgCR01X<*6EA65VSL4yHZSQupL);7sP^}qd z}-wlbp6X zR-I@x70foN|AHhp25Xn~say4_ozy|3rWzUy14lBr25%qNf_D6onVex|`w%v$e8Vvd z|83^{`pMA@-YD7qn`GlQGKApXFCLOW+T29m3e^k=@?S(WXgcrso9*vTb}gFTQxouC z#`!Rz;kOG?;yzKP949e_rpOx%FvDJP`GlI00{y1~JC<=$!JeU&sAKs>E?&f;1&quB z6XToaB!$h99KNBIuaP((q<>Dx(18cx`T^P_Z8}==y2u*ZrE1L+fAod@zuBUHed>}W zd&~k|9?ngRVgpRgn8v8h@`Hylx(nbe+V;Vfy^clffU{jb>x{Y??pu3bEp*c(vWxHx zvO;R`t8%%waD)q7xHBmFt|ocL;>yMRx>l|CdimP;`T7CR(T25$hk#qP2>v-O`HZ1v z@Z(38$HdNREd&?k9gwxQ@(Yt~o_8~RMYZ2pZ zaGqFr(7=ph?MMk9+t8Mk+J>)kzM=iCzGgZVnUl1~kF3F4ZGJT#?*asYO2A^@8bF^5 zf%2B!*8AgM-!Ix!DR;d4BvRlKyRf=Y@ZqwW^xi?`CxcK{l9`HPEol$%vGsnC#~hEr z?DX}QolWvqt3myro-$-q^nPoN;_7mjt=qpO4qH6fkszc z=TvE#NKGUEXjdfiTd1<7wT>oAII9`j0jZENoSoZ&S{W^Y@XP4dlGlGy67OHAP5d0p zNyhn1o5+v?5B2<9Tn;vaokF1_WA#+yzxv1YX4gjEEV^OWQUNzb*d*qENdXU0fc?E! zxntAP{LD_L7_Lfx4|EP1{Djd~`FttcC^+&k>Clx15+~NlX|F7n&2CrWxf}rbNUNNM z`$b3F{F4>|_}Dp8`09Kn=%CXbZ+O#px7A1km&koIOJ)$a@3hayb=Lg@eIGnjbur>A z?Rlm#0{izwk#Z-aKmYjIWsv;EzSdjnGD24%!67k}cHcL7a(C}7S6lzW(GbJC0atj# zf!t2na>#cItF~f=x)+iT+2w@zwS2f(N#;1ArkV`Y(3fbyuS&x=Z}j!CE|B4G#6Ni#yb5~t`B}@no-8Vr zwstW!SbBmCoVcvr9}gGPfERFChcT+|FpBBf5^| z+|iq2zxot&xVhd?%JfwHxS%iSWP)Nx*VtM$vUDiB#9VeTkOxmhNS3*6#~hmRj*sYB z0YM1QjFIAipbsmq-_}8ur6DYWLHn+U2f1{1KPvP0*bWk7j-R;uP=d{WD3vLJHV-j+ zaug&vg8&kC_E1Ve{i}k2Oh$^lwq>y6W0Z0@#f!G1Hrkgeh!wrn2s|#mV!g5|wpGh# z#lz)q*+f6`PyBxzIkW=lQ3g~(*D#gcjxB7U;_*(0RQG4z%%tJ|`=FH`XJgn?l5_sr zdtST8#;VBZldgetVvxOr_#Fqk4==R6(|-Mkt!8>&ed%pY6gl|#2CA!*vv%|uH}7xo z@dqYh_blGIM{Y1KjHF({qB>zw-Afk}fy7&|R zrH&(lK+a9LChYQL>4B!V!oZwRw zK+?`pmag0D16UgY&(UYlfOCMN%;hT~U8=9I1>Yl$5J9TfxRI3EBpro?OgD?Xe#S6K zYR8@`@7E+qSp`hc?qs(I6K@Xoa0OR%G)I5{z^PU2*NAgNo%GDm!EF7Z9oeg^ z(zlBh4Xt4rtZa+RDZ{qae!4W0ECZSXqI2aRks(f-*$wHm!?1S5VIKuONg*8_9hy>M zok$%|o@rHT$8z0kRpLvbGMFMQfXkaCjL+*`zK9~nsfn>c5B>X$Bmun#*WWis97P(Q z>vkAMlXEom)4W*P+b_Y@wNyA70vNr4p>$Y#>`6kV-P?f~pSMRv3`iqasa zFz0``0PKetpv%ElvVL=;$+w6^z)y~?addaKz1!QRIuk`Z=excu)wAx4xX6);#)|7# zDV`D%v;w`}0&!k$_Lt7Q@O~i>JD-UF)5_s*9FATV@tRz=*O;T+ogW!S$3^<@qdyt7 z#Vq#Sy#ef8?ff%R>QNe$?}dnW03_~XY=BevNm2*`Y&3|wjN)Tv2SY~%dB&vPwT zdDY>g!IhgXitD{vz<~~N^nYOy&=uUS+DpN*US!CydVMl8L+Pzs0h71*+Q`V|kE3~h z0_z&S!#@YY>Z|7E^_w3-phq|bOqxS3uTIrDHeV&*xtfkq?>x;|1)uTcBO@y}z?>Rj zl6f2MEF%|5OYQk07v^D~7E>OO36tl<--ROyIYnV!#Zl=pAd5~7;P9N|Cc%O#4zu|~ zuHBf{5s+-Mju7>;>!#iY(sHT>J_8!E&6KnZ9F>pF0LgVOu@Ve9K1t)qQ7;+I8;y}! zycY1{UNbzlIwsiwRvy-7!h~j^+5PTR{!4WtK_}_r@Lm%YU?r-Sho3eo5aKU-?D-`= z)MaIcUYr(X@q#f!C!8V@oL_275GTEKfgCAqy!1z_8hA3GUqLV(dK%^f?enkLzEeA! zK7JI58Jc}|aHa)BeV3ZVV;IoWUN za|MiWm|kKM7PL2#Q>?u14AWcS_b4k0&I9}sg*j7yMTSa#QIL0Au9)5NHD7;O8g@6q z`+-R<8JPj3pg~cHKN(2A(dQEeWgq4Y;1!A0pE6F?b3;P%#>D?AP%g7G(x;Xfgegxf z$N2YYh_yLNB*>I zOf~#&LFC|Hs(tUzgw4+Yr~e6+6N+0p4`PeJPwfd$R35UhD(-d<%)TI8f*<|zEHWTn z)!%)N?hAiIt1wP(x)J9lPXtd;w}$im0RqX5*gyF&2bL7gm5O$@vYg;K~$X$hjs?29_ zlU~I~5sRZ6x%;>TXX6mm%|{yr z3w~VePcpLd{}vH>jPbrL`XZun=mW<$SbG-!QiW+#N#q{{Fb2G<4qIx;bN`_!$teMmrrQl1l zFc-Cl#G$ytfRRKQei^!HcML;f^ua=mWr0^**e(yeevK2q4U@vQn;PFxZf86ShGx{j zi3Lm7zqxwhMa#a-OVQ|Rr681IWR9*OWu1a|L==0gs56+$pp4gRR@6b42lT=Bv#hCU z&GI%Ejxx%H218RYR(_BDy(Wm9MGvl)HF;F9cHEOM1AP6Qb5fY%XU$WT2Gbs;MW=_0 zHSc#1Q%tiKM(?0C;pOSmH`ly6j+YjoSMTH=5vsHm=gb9sMxOc@i&^NbAGi_!m@w%l zG{3W1KWyjH&D3rZt%A2w@b>R;UWIo7q)ub1)mDFa@^LHb_3VrJ;~tiR`|_bFjJIpv zv})B+H~$4{^AB0Q?hRc^Fi#5Ps4HikvQ{4wMWH3MAN+x1w^rx%AZG`(hz@MH2;+ zG%M2Fx1&z;rH~ ztaf3$*t=X=Q_*AK?`a`W;3BrPlNP}xA;>(oC-M7J3Q6L!Wcy{RIn(Ti;dgE+w>WfF zdsnIED3cD?qpHw}86-;VP4IDWx|LHK{rLcShsgTD*XAz^1!>Z>(wn;?E>E|}Jkx1! zka!fLXg*wQy-}fN(!>QV6Bq$IM?=K?t|Y6BKjbC1lN}{X3%0_N%?eqt-Mj8Pb1OPEKTwW=lY>u2F03Z% z^9g1>GA&J)dQt8URZ5z-u6)&ZL*>C>41w|)1H*;E&Zhvh$?i9P%gvwxmO_Jyx;A38 zhz=f_sfN0QUGcwlZ@l_yAI916BW-8A;f;rxku%jNfSJF(=XMbD^Im(>F8iWd>J81( zOXq?(n{+MxXQgFJpHw`51dv&Fv%^~ifi#D82_>E;DTO*&ed|_il*}l*h)Dd#{^rF; z_`c@J-5iK-1$hQn)KLt@|pua7#5MdsM*t+9JyBon)%gnG$n)Fz@O0@9d^ zC@a4rhxzmat&ZE+$8G>oO4afJaCtcAqmmE@2Q8}r(4u@M_h*FnD%a4_UPq42#|j&l zuvn1-kpjuv`lhk+fa)@UO{$c@q|_)F33bWlKH=t;Bq!+{8^ z5n-XCG|F!gD00i=Ia~1Q#TTmYXsPB>Y3~qznFSQv*SA!|Oj#HDd88(Oh9TDM*>n zVA7(++y@%1(K1Lbr=zRb96ky7BHIdpO%sU$1VrYo$yxv%28K3rAIZx4eu2W*hlWPST-EmhyTN63VZ>IiH{25vD5u(y{bmFpc<1YK>EKP^|h zkvYz)8Hs^NiJs;$L+jU$hu7)jqx*2O_L*jU#ZC!|kMcP+ORfp|FK`eKXX)e%RtY;k zJ^Iv-IKs3Q86x&WjAa0u-dK5LSpfilvd|FsD|ViR_)TsyPs#$p_=TN*)UH*HGh^M~LU zrjd{8aF=D>i;IGDwcEJ?!|&OQKPj*++zq;kwSu%Fy>+-9z^hfZUd$y`xu<5NKp{Q?J_CeR;KuJAlBue#3(|!^N`f!N1F z1p3^{c`?%iPgW%Bq@C31g5-T2eUmxB$`C_Z38@!|LtIbD0C}MBDFlBbD4p}=&(OU^ z{F`*_B&KO{YN$F~+{Gi{S>iu5|MW>HhvVaPHD^w`IHiCvh<`53 zdU>e{R>6>@7HP9Glb=g!rlaltlmY+}&D|m-1}}+CdR>Uu*;l+R^Q9YNCfQ4b4Rszo zZC@jXmctF_oC3~UErEvI8jH%OkGEGOZZRoNoye4?ohW1)E$4L61lN{37X-LaBqeBP zoDK?T-;-^!ziz}m#Sc6Ip}(s8O)=&sGd;8o(r zpO(&}#wY}?9Y7Zr*y|+o@}R7gwI(#FEY%0%dO~k4}@bC~rQYti9%W1ONf&`Ko*Em5Y}IqL zsnib73VXeZjH>x#YRdibi3y-~eSGaQV!3vHw*w~wy8Kol#Fd6k^6?euR{@lw%!qDi z7{$7_Kc+zW=5m}mt0NnfbrN1MtrA3l*$h5c>p?4?-mpqr0r~5H1?=5k==)(;1mo$r zzkbz;gwgnuusz~U`ViT4OxjdBcFG14u~JECMo8Q8-`RyDYn+TwmqdK*x)j;`SEd&G zy9VyDi4DFu*&=T4?XLLv?IHH{Xi&$SAt7lRY6xy3qj-B##Zg6QJ z4M7Ke9bWP}3;np=mI|7-!WJ`Bktn$yvOFzszm?~whtPX3 zNdvzg@=)5d8S{~rB@ZqTWcfx-5gf_x9xDaHw5=1BA{!T`Yxl@It99G0gkNVVCphfV z(G1uEK4s#~>TsHA;9*L04;63FBlMHTbYj7BwDOeFg2gE5H#fOngls z4U>fP_OfC{%=#(As((Fm5(0&?oW4q#Py`gk(S2r-FT5`z=spCh9>xl}%+N{Vmj>D` zWG8yeZLmi{Y)WeYr0totFfZUQ+;g(~Y6BjZCJ}GQ_tBy70a_RxSKE}Luuq0N0A|2I zQ_)kxmUYZay^}x=_QLUUWjcg$<#K=fQZeV4+2Xq|nazm&plL`6ex7bbL^OP9v8toT z2l2eE2V#P^8u6l5Y#o=J*>pzZoGKhC$~k0xR4t@P?9QL1lS*jwh~xrVjud$uvNc#_ zE}^QR$^|z~U<_d6bSewNGcqzYUMyd@Y(9)u@TpU@2Xtv43_rj$5?X}V!1j6gG z-YM{uWepW;^G?{fxe+#e;6YH<`g?PVA|zEmT;xWrGC)^pI-ReN+3@(LVnEvPLT_qX ztLj!d&iRV9U3RTNJ)3%oE5rmh*M|%OFq})bct6YDYiQHTg#qwuvq?&JMmBF0=dMYf`_JDK(lWPSdgE% zpUpu|_i-WJ2ZQZ>FWISciWwXdUxWI~@A`W_g9zK_Ew9>t`;sE&{i{y>W#>9v*}}qe z-COSz)=_g5N*p`RA9aSVXuO#Q`xKu`R9KYQF1sjL4?{13FmR$ao-_OytB}tSaPBhhLAkchCTA)moosEthdKt-(^6cFFQ( z_DHFLu5eSG(@2GEgQY-PG~1-2-mW^)e3;*%Y|`gbiIc@@1NSfx3>~D(+gv)DD9hwB z{d&7}SyYWBZG}h1HnGI*SIzLv5uPYk)?G{d*s{H@%8mji?=U?+d&w)^P$EqfTvryn zSmUkF@>WwfOJ(1r>PVAyq_MG7@?59&@c#TN#7(fzv_@wuB`ISLu(*eTto>Yxh;U82 z>2iQ;g=5`s@J^$bcKRy!(pZ*3x`6Npa!mDA9RB@qSfi?t^T0tph3EQjYqnRklBB@K z?#o~Oau3rUWBB@uXsqQos6A zjA4Mg(6x8>n~d+76)hxZ27lIDq#ThHeHy<$O+XN zWG41w%6@f%vNFI`Ov6_WQrPTiHA)N@V6a4ZwdweNnxuxp4)P7H z{CC68Lr~W7Z9dR`s4r=uMd)FyLQeRopf+Es`Axt6 za?BK1dws-Nf`O1~aZq%&vUVb3F5ho+4T5p`JA7wai*gs?!uMG5XBZM0V47ok%0LbAqF1MEEcsWj*&3MRW zQ6o`!PSWPXKV&J4uiBnHNfURgo;E9Ka!{!RvfUuRhP-jt30Zh=bx}g)e7&U8kQTpT zdFuZ!fHg3jCR&fr|AeMo_m+Modf|36aACV8FK`J*dkhrcW&1Q(%qUv}NsgiON;dUg z1sk-ELDH!HpV zn0YiB2`0PpWPLUjc;2RApW$6& zZkU^N-J;UVDUHXLBQ)i0g{R)%GN$N@05;Y$`7`g^|Bg(l-}1)gs`c)Pm`((h1QVxm=4qQ&14O*k)1MtAOC5TE}h1G>%wrO4Z@D)W5* z704TLg20!b7BqI`{-zSw{_Ie5%XN;k%~n2n-Kxd>+~e-w=JOsX*txy+W2xvY*#VXu zD6Fgz=$QLkA-)F;*o-fJ7O$S2HE-y-0TCb%7ye6M|Ab!tQxh!8Dtl&Lua$Cu&TeaD z?3}6M|CbE-X#!K2X~>XcKhy4ZH823VAU{8kvjaHuKcy+4+3(S*3^&hw+1hgH|ErSW zKL_pXA-I77swKN6l0Q%Z=lcJ(vw4TmI!dt5=8OElqQ#j|=mX zq3N=|nu&WQw~>eF2q_|CB0$!0Eon=jx6TQ)Ax)KRp{W0N5u<+>05Jaip?*1;5_PBw ztUa_!0q|OSErj6i?Eb2=R3E@W4y>Q$a+GpcrdgRNSbCdi%~JK1@FVyZ{p`(tCf=)bj3 z4!LUIsR<0(Wa4Bbc-w;gy4!gWfQl1OZ;+-Ol;dr%qelbJc|HFf0kTN(65W@`H^ki<&PFgUVN7@%#ZdvpBYF*K{l())2UXXim zW(4%_n8)iqYfBG<(*#ZS3OFJjV=~NYUSD?ge|cLF;2FBf9tRX(DgIyVy=7cg+x9=K z98eI0l8`h25h>}$Kt)PLItAHCcbD5jX$9$0q`Ny*LS)n32uOGL{?CQyoGa&dVBvl7 zJa6th{jk?sbB_3qm}882c@X2ur#Pz0r7?jMyLSEywP|><(gj!}-IL?pg=f}PqJSbr z3WEVusV#sM?2otA=O^a{-vf(Fcs^^lNmm|NEaSQn1);es~aM?aAKdCr3RWiSoQt+d%r^=koX4g2N z)LS$q3>>zo?`uPeS_|SH8ON#uEA^MEo_>(kwurw%SC!GJKaEq;B{)t`0GIJ4OO&##timNRU z0YiVfXT{S#UjajK;v+UTDi^d>O8P4InR*2ca=OW@I$9o{-|wDqg^pUIz;o_f0fOs{YeKTL!#lfsX3rh-&A<&!Tp zGSw5RMjy1T32zr0p;OJv$D5qa?7|+3!z7w>)NlGmT+}RjUm&_4Y z#OKlGnvLpYVV;(eWXJ7hW}AJdUztI(qyW)Y%WDeaCQeChc}tjtcFD(dS_tmuOwJSB z?9mL9g-?gvm8BRj6I!`Pc=F#$4c|2<@E2JJwwd5-I$%B4^~**b;o}bN>Co#3*Ega@ zuH;QMWiWN^+G^{ukK7>x*|@=a>UzTKueO$;hYGo@HwDEv_o`E+@kT+z-0mrmD9y$2 z%{X;)8Fff*IdP}R80JeVxV2DcGdcb$nRx0*1?1_HzM2URo|$#crHPEWHmvYaWs*r9 zvORTn4HHbIi*)!@@2Y$GEnmuuD+!%&<6O#VSzF|?E?hLKv-*`9 zsWTXXIB}~Rxoerx>$jhEt$Ot)E$s7Z5t=Rx_B-Una;A<(%WC*Rd z+$-ALUUjLuLi_CP>}0P!Cxjfrkb?XfL0i`T0hW!0hh6zccTd=y4-;XXg#NUSdR8rU z9&Q3>x*%(0AJySO)W z6ZsqyLGj?`Q+6ZjUFPY@lVfX z+#9mX+V8^>noodj1P+IJ_SB(&Qq=)awX7{Tc61rf68zGocW(+fHx1w|5*ljqbu@1%kY29@&5s-|Bu|HkV0^8 z^(E!(%}d(fd_8R|z?484F5`}Kw}@Hjj#AlZpr#b|Os?&6K)_uEw!miz%n@G+s}@pX z_K6laI})mVFR0f}+;vMxW%-SSqr=P1bX)UBJ-j;M3^hT$mqgvD@W-@{z!PH!r#1S3 zLor$Ka1UQ-1*ld72uUr)HG&Q#xM%|6mK0BuOguR zc<&3jc4_}ZGg*)E#*e07Vz+WO*Aomn7mGry^j^en$BZy}^GetGtMwFodrj}>rc?<| zAOG>>uy{;B^++*1=wW2!o6WxQSO&Q3lCh*tI!WGZvp|Uoj|qJl35S8e+a27|6@C_mG=^ zEciJ%2Ew^oHJ%Jw8D5@53xms#wRL2t53fqn6|IO|Bg7fU(mi}N*p{F@)Ao9jd9oXKrI*)4O5VB7OkJOi+r#)YB2Nw-#=ykJ+w&i1k^uJvRUG4x zfqjAt8>GDBtvs_&wlrsomJ?kF*Rl6~c;~$$gZOv>aV`bPx*CYF#wb(tAEzp>d%1h6 zTKBS@6i!qZ45_`f_xJx^+8KXnA>G!J80_Z5sMixO`$&z8maHhOzJ5w;^5k#+QsscT z|5l(^May#EE97(YXV;nVpMcLK0{K<>? zB>!3Z-h|ep2g~8ld25x#z-s=ZrL8<6#Y1(f(2q%}j4ASF;_xA%|k6Rikl%1SmE=ex* zU>eHNN7Oq;E}Ut$S=@XO8G~?KzQ*|Xg8t0#Il}t9x>13u67zM-gQS#cSQ@S)Gz8QS|gbI`VJ6 zMIJDpW@16tp$%9P=fVEe?rP0!$u{(EqB`? zK_AA5x-ci5gqp9=@+M(^MQ2ZNl-m9d7*YlJUU?U4&H`vd^5KLyw)h6{IhqE|Rm!8OIV3=Mz`6F9#BpL^KdB%xbjI{_Thq3V8-r zap|L_6JuYIT1nNxN}vpoz?f*o9r80GZ5RA2;z*?L*emDg5y)>9-r8T2u<^b!fDl-w z36zflO?+4Ct|&f$s-}-A0`TJTKE_%aZu`8zr!&(F65Y{2f`BWArkexf47$dEa}Wn% zxgP?!&&yc@dD2KF90vj2dn&93dYxSfw=#HUR+C}59|O2AC7H3qeK`zjhXLj zfctM_)nA_MxTna=)T(UU(~_)|Z=ov@Fk8}4?6{$g&QhM@g95gQ_c-qM_E+6=t!*_B z0A1X*PT>XUK3`iu0qAW$8apl3}aX1DcE6e0M9)Swz z6F5Dyy;T&uy&TYE)noe(8R$aoczHT+1=()yr8-Ei-p5QQ6+)EL>m>i+0f&d%5p_J! zYqi?^h!$YdnXu9Yt&wudNS)}T8*+WE4aO|!8F8BZQ9T_X(xV?LLX$Of#^v5_EN;C; zcA}sw;gvXZ!4<1MLw}x0?`M82N^&*9+$^5_-<#X5x(o+$wVZ-_?aep4s+UiBJUiJf zyu3b5HD-wgt>Q!Jj9MW1$~HpIE;BS+pKxQQR|pnYKonIKw-%?^(nqi`_Z%m!d^ouL zgQ(kJ{drF%Z4J;mfW|AyAM+!%=wFbAy`3s{YcVm{!3sJPDpB? z7R(2}_idr28)b#NsQUECHzu2t-wQ^MK#2KoHf0BHA|!xi8UKDR-Z@Oy5*ax0(&LqB zN(nx9kBuXTZsVgDO~*?fJ}R7TtTwGoIxlZ${NlwK009oQSX8zMD}lN0kVT@tzBJXz zJjbpBvRn@Vk`3%OU!x!~PR^bD@Xo5wa>bEtJ&j(oELH!*^`pX)=>*;&fAN?VV?~gc zG0e%<$S#a}s#C~n?Pl=re8qe{u;dk&p;BeU!qMc+jW-Qml|3un)Yn<4C?*n{?4wqS zAUJt>&SXT3eK1eBM%>H1-kQHGCr3Bb4r1s&>S6|jXQ)}FCK2R=r1*X;j`kKQhw#si zFiufztp?;yw5?S9xX$9Lrk|44xSmfQ8i?Sxyzz(n$51LxKRD-V3uek+J(N$$v@P@CE@wFM-xI?ZBCOxW6gEiK~A8+w}kC001s9=&w**}9O0wvEvf)WC=K;p}BMVRQ6 z(B|XgMMM5+QZs6d5HhD0 zr~RywY>2D0zo1M7fV1X>YE$$c{A} z+59MOkZZK?J2ECyq`ms;&0O~aOGWXGkg6=i<)COaYbm#5|(H#v5Iy@>a^BsxJRl%*kR^M&!kPbOd+}mw?ysu8DQW zYw!?3i_=wh+gAU)m+g?wXd29DT`d#;)$6g!_9h1 zsTv9uec(40@d*=A;Yk_XRQ}UexAvww9LcOdi3OOd`}$LfKr zARjewh63`@J>(Qq>6^v zJsyFT10Y9qIkC17x9`3!C3jZF`{E=hIMuN!&NR6C2fY8)4MiWKHRmBYe2b|@E-ZYr zSNQx?2ck)Cu8G+g^s zsptXsde~d7Dh2bH)GfmZp$JV5@a~N6EkM#9aRC{l7D9Mx)5@wdW5PMxgL=A=8P-n$ z#|~9YdOITMdttVHW~6MikL47~VW!JaD`n>QWx%8(r&=IyQW+t%)@40nmDa`G<wY8M0T+s(*680bH3K5P+*_&n;YnmmwX-9L=q!-U22M0m0$KF zTp+evk)^2lco8*p0b+(4ugr# zf`iuQ@qs(^KaVsuuJgiQslBbAv+m_*irNMh#W(g%qKTXZ67VAR%$*$xz_)IasD03=n5Bwpx=0`)4d~{~itc$NWbs9HndT z=v#LtOHP*9Z~P_`!fcGB1m;nbnO0uLSssp7dj4>(#BL!Ju~dlW<5;NbTd_7Eu{Y{l z_GvBIXZzq!7jJ;`R6M!s(AjGQ9Y%|A<%6vZiSW&-9OaGnwFyHZ-7T0@=r!OF9(%~? z3sG9{Kf$N?sckivcBhHf-_(Qd&3bo;mAX^-!lR@RD}PgtfDFAdH3qhvqDZ}RwBU8A zgvadVeb1~TT7e*CMQ6N$wlIFlWGb{t3rKTg0O6@|BK4kJZ8#XccnuH{Tb6x?h&M6h zyZM;5m$yG>F6+2hda^ja7yZo_ka#7!uLvjJ(LcJG2|_q2*bwd?Sa9S7h{_~Yd|SiJ zRoWC{bYRWU-RGs~!-o!`(OQ-QH~yM=J=tR&psL-%-Oo8@NhjERs1aWjTQrJfOfr9w zj%iWqHVvNAXxRn4v7(pfup1L@GgL_I1#?j-a@<2aIAXC}~mIxl%e zJE>^JwsoPq%guRJb;P%&W&_uGM>J`UB9YhW%W}oCbm#lE>~EwP!3W@HF~0$!`=loc zDYpVCvWc0TS|++q((5E|nvMm7@f$d`IR;@5wyZt`o~74tLQEQR19%I*yVWN1B58FwM*f1AY& z5%==lejhgTfz3BQjqHxZ#*{i#y-dHkfz2r&Uel@*Cy;?ZHZnbBP7wzv(gX$Xi057m zyi5Shx9I1`_>c&$W@9*S$MPlTTbix6$5-dP9$c9Sf|Ws9AcGebCw62I18aNrs;r7* zo9`m(OhTqd_sSGQaKsj6qr}h=Br%}ws5E9!VeIG$?zY83e#9SUnu7$Co_Yg+s_p& zTiy+}M|w$6+btyJ48E;Sc1P-j5ho<&-^t&}2Bu-V2dzw9kw$I!1){+;=$S6$vRnIQFT2^mGj zj%$enkPdLLAPcBMsp^Wk*bVJc4EZXfC*a+u7vLnC!FMu8!MZjiD0jH6t-RXVhSM=# zTvRlKeH1m?lA)6y4f(fhINkI0nX6mM8I5n2`_cqj)e{_Hjp|R3Au;P2A0N-{{~$h? z;p|9dKV7V!nE&k#n{MM!u66Stb1AlMM^5qx`YBrlzEG*r0t9$0gwfW+&8g;WZPhvZ zzCf;wPxvvcBlf2LDn2ce#(-A<}nSwFg9~m zGZrGb;QO%6dfn-nxof}huNU5P$L&^Nx4c_ za9|>81qziH6;(8%*9x!lLuP0%Gh6Qf<*J;lWum1#nrcZ&&4-)I>a2Uu%BehD3*gW- z6Ih%z9`unG@^HFEMNFQE_6f1p6#y?IE-LN#LRUdTsMq-U*}A1yxjlS3cPgV$(p6uhhX zQ>aV6QUsnxCJaNqy=C0m~Y8h(pzCfEq8i;cBCd-OUkC_=AR@@TIQ` zmV~DeQJO~L?iN4p?3^IC_3Zk_ifgvvH{w+??)|GXQ!fGxB!2OM6M~k0Wn2oO#|Dvg z?i9@h_fqyfvU?)(9@CYMmECS}^ctDsPQr{hO~lZ!Y{`rHot$CEl>u)G}o+9Ial6pU!Z-ty88A+V7Q zO~Vzs{$A43R%6}gUWPQoyG8dS9v451_P*V^lMfPQWHq{Pc$|XoEK_HKay6-gffsB% zcpHM=aiw5Lo`)G{JKBRt9hS;0jH`N+1`^K~z--|V@*1><`)!>Nj-! zV^NE|0eR(Q6D_Q3b|3hb-uXXCxOU9l$=GUhy*F;GS1BRO?aN9mY)t+Fs^tBcoCOK2 zMlpu->R@8-*eBhwUaz*tBuBSYH0WT?c`n8R@ARrI6BxU87-NCZ=DUZY>Bf2B9D1}G zQEwQi3zghbg;M8xK@JEh&Vj_D;?PIpo#4Qjz-Igu`(STnOiX3=s+dc=V?r&gkMs{d zG>}{xe6NG}Xy0Yj%x2Y@C7MQ+c zar)pwTF|GHQp$Utu3}_Rudyh@bCODY+2|c?gaXQ>WNxeK?@+-3>&Wp?yg~YwX!~bg zQ}{*sS+K`M|Iox3H7=oOsqo%b_tjY@Mf7id*FHF`Qp2?vEDsTPH3vzHcN66ZZBMV+J1qJi|_@@qxbo3dTKOunUZ5)iE*>#s_k7E2Ab1yL`**w~OH83W$G929D4gA75ZCGBbjV zyG4?DC9&xkgCH#b-|v3j^p4?TiP^RM)*|uh-2PQ6SOKhuYyolhPIC(f!Cz5&GE;Ac z?D6q7L0I;IBERVR&#h1v1bGt!z3CvOGCLtQ)_Fxd({tO!62__@#&`iT^bDD)OFMbB zH>K)mMN0o(9$r=D_tFzQKQzENg%5kO4&rJ=KiB{kJ=cz+7GIj}?TgnMH3VAR;%7`) zIn}n5;1#>STXXj=u*Xm5l|mq}FJ_)?-H5*ytL7mjd<=LGe4hzGXP^RNWk~Fji z4@@Fg9gTa*Yvn88@>1rWi$r1yD&B3b3noS@z~s8}QC3BR2Q% z0;FLCOicXvv)GmeYudrWPGCg|Wa>Z)0febm5in|u0q zhf*DB+d)$YP(!m*D1oKc%-rv*d)P>BzqVrx}=l@7=#?AH31PC1oE3BC~c-;x%pvx0$8`Uo_p+JnBn< zXm~jmg5cG@HSEB;&o0$VMDHwcTL?1pNCdq}YwBw@t83RahC?C?Dm4X_I19|%Ss~l8 zr-`W%?@xFih{9n1e5Gc>`GOV5h$2Bg+Nu0`fIt=(lk;~R!4Jx!um|aPFCx*;5m#_f z*wsYioJvp_RU_U1(XF!5JulD=tzWILQ0qrpW!#Y7ZS`Q?rFM}0u07(SX4 zs)4}Fhd4HblUs`7iqKTr^$lXva$R_nN{rzqz5hw&QS`0@2Y$7v<-;f2v%B4RI8)FN5)VsS?B~ z)yIK!aTp_|E1Sz~&y!=Yi!-%eIzrV@WJ~>RdSBc2*b2k#0_#FcDymj^jKH5d+rsx9 zCqFLvPUwn(>##T$lDoPtru%KhPmeN&vJ*C^{^;yo?^2ZZ0tP!1C~L8ChTQ)MMVvyk zsilf-^-$)Bte-w1Jw-hy9PB(gn|d3AeTjUDiCwXfnH@5Gg;>4Ysh4hc^U_idxG-jU zIN4jn_9*NSNn#68awe!l>r1j}!zb}I-RR4`AIKngiVnlLke@%f$XKs)s9rG(M}`R*!#A( z1n0Z@%4O;V$h9gxH|D=2Dd)IGdhwlWRgIa+QAg23RK>&!v#~|E+kH68x{wiW^{OX( zvK!M{PkbM|!o()Z5cveS^H}{<&2ipGahlniwK@q232wngd4gdM7z@R17miT{#0fvIM?F>7Mk7aV1al>6)t7GLI@LqjF%ENN0d+7{T_GQP zsHRsEf90_7v^Tu}WYW15u1yHu`>GzbsXlUx+L7XqS}KalMgDV6>pn}vXzv6-@rwjV zWoLFKH9K=TzM5iw-^!PcT?a__954K_kUJIl8uWyXpE}R6(3i59N22EXrleSiId8OZ z)d3Y?Gtwhm2`Y%S0;BvrnR2=X@*g|^CBiDeFA!lro$J)xY%>+wp}TT)=05(!R;ntj zPwQLi{P_x#vY$3N*i^mzb@rpi9p{fs7ume8?YP`pG_!qFt9k2G`N=Lr!a5=JwZ!c4 zc&NO0W@~NhF&Hy^oM*6kv`J?SVM-hf5+tSEIMBJ*>flk?v9$BclLY$7ov^M6(Y5}B zhk^Q@(>{(G(c5>gv7bm;4zlfIUf3)&4pg*@qty~Y%S09yZdM0VJ8rI!T1;bs8%L_k zBamC3=_&r$*JFi%?v3FVW^*~Hb_I*3IP|$2d8FpV@u6> zkZBHFrCbq5Pfe}A{n+Cs%hvdtwsKsSZJ}iJ(yP(>_l|$2;%_0vjYEi>w?;xTmwZl6 zo?&F_qJsm&%Xg4#FSN(oSQ3I)axNZq49=pW7GzpKfxe(O(ps)tz(Rb>plzYcq3~ju z<1DvVSgdYKkhgU;x2>8(^12oz&a)pW0;%1G_X z8X^C7U7U7lWnAC5?A>*j%0QhEf&^#hteZL|6JZ+z@B22bdbv@@!&gqQQ=aK*f(!-k zF;M-)R^gr^rYyV>JDqkTrE$aB8RPDro)fgnyR1mDCjEg?{P40*%FD0T!ym4Xt4|{X zQ;edCCW3-&Sw?bwG^0+-yAyf|^WitQwpK92oOsm=dMLbcYbD#De#^(T7~tp{k1(b= z`h1A9iq~jE7Hks!E2#IN!~J0#Ft_R>T`9@kM@(*mI{CV!gekhw7ml)_SmI3hCgSzv`OpS%kn^bB5_kQRIj8 z^!e%-`=v=T7b-K2O^u}r;igPHaogvBZIW{RAiGdL8K0k7!YDm+daCOkY$3p95Za{Q zRr^Y2X=ypP7QnW!J!rZy+L|C;96m|7leY6Kt&2tvFJMgVRQvp^ zm;lXs0~Ll3|ynX@_DC6T<5_^`l zDcMj_#qwqffxM~19y0nM9;)0LCtv6W5X z0|VRTEcH3YeRQU`k%4q`XAE|ZhFMs_WvOD-H1sib;ELhE(6fBlBgaHYMBZ|_07B9-&rYi+49Mq5 ziyiAze=kWPeSeVV_>>S^SvVVMnQ1XUGR@pm$RbB;e=zo7mreZY8&H4>xXrcYSuP z-X$y$->dj;Adyvfri?+3DSThzJ3u_S#$gCx%dn;$9qa^_Tmr=&wlVQn`Uy|L`Y!2E zr}&*t3ZQPjxusKH5^jKi?}(hzR7cvOOJQL0Z#3*6@q&sy0hwD}T!?QrKc+fxzCQ`A z9*hyz3y0A`%-x?)nF&1;*{6?<+BC~?Rj^;OqD>xHh16nCqcsGoynI~pp$gNBSCJ2` zC0<)^-+w37J42!hqKF*WMiE6&CiRHc5NedaqtZVgOke5ZoFa9MezK2KZcPood2bi> zU#f632yGik-RD{IHcH!Ugiqh^f!oRnvJpYvaJ*qrI-bhZjTB2;B=esZo4YMlb~yCO`5^&Mb<_f{zbceirY~SGYt0(|15-X@I^{ySpRxLRRC#U6D|Cidy(@Dzyux4$S)|sqEqOPJ$ zB!)EQLBDZ0>b1DhV{Fvr5{n5)+-c*#x9_j1P(#oPIV+T#D4KuKpdqtyA(w;2T z@*8!+o2gyoTQ~NPLqip3TMlkgX-h{a(M{|0Kr;4$>MKw)h;J9vTIm~Is_G@>rK27k zc(P=KD^x3Ei4XRaWEcHRs;@T1NiS#>9y{}p779XQC^_4v=~r+ka`gxb;5Q=NXWwr02JLAFN92?RNj zFIWO}AAQ)j_KAicpzdU%B!u~5$C{g)ML`jHR7Q>g8JniY3|yAoI}1R5>i{$Y6Brys zZ4f#AabR#%(J~TC!c{{s6&|+0w;7@}hAOD<+|c-znP=Mh1DuS`OEC?+^|AN+I!3t@ zI_;&i$mokStW89Hu7c3#Utt2@!UL4?ey9%){JlIPIdNckeY!l-cE-aNR_&w4p!fQQhw(+SKwZX#i%)!XPcsgRN+qWM4*-v zMYmw6gqnbmbgOrAb*V_EDXvW=%a9^120p3+g$WYFLq{NIBlFLwNCcc{7Ex!rJ+qFx z$b=cQUs0q;gcx8yM_k)Oc1Y)i{*H?%4ZajlY4uTlgS9xjHt=_SlZ^59;K{VgR(Ol` z^Ldt`LQqPa>F0Qe&7ru^U_l zZHwK#P%t*P$jIJ=uX5I%(feKC292)t*DgJcSGpX zM3Os)jGOz`mCl7(O27swClH!f#~l;U@99py97yw z*VgDxynwMBYyZ{ncMOC3u1*F31GA?af&2ib^y*@y%-3+EN&VH>I6V1>V-<{hvb1VL z&VV$|teOE5lx3a&yAsPS)C5#wX~S1y(fkCP5-ww?uJ=jCk;<17=nE$WH2PR(j-eb* zh>1TD$so?1?G&5ya;_26;hFL_nk$M@hIRWAA-9nj{jKoZw{N7N)H?Pei`U^TX%D$1 zB}ZF%jbX;ycR=E>=_qTm{tKMrP5uWO!3NJYvmuX_7Wx& zXUTeGG2YD36Q<0~EwnkC(vYOwHrkUQKRLfZskJnd;x`Qyrq_pH{#EJ4bV?}t*5Y{Y z6}T+*BglWxT9qFbfr?~u_|8f5oyie-Ro zt=>0yeF!;ofz`T~g^kj7y8UK2-4{71FwtrwZHoDU|gT-H~uaZ#-iZH_KDhz9qpU!8l!G?k)H1m>=#DxKTd`{fz`yE6&s~W6FH2+Tqbmtn z>Lgrxv_S~ka)c7rpV_ti+=Yg*xo&;n4}%Ihis0n7_cx?w0`|iKYz|ow7VYA{$qy!B=^nK5>eo~?K2ocenxw^iyiqrWFH$~JUm12J((bQ+e^$Z8HwK1y zcoG+DM8A2xZ#OY=5^_SgxuNcN+Ow=Wz1-Clf-~fZ?S-~@ZAEa8{Dg3lGjx6h{=SC> z&~O9ZcaNR`r9&d7xDTL6^dwpM$&O-GMHSn8_+Ta&1T#j9N1!UPTr4{21dk?`aPO0f z4SAv}4)@`QfkLxT)#itxSm-NOg;b(PhEogh8#|J;L#z$F&IxA?f*5u0D;bT!2u>HcJ8ektp-rzcHj)7Qo>!ZcD1IMD! zJY5!Bb12z81g3eaP|9~-;SDv5((Wn~I|@I~>X%U7Ri$4V#G>D!SXAYpv8Wn^+*QGl z@jORjGg#DNIt5};hT~h241di6Xj4iuq$qazO;)OHgVvih(0b!7tQM(CvA6&~wrv+L z!<-%Ey63uHmZEOz=Xg10v#`v|@bAoQ+S4hkxe9zT-a=Y?2#45-Z03Iin)VSkHPv#X zO^iJ^AKoq_8~9&1a034`94R|b7fmD z^rY=#uj;^2#w^$)yWP3~oWM$TbO)$%nR}9)Hg9I=y4mcxGxu!|Bzq!a4scxeq;VA$ z(8l`XSj>f1_csUC%^Pc_`7@OrjN{-f(JlcBVb|1j5K5*CHS2%VqZQYi1mh4t*-b#6 zg?Jpchh~O+KMpz?V;B8-el*Up8CG;#d^=0O?9TiHz87@&1H?R_Q-&?)J2V!0XC#KADRt-AKJgSN#vumJ*9>rWTmZHv$X~?q zZnO|6Q7w7%%+5JWcHidLgoa|2J#E+%kz{D? z^W>oG5A>4;aA_HZn2oJkxfyU>dPKbA77Ci--?zo;a zu%$lpP!?LI&j8pUqPSAfrZo_PPuMg@JkfBemN(xXHd_Tv#Flog)1MOa>zoW!HP zu+zYH^RFodpF8}KfKet%d38>`@?%mSDij|C`FdH9O){BHos7F*yOesv;&!)}Y zB86sig+fa@j8fzCNB_S*Ob)Ow{M8r=_+HOO%wX~EwMpC&SrLyD6?$*oz*S9&AEI)@zy=$&(%yJSA zX0YfrBI^E}2?5vN{q?6@zx@90-8;6)arH|3nJwOv?Z)Bl4jGbXjN+lxBntD$w%#@O zV1-~S!C3Vbg+iSK*d!7(l|O79?Y!*EATtoMz`UN$zuoSXCJ`PLT$&7W&!8|}wSTdi zzHCSrWEOx?zz4=*a~gLYvUdBRBk_Bv3$<*MS-hpS)`R^>2qhT!!Pf6C6KOso)u&As z4jpm$5b&6OU4#fnwtx+qzwLIje{`Xu zJR~STv;BarKi)ryuz=_@X=0iilBugGwx1zmQrcdrdzTqxJ*A^;;J3i+0a`*!a|n4H z>f3KplO7~dDgc7i`Q~u$4cCO1<@zaJ+u;R|yP_q#Exvq3+xDG+A~#OtIIpEC=v8XW zR?52M_Wch#*t6S0=&eqF3`3FUS4;#dgq&VgKqxf+pxr>dkj*JMyZ~9iPL3vI?w9Nzb24I<|iP{k8U3C-~d)k|vW zEdOr*05+k$TO8D!^yR=b!c2>J>XZiNlk0i#(Qg4jfa#RdBY+@xRsL?^;cNage1$Ee zvV{sMwvM2HdWgKi5t!TfM!GcQZV?X!epY?)=I}HG0yV>}0d;J?8au(rpSaPyZpMH(=PmdVNOJ`;zMiizrtjwAH5!``1NqJoRZO4!C! zI)^WE=&(PIM1Zv#*G%qsbG+3Lj{6@p?&}1S!CntdlZ=HO@Opx{e-(W1Nj2upIw5-D zsp8@0_^ahR zHsY7vgVp}ax{$fVG#Yft%1;K*gIj!=2}wD|+$T2{Udkl2W=;F3oT9h#`&U}-e%pZ3 zlP7_>Mu$DU4q;&DO3)Z|ldUa$Eji3iIUenEE1lL%ktyyZ+{L%g(+?eHf8TBAO9>W= zeGNGsDOKIz!yWq8($H6p>Z@CTJVFqUuOL0IOIMAV=Y%LN8CjJ) zy6s>3-@JtD59x2^)j6R`OU9vB8>3xkE`z>Lxb2i>f$f;~U{Fwl?U)3LWTXQ`1F5(d4u@0sqqWNHC_IV~)$k`qTA}WZk%*f!J z%esvd&*k4&Sk(<>q2Mnh#%qHF%@Wtd0TMJ(3}^MMkJ=^9e<0po@TC93kFdCRBJLO* zIdZQ)c|yjWdCn4&oToSXH_N*kjb_DSIO6V?`Cm0;=cz`~{No$C~!PUgbdO!f9y@u)t8G~i|#VPlZu35mFr^%(!GDIq2HP( z&vvwtXqQ)%gmxAx@`$c_6*G@I~NrdV0w18rL#JHq||bx-m>q` z`En}h@q?f(CTPTG|5Sg>_b?I37rHnq629|Elya=5)7-rSSx^ z{QA7jNjH&L9EXyvc!>~ap=MV}+d+kho}*(!4Mz#fO&NFu;FrV%mXvc;9GeCYS?V39 zqrEcI7TWASMtHmP0S*K;v-Go0<;@@Z7$sng0nHN;RvZ8r5=mDT@v!eB%}I>KUA&}S zf3TgAsf!+?ZQ8-5P}_uheqaBd9Oi(C$jYTA-F60E$7w(FMZF&~RSV^B`TvXeXw)Gm=I4AfYTpoE zz$0tsio76wrcSZ)I4qq3`n|sZOw7eBVr@~HlbCc&JS@RZ#p4ufRh2$>igFqcq^w|9 zdeE+v-0rDiYToPbv=mo5#lygD6mJ^1?X0)l>-ZL(R~}gWw^a2n`WnIZnA;BnrFiX({llJ`UE)sNFiIZ(8zEI=EDy68At`3WAo> zs_9FDR3K1D9e8_L*|~$aQ|lD%+ic6mg9=VOL}I<_dq$X=cT3Z6be`m6AYtjV^1MHo z)jV(U{XotrS(xti8+uP4G8QD5%@=IM3Gla?mA&WBo1DV(49{m!y%lC<=1wC0 zQ9a@KTP|4#9ZJ|(2XafE=R=(8edDL&hSW>cS(wpl#ykh#QE~D+Xu2Xf4&FjgIwliaZf5iy14sM_tE!{ z+^f3y&G~A7rFu$L0PjdhJe?SY^pTuun%4wC^#cyVHxp2S!G5(dK%H6XoEtIAJ8^&J zKmx(V`e%*lwlY;A3|ij4-kQ0p8qFy4bjKOan4mhLK#ATY@6LlU<8Th-En+g|%~q#8 zs_nMDpFGKUKmHL8uhZspi9jwHf(x%$9PL-UIdrj=u%9B#Eb*DuikS?Lh7z?@y3*7n zqK+UtcG>e%?mksN+iLV!&+U=$vF+!L8M^BMJVdtVAl}1-20ue#Q^G{0A~~T@Rz*9j zi3_~uLc_8_(KX8Au0#wUofV{0mM+tnq+sQH3NTel_gJJmF1&j%e~37)_gWG{jfGjfp!^O29C z1YukVYL_!4&K#&$e32Bf<3F!`Lkdkh2h6W{+9=fGd8f0itIwXcp z>7j&S7#QmNf#-?$UC(*X`PTaW`PO>Y!dZ;JVAs9(bzk>&?_Jt^4faX?NCx#R%Of%I zxpx)4ToSh@XD_aVuF?8v<^Cpsn>-DeqVx)5jE~rG-v2dKa}7faA26BDet~yg4wLov z&7o(e2}&{@;mI_~ycaZ(j)*-O6Ku>O;^*#rH7-X-*{?6cJLrXzbK~VvjG=a8TbGo` zUkqPgG385Ask0w3xpvd^yp7Gw=t3lV+ppLl$8xNqL@1J{sLFnN*jo4|?#xZU@78R+ z@kMO>+QKo9qg<>a2mY?atom>|n5PqCDIO|m5k*CK5TKxNVq5;?m&D+T#lg{4S%_az+L20(X34ZV5qgQ6| zgT!3-!~x1_IsfZ>0U0s(TNN-pF1|hsU`%%{jG^)C%BUfG3>yBsORhuF z4iA#s14TYu?g)Dr{Y2&EQ`N7L+*YrZqUjYWu0PJkwY!(l@XO!kbmOC12_u3r7HpsA z`1deROaGY21FOf_F{h4|;2-v6$EIsQd=7~CRL=Q!e22-|8rp}#P> zZo&W8Zu{kg0+428T6}D=;w@SW^|o53@OaXc_y4bf-B(?py@_n+Z_Gvnz3qPLR)!bj z#qgowT(!rDnPlZZ@t~LP`MPWind8HJaC_t88UObfUNP%@7rd{bF>1p^Oswml}`RQ-ns z|JVNoV*s$@%{63m%wuuRvv?iBRk%);suc(-U6CNz;zMsyA5>&?Y;+M(rlxRN5kDfL z1qw3EFo`>tljO&mVN^DNx|A#fp0)01kcfcV1SR$2pRmeBuz+*N~oNrxKK>0pUxqn@g^F^52$T(A6UISi4V-$$GEE16d zP?b!)uAQs7<_qxx1+cki&YP=mLziz*5OaHV`G7<9wKbWmQFql5H2IfwOW|q;JMfN= zn0hTA-V~{rU;W{U%T|5ZLxFW!UI6(&e--$zYj=TG)g7k5xvC2W@Qy{{KWcpQ>s!nU z!OI5qwFaJn)>sxixN2T*;G5LF$l0qp>an(fhGG43E5ECO%LH_}e<$Ni4K>mqhJG_d|Z8XA{HzHHe4`{Uas z#mm78Y{~t9-}ld}FCGKXOqmDg!#`T?cm4mUz}3k3pC7@Nmo}-BaQfSf{+Gr6hp+$M zlz*#KL?ggF`>l%o_>r$z7w*hgNAXKwjhgpqrdLX18D42}-Krt} z>(^(-D_ERU)C*K)3e}%t*~!uUZm4qFGK)bG&{jD`G|dZtTtfGi9%6nkbf{^6lH||M z2XvpL zXermUFM)Q!EiFXP5NySMwXhTQVWLy2-RDKRlNnKzpU5ViEiyvsocl==ZG|H4z_x`^ zW|y?PSj!n^6u;8@c_}uWB+Rop(9dsp{7%ck%RRAjvw8AVPm=3p1wD_-^y=LdoR+)p zI9&9`v-OI&h7YFjS00l(EIEWg&pi&eI8ZvsvoSG96I(qXya62yy)wye@(bTilxhjh zyMe%^`IUbEYc{5Su6#1>Lq0Dy^h>4m;{E0B$E+eYECp(L1aB+eb#rPTt-Ki`^*U6~ zXjxJ%Rb+MLl(sK*GHBMTk|1FLwE&Tj0$LTyqp^exE zAG`EPH@`^FQ%sLrd?eLtf8s;x)e2#;RDG(uN(?$F=}~#M`gIRticGT4v5MteLCO-J z?)bdczh7fH-kpuy8k2Ea_3YbqJM0k;B9N<(fF@Lgk)M}m%ekkgeq;XKizq##%^GU6 zpUal2TiuzeMIH6ti21!H2G3cA%dT z>GS+A?Hx)9ELvX-VllituvzR(2U0P(ltWl`YvWBim81z>!xEVNt-q}>YZf^lsLMpr zeF!BNc^yqJbC-P@_|HUVFaxrF>qqO^KgLyykCM^OOr2`Am4?>*n%AxruqB_iGjV@vn|1 zL!H4pRi4LAmJ?;4PtQ+w8H!l6E4mUmOtMvTWDT?pzdE$WnEm_~;&gIo3(>54t8#oW zqLkyX*fL%TUOGQJ>22}Df{DlH^*3ST-;V?#Rts==8hz$rF9coTqfyv5NrJtlxl}SG zRGU0Oi5w~Lk>7q4-u+q$<#lA&eeIV7nFiFIGaPF+Hzba2IHu44%el+`? zAYo`cy4t#lF~`t*Xx9y#)8uUf%MGB=YAt~>KF2ht%cjEs%6Bw~KcmnRO7N23c{S98 z_sut4=K;&H;>1ctQRUBA#s}Q4aP=Wef#*3=VdSd$%Cy~atjQDtF4AMg+F3gfbE8zU zr1($f`uhqsin8_Uoc4cyVv|kgwOwBAPaZDO<(q`M7P08o^cB}4N>p<`_N9v&f|2mY zrHzM48)mt{fLT3X1Cs6@tL4fc=8BXW8ygQ7s4?DKP%F{lIo__F&zAf|vg*D9?BB_M z0(W*ulf?j_FTKqt2`u!uZ2&nS_{~xOZO+I#$N-HZQS3bU` zL{~bh4Lh|0&WPELz8&3hd$XJCf_bHwP&7+)qTM}x%x8hkmw6=( zPk#UX6DdUMHe6tG>&Pr#U_h+ki@z&V9NT8G#qap9U&8(Mv8;&oYeVsdo^upZI3D5D zg2O@~YoM9B^uc&ZL)O@Hct~rpHfJ)u*UpHjCY%xfRRje&d)X)#8|5gc`ONjFCsvl) zXr$A|R6)RU|K_x7EhRfd_(a_4*8(jWuc_}$`dsZeZz`$|v6iF#iFftozAyBS3^2z& z2j*B{Jx0m4G>Lf9SZjhx!5SN)Z-Zl0)+&>BwNU&LC<9}sjh|*4BlXGjGAR?;$$1A; zuIfrKVW#bAiBlJv@pzGx;@`uH4ukSK+MpkrYcX6qU(B*OW*@o9XD5A8mL`%D+EX`T zvF5-m6+y{1?R_ePPs~E2TVtm-{<)prQgwdL1h4=vR?yiL5He)%TXWYH+@!9tiH!&f zk9kEk@XV)Z-WD&R-0Yp?ruq}`EOfA9?2mC2YptPHj_UO<}!o4dy@G|`44}7|DG`vH3C6W~#fjwhyJyvQ32(jJ(orcg|}-z#~_tQZtTR zw#{If_;MP!=J$Yf;;Ut)EBb)UIYqltlxyt?PeaDIBkX%h&Y%jD@2GX7!Ru;p$)p8> zP}g&qPG_jmA^}#o{VGmm;G`OGJ)|OlH2=@-K?-wFJ=lDyi9$O6^rc-q~->YI2> z#`G#9^z(4tX)f&=_=ELC&w)dka_mO6(KGMP(6^lj5`|m?l@wovQ}I~dY(DB?v|VO2 zDRH+R-Gk3bK zf1R$FU~_h~G`K2M)Vp9`F_`Eql59~kvbGb7%q#0alP$k zUm{nhYAbmhdGu4y=*nWSGRJg2ZDNXR8W*rsRHeQ9i8rWWZh-t|yV4Em1o|u$SVf+u zA9NLe^*)30I4w(WmZ4dBGA)7gzH&VaQKab#a~`|Ga!4k-0x>ek;fRuGqOIuh^1V`9 zq;_;PQ)ChBD*h7n&$ui@B$}nNXLI9x-umiitP@zF1G?vp$R&H&Pzkte8 zo~p2uau8O|Sz3?r=8xV_g&tP97=<=JExw>BvP6t2MiZnBi8>TIuBW=5n=>e+ne$i= zjWJt(%jeMChKBVK78~GMEkcIUlOFn`JGK6(`5RrDOy9(;R}qQSWEzBAB9a2$Ki|u! ziOU~lAL|;gRWE$(Rz5>hq z{Afw3NM(dXbGHoRoVRlH*T+?g)7e0UIPbCmU$SQTVu?#5L11!_v2)o@ao?lJ#4^}% zgTC9#>=wU0d*7JEji#4S^mL&z48Hi?+Q%z`(|NT|6IQ6vSOdcl7ceqM!eIkoo(2eB z4Zp*JuXbL5k!qfz?Eq{*>OwRtFsb4$z4Su1S$`6Y$*{@usK0MtoKV=bV9w?=_xrLe zFxjidH{21US;r2Hps@8fdS-aoXq=bs?^D}>qZrv+%%84JDd1XpYFoq%-uwA@v*^2= zLIlrd^YprgJEhG?g)2^}>!JUd`sp!(bW5Y*H^)n4jd=&VFW>QJD)pUqQYlf43=g$r zc1x=x`sQ9Vh0b>4)L1vbu+^Jf|yzB#AcU_J}hW)B{2tg5yeY26>cS)jOv zR%K?t^4hOgirHN6bJ>`iX3j91I?!Gv-}@DnCBp620szE`;l{>9s+J3Z^~zLlc5zfL z7_rKF&r`f5l<*Gom9fQ$$=~S9Uks5a>S^+7%2Jge5#_|-681Rc?z}|&N;PtEEF6|r z>rWYNTm7*$hqGl$aut%3t^p{m(B)&t7m2)26!@2bA{FRMH zP|0Q!!9)8ql@|~&_2^yVmAA6Tu%Bj}CSw#_1KU;I=>nT)8lP>01~TogeT0IZTr#zk zQ#H}R>3i>Nr*icfd3cSk7~*kof6`Dh8vdtF2kF@r8DZYb~rszc5PTlSY&DCruQcHWlXGlR!@7cC_@<>kGQF zPtQPIb;*4uUZ(PKN$*nWHyjFjE(fn8%u{uC9CW4_FKe1cw!iNHZRcchQUv$IaS zD4Q&q#~s@0e1scIsqgY|S{-#pKb!S3I4=L~Ew?n@|LVAuyY6h1s3j-Yk1Fyo6L#EJ z*KT@KEuVT&Krb8fgIPhi-)_M25~-EOcy}}RJNs?QDc$~U)c)FHhDG}I-umbuYyx_Dy?94akm7^AXVtfhUv#Zm}PUdt{LAbB9y<=>f>PcbCL1uL8N{RB>z! zi?$y5Xwj05JHWWA5c2d0YRpG}TY^2y~g+tNgHbhri=u#hORJ(xIp={ zzhTTDjs;A(4dQfhhB~oP12EuFbC}(H(=4;XS}ou^s5IK+G+eA#t9`}hQIF1+jg?g= zN0A)WHcpc&pO>R2Fb*8fqr1EFl6)ara@pVceGcgS+);5sMO?YSY85 z$$^@}aWWNg*6v3ULO+Xdie~xi(T543>}I}lct#&=jw`AAh5`F#v#r)H$R~2j1QAeX z1A1YR>A0tAQZ;t7RzhBPO&qWR1|nE)44{$7F$IjI=I{6A+f51YOS|!dfddN5FX%rB z;88sP6%(&sFR2%GDsM~2 zOE05fiIuB83w~aYi=ca*@2}VpF&lh|`@jaW(@0LYnd=)f<*Cbq@#A^Y)o|{}Ov#(Q zK?>yPY|xjZjlAt)pC3esM=OXy;U#(nAjTEv)u?wP-**T{7*lGST5{VrahK0N>T~-m znPkoW?6*;E<`)2xBIYTExS;b(gwjL-Ic7N1?+_&iE75xH{5r>y*{u6R(~eO*#mGE; zDjs==%g&S<;EO(GYdmUboLY+oR`k2SZR2`@m^@D3`n()+H&-A5z}unWFFlCaofl8B z$qJ|vq$6pXD(AS27^bnb&4yz(D!~0ZWc)T|`Nnj8ZfF6Q{we$Zc9L!gBcoBrkjd3( zp=r3BVgTg!(rtH+wJ<2|SJ3UR6eJ|(m<|V0Xc6;LgU00mLXpTIYVV23QoC6wy!E@! z4iDfssEz(oazd;sgiv41JLk^5zCA);_=;4eu}eDO#%+L$U{-~?SWZ@3$6undG_ON# zewXz~m(8*M;t@Z7$&dFP!2V^MQnoy@GKZIQ-V61N3uVMQ8I%iYoZ z-BwQ?YZqdg_r!Wh&iT|%HE*^f*|XBy-VQ+<@oZqNf?!pXv0e@2w}3PHN5Xy2J%8&f zzLoiU5gd%ShkBXpj&MApH|vQpcs$v3M!F$rR90mR(>v>W-NnrM19Lpy&qZ1sn0|?Z z<@^$EB@8u2^IDD#tM6{}F?(n@_l{Ao8K z-`M_cVBah?+AbeP&LdCLTW->+t_*-JgkV#lapW?z-r&~RF+MSF_ z52AL>_(<@Y-xVH{|2ei{{{p>PDv4U(Ux_!A1rT|T&&7G}T6}2}TGnOZqwod+mWwwO zhmx}Ir~R-WpTL57XE>!uH`JYMwl|b_ILmXLY5*3g#0mJa>9(#Bd}xEh9Ww@AMgT6T zC7aOtib>;fTTg0Y4+?=h8Q0piWalS})M}%a2h+8tYV3@oaR|wtd7!rA%hPY&Y_0== zeMVNPO^1&-L@a+hOky;-*mU>_$B4n^Z1FrhtGC(Yz(3N4kB;yI%b~`+MyrlpgC z{e=x{Bl0(|9Dj+$vI5>5>=yVj%wiSngp8)O0fvthAQWcF+%YrX8!j~iLhiYpNugw1 z3A4Bf<;dUO87`X

{Ub8(=r4_FvuRm)>_A5Hs&dMf<3IDK}tdK;~8I0ZVt;MWKCl%(okY$&mF?O!v1>9CFVrEu09l*;40K7>;$Qmd?~xCmPzqK> zF;WduuYkF&hF?-?whLC0V7@t8Aykp`VNDuOm}jjKa@3s=cOtYLN0KSM2CD zzXX!tCq}DqnDua(BiB>CuNmAIW#w8NP5OCu=rBsQMh};$SJeHBv8#1urW<^mwjC@( zjibxG$(>x?eLj_MV%MFsE!cR^G0nf^JGvo{5K8e(Pr)quXEEo&#sMib4>8R>-)j3^ zE*(VTn0}b%ZaZiVaL{e#*4*79qY=_ZS$3)0&iVG|VO0DQcOT0x$GYVKox4jfA#jNx z#q@B$nYQ$0L;SSK<7Zu2bU`w1zpa9(@H#iBOFZ7B~02(4L_W zsmxNZN(&!po$9ynf2BWoL z__kmH`B^4FXv1fqBiC!*6DC{|i=mW)ngkTj7kEw~`npNO@N9Aj-la#|BEGQOd{Hw>B&(Tx zm?|`e9x!MG!&H?{j_FUK9udfa`s(82n@ujm;pxwfH9Sgdayq(Q$2JlT-F7&q&&$k; z#=#_4*qA7o)$hs!r*n;3ah4{&ZvsPS__?C{$QTvUPrwH|*3}pJpDLeaCf309bedJT zHdp&~z4fMzoWwcth&0X6Rm;Qq^6q^2c`IM)Dv+M^=#ZM4DK>(tz|yWA%! zB4_seNbnyn;7)Z5a+9x*-(r81OhkLr*|d_xwnR}MobNoZz^E_$*#c(!V>Icf1+~Yc zFKo7W23J1aOUX;uTeDtTkMxFsJGy8S@W6`!f4%$$A=x6^WbrgWDDYGJ)V(dQ?C0y% zN_52`q;vyn9G+UQ8gtw!i{{vooj5d(xmEHLI8Bw|o>x+rDb zawJ!qDZibZ*CwIz*{M9>5R@>cy`wv|sw@s<;yh`-I6sMldwt*KMSGh`K;~Xi`}8OA z+_8PLV_fJdQuS^OWP`#LGJd`m14EVu7pz(R-NVI5iT^C*Ltj2Gw>E! z!g{6PlxpK{f)FXo>xJTUfU421by$1}wCBcf&ZiuzXXP%FZ#*)C z5?|j|`e_81j149_1lg^Y+q-m(D6soRr9K;S_E=6Gl>%>*pDLI$rt04dR$JcSTI(9L z@|>ZX6_5d94rbF4qP?fshFwLa4J?G_9xW1(ovFrGB;MuHfUC*s1$IM#F<**?l%{w2 zEFoq0O^4c?j=EHM8otSo)XT4hZ^I_M_EJqaey3W9+2Bcxwug$Gw*~}BocTT>Q+J1H z%oPGbjhyHeX06`9uz9)7IBMC&m)MV3R?p`NgYm^;wd9)VtF4+y7v0WqZaacQW!&ez z;HU2-rm8lV5iU*mfl;d^Q-uh#mm{e)R6X5k>&6{%3s^ zXi{2$@-kl1bo4UO5<1mZW`WO!+rO9U*K2l!l4X5aaZ09obC*$(!fw!q0UpslT~&#n9zfZOE-{pCQ+dHuRei+oT7 zv?m0@s4(d=J^=tmbvUeqHId8gfT@%!({jAj!?Y{Id-au~m$?16{Bnk_jyd)h{@1VE z-CCG}WWAuWphASOsPVA6cCB~7WmwU*JyrSR{b%%HIl2C)OLO^ssQYgKeHF%-he=0X$_i zlYKL7tYOgu6GmTIw2WdVI>%no6Ocr{-IZrMLK|LPNG2vheKxSMThe7N&Oh&n`_2Ev6 z03bCVbwHe0N?@mRn?du_WO6*l!=nYY6hnX&bgX20b@3B?S3OGg@h1;6VA&zX`7O%z zzV3arh%+R97vK&fR$D=hGJr0wPg&uTosD^V;g!#Jx&thXTef+MsZ0XY!txM!!KeW% zKtb@npto<>3#{C+vp8^&r4)3F;j$P=upXt8{MfZMS-Dc)NrmW9C5+7mhuooT$=tPs zZ!88;lL*VJ#xiN7*a8wpTmQg=LjirITD#e3Ae<2b2XzWP&kP7<(ky=K|JH@^dfJGL ztI}af?OZf+b3A!zJ>#L*4B)tc>`1H;0MH=k!FdTp^+G5$$w2Vp^tX^T-O|eqGDIC%JhtR(KsRMu) z%k6XrAbaH?oA3|6J<5E%{Abw;rJ3j#AA#8N5$ib+oRUO+S><>9Cv|sq;}wXYz=T@F zc%2-|KwUQIb!%)Gek~is$)mP11I!Ns&H#;&BiOD^tMkWrK6E@DU|*93uJ>r63=q@y z%`&<2iS#B?y93w<-cU8)N;r7TFiAfGh~X5dJdeI15Q-NG0|+dGw?L@6UgbF;&zO*> z|2rzk%VG9a0Z<>*RzE@h-M~KX6F> zLPHqx=XdL z|GOIedxeHw6HbZKcmk7n5$ba6V1x1uCM&(LFK1> z7q=VG3$k!I{G9ZldUCI6(Pcq?S^#y2`yN%G*}p?7Tyg;U`sY4()fDYt>QY&T$=fJ%3{E2`aTW7w=45dQ+2WsPVC1#)$>hVc)8h`H)g186tf@Dzkt zfdE>(*-i1t^t-PsOv~ky1vKDeMT~5X2Nlc;UknWu)63pJZLgB7vAd%=wSu=jT??76wUa5G^U}LW+}O|MhUwNhePGdrssnLA z{({#9!#5@Eq zO*4|K1QD)x_pr?hFzbmg&9JkAMNu#j4sI;82B?-y38oe8JWt>DvjL2wW#35cC)^Op+fJ<95FwC5$qIE`!xAf0m;MN zdA3@0hYx8kWuXK~$7R}F&dzfdc{Dm44q`qU=LP%6YY2MxG@%#j6<^tU?nSKe*+P$l zSfe@3dcLv|Jr0g*Nf^p90~%Yk(wxKJKY?oN-du%;W~2E^%O6M$4`ykC z$JD=^LXYjZO;%ZeXo>?-Y-r|b{B=M}!k8l)$FA{3tF)=g2F5fDYks%qf8PiGR3?G_ zv(5aTTsCUt;a&E7kDu}WS;kK&;Oj-bdnCbQl6tdC z_7eAABsE0GYylDF;TqeA+SN`uG5`&f3I(O>0{UjlwEVde%(pILVLPs7KQdYk_-f8i z5lRKhO({xgZZu*I@Al}uPmc^XfRp1hShS&i#U6_v)>cNlAqE@h*KuYc&0ferX3a0r z@`;%wHp{Npsxu<)jO9i2r5r0=Q<UId;!(kqOA})bBR^ z(k|P2wE+AAi4drYpDA>YRq9mwHTlL5zb8q^GL!r5gfdX0ax z+2W&yLT5Fk!6+Y#ym^0;<(Nfxv?P!r@OZq`Fuw8Ru!juR8|6K?NmJ4hmYe`8z2$GZ z2t?ENPn`#4&rc(IM=eMEv(;NwZUOU47Uhn{Q-4~cRmJoIRN)uLC_*4l^78;k7BkVf z55x<75SQ+QmI0&ixcq9ON`Q+|v2O(b#7-9GE;D-ZI@hoFsTb&IK;3s8JF|cTUQ|f> z((P+LJu%9)9ARL1ErrS+u5%^@E%oy?1_lki;FyKFMfE51B`?HpaGA?~e)$2Ds@^dx zu)@5be8lWj5LSpi!|MrbAqtT|y-~@v(LO#}qFsdSc313Rn;xty$r~t$o+`uhX=#Om zQqg;z)Hw>9nobAnDxhDVgG>R**J{Cxhm!-TMFkkfWI3E&zTBUzw0d@NGVmRSEYPt= zR-pjC*mSu|Wgpmg5R}8F_f=WId-TO+WI)&h8K-3c`Ytn$@rEl`NejagOW|4=fdpv3 z`;8*FtiMVP!_CkO8GDPGcS6?P{yV9@WM^0hP~`k2K}shy3^1U}i5J4Ge0DSJ z(?>TGv};@ns;pqc*|oOQ1Gnmz*~C-F0b1`d&IMYI%IknbJHzgL({A=rl0U!EDxfJO z6}}(iHq`o}(F3)o8-`dLOrCqGSU{U~<2Kb+50%QPrVu%^I8sWLyKrl((EirO=es}v zl4VmvNf4ayc(5Q5zfY(9O^ul z4yfgLg}Ft}zug;#x+XtC1}~K&T^t;pd0cV^w3L<@<%87;BhelW=L1fgW47H%JVl`o z_=gP-i?8$z|2AL$gZbGhxSSpq8m4^{+dkanVBtt6#48?M3eOA4=VS;Mxxsx8Ks$A7k7h&?u*`29?6N@^ zl{njP^rvx+-)g_FB5Bi3C;6%8V1vt(cZBao(}gz#jcQy^d*?DJ_&uHJ+4oUpMIhL= zKWTtE%&IMUT@Za=12m8>ss!ko>3q)j@=Sf6*T+25*XfBvQvQV7p(<}WtoD&{-TyJh zsw+9q{ZubIIED#Xb)U^(=2o?tJ?XjY#rgcDTB_n?eAWpGC+4z&Ek%gh^#JiRCkw=E zy^n@Ct3upTXG9`8M+VXX@)0^a7%}%~+ykZov)S7Do}$twI8Rl4Y7~L$ut+kjd0Vii z*CaxONr{+^_OV<{qb^CaAv(&6TaCaFHPDcUVD?7ya zNwz(;^i5HMGn=1m#kG^~H_l8t3D!+f!2OLqbVBdsilzea8Fo3EEGiqxO& zZm4EX8~2P_sum|)%$Xc08$nN>s^!MS8-ORfO@_aPQ~*I|wO9J%zaUg}ZvbKaN2-_d zIDV6mwUb;iKTJ;hxwQ(%C8@gXK#k#DzZ*;rj2eZb=FZz0i0AKqMG64|^1`5GMoE+@ zv9~l&;~s!DvJ)y`ejX2b?eHH6S;RkPDh0B$}JN1R(2-A_=unPNK5j-_-8@)-0M11; zpls^BNCQa~YI-p)%)1{6VXfN@Z?{}*u3=TT2^ni|cCYtokfpjlz>MkZA z=88&AJ=2Z?5@{@9(CTsCsI!K>siz-rs&Iq@K^MCVs_jgvj$t?Gh(%$lg}UgHt34p8 zNQ+)&)ya2mlRUN>q8n-AcM_sA_BxrIl-kfBWXl6?GFpgw^h%<(+?#L{m3cmQ7YGLc zX(fZDL$>krsNHzWk-P%LY^l|2=_nx(LK;AED?nT&t|!(oUfAkg4;h!maf#d!^jJ6C z?wAhIgy*B@W%nbU*ysE>NPy9teeFyYj%b@-Q&ty|Yo})XQE|TW+UXYG|~L{>yzGY(Rvb+|j45ds8XdJnfnd->))A5GWT@yz2nuMIpx z!pHg2bKH(I(R>8~0%N7RjA&1{pUZgNS^LHMdEp?@+tecR;S?fo0*ySSk#F8AMIG0V z3e&?I9`ah5?pL6y4UrZzYw14bO2M^|k%&e{DP=6;=WtI4aA?Qk^;JX@%D zklkE+Bk91sjKJ!(;+YrIX?8Q)`wvK-##ez#pSJeLd*ft!<5*Mr$BWO#JO`dL(m)>M=#dYbs+b`&}*4ib)1j-hGJRI}$Rvc>XTy#hE+Nc6Hzt`cUp5=H`l4%_Baj8e%Qu4Try7)*H-cg4 zx$z4}!~*~-k=;0Rz2)(s4B^e}Ae`ZL>WyoJl(%v=^BD8O>zsRwC!IY5u^)(@t0C_n zD4Uc9Bp)2cKhx(tfv2gVk(<=)2|YIJd+D=Mtgte9Kyi+eKDMZ-ff^&vaupa9?C-@E zcsD|Gg#&L>8~Ycw?F!n$)ibo7Al{|+GhbV08W1k9ZPanYG3UEq zG>L*1;pLUHE(`)kx$)#8J-n`*nq2mU1`gh5uJQ89twMmVWnUh;2|6VqIUDndw zjyNmCQbZS`A_>IG83$2f1W4_SX;@lE5h|3xcX(vBp?S-b?!*eGuP^l^(P|BviRB`6 z(KM2)P-NGo#MkKZVQ|Db;d$z+w*8s+R+0Y$p`e6-Re)QQ(PD1Q-oi&AE@gL+1B zu{!z)+>exSq}_H#yKnL2^1;$Ap$5B?5u}?|Oe11=3DHzjy=Wv&UDK6?v9(LUwL1tLfSH!?>9fPLW z9nPu5TO9#y0OiLIfoFTzSZ83~aw$tn6B4yJ@cb0Vnu-cZbKdmqc zYPdM}V0fU+HoY?5iY-10dXo*0qJv^^x$8FNH`u#OZg(Tjc8)=rBPRvUIRs({DRd{= z@Vdd&RUkW|{RT31_j%gNJ4AnNw$|>PBFWJ4X>gC@0R|Ekx|Z%ScAYnZic3=@Uv0Xo zac!-d;51dh7P`JG2>#eJpG^>RDu&%TAuKet%See^fMw;{655PXGd+K{?OaOmli(s% zns7T`)MUF`#7+QNS5itj2S$WFxCtcF-H&C`WXE`i7S!mCE6Mi7cbNrX{Vnq6$}UQ= z;Iogh%&B7f^(j#x*gVAb9EX6yfj2_FCG@<>ut`sQt)2zg8;|-=HW&hOj^Vl1T?)v0 z%E~tgLv_ENSXPsje#o?{lD=-W)fhWMx7KDaxj#4Tp#l_&XH-BP-+yWy%LKNqclwTB zDdN-AFgEXVu^me?)COdM_KCn>Z3gplY(C_%F{)8hBF32+Fa(sb_xhXQPgQ-o2cXYV z1(Ua{LcnO4HuYPn*>%@L6%1NG-rET^XKU#tbRTXeHb{j(Fy5YP1d1@KQ|L}qWE|iF z|6(WqI-bq&uqV$t{+T&7k4pp+Q1592>3*CiseK6QJ`Vo0O_h(iAFOZSikRMfC+NOY^^xSM&9Eqy(1fbeOfssgFqWB>7}sd5 z893{Gz#HsCZ1aXyyJ8}H!vt=2rc^%xf$w!?N1QL;^N0ljnGD4_c5f57XLq2Ug{1f7 zkoQe)Klm|U%yzEMu~|ER2->cFJ46T3%sf(yQylLc2W<#EGdvH|sE}}koOd&3H5`r{ zTiu%_K-)_yK?$Z_jmzZ~v@n!4PyU&7}t(UO=XA z9JJeF`vS-?<ar2zv%Vn29SMz^3v*A>4m{|O)Bbm%|Lr|$;!~nU@v9o z@DyCToe4gyQ2+J*soW=${{G`v>9q%I*&_DvX1VR`-oo+OZI{}WPdz6c&ywK2ONHF;zd}RS(~DZ{=g;xB^tf zeoD>sf&gBC)Rgjfy@&ZA+sUjK<8vS}T@_R7cL7F<*Rk@m=;#*I zLZo5<{nz~%7Mc4Pi?1lsqNmAhq#@Zh2OxK9Ekh@ZW99E6cFwD^=OdNZEVPQ5TXb+G_MQ6 z(Medn44Ky*%@nM1ab;hX$uu1Fr{-J*@--nIs~C>AFS_oM{3O@eZm6p^&{q9aG(oI_G4&t@|fHM_(n(Q^!;x%;J z*gx?rYW(Zw@=^pL=b09vg$xVLzG{Rw1LfM0Gp;#jDj!j&QDY0TbeaI#)z5J~_&I6w zJGLI3Bz5hNxXfEWSlJ;?FZwWOiN}Od+AIU;J9(7M2^cuRX=fN`;^gQc3jx0DdWMqq zSHcI6h21|>1yif=0Yu!>9#_l3@#Zh{jwiOc13(_Z*IAxUL!UEO#Z-Z61+X`s`LC1@ z&i-F{o^V@_jb>-1Ck85so{jcd9L%0yVA|F>Gv+G_j_>tNlJ>p+ zr$01I82ILN?}|e3M^>G&x!#Qszqw-~0i$l4^`(w9_Wd3))m%_V-U=?$mv>2mR-ZVJ^5<{z8M_c&<-_xJ9VzVIg#q&~H7)ODOV#QBU8R#;ejohiW7__TRaK9BHl}`%zwD(t_x9;|dy$?atL_3vo zl&T2(vXg-J<=C<8U*I#eC-2THtsi4^J=3RxT*Hg}lb>ZqKe~LO=31|wO|;+Dg&H& zVwUw-k)KC87{5@S@{v?{%)L+P>o5yKUc0F$(A(joK;oD|(n&?g*mk5uqquaAZ0rhB zvUSa(_e4~yROc}e;=yArYNJqzcsw^F0Yci*KvzB-&s2dvrFf$^&aL|0XTehH@^4nz zS2_K`W0BroC(0E0hj`m*_jfYsR6oN8x*P+Fy*Bz%bO`hSO9W~bT;>e%LyjG=aHP+ zP6J{vp5NIZ`V(8zL=g}zqLip5f~*-P(9{BMG^stIx-X5AFpq2!wQn@wsh2c7hQ`=^L|r+NW-%{%9OI+m|9UOFlY>H5VAK= z1=~GpF}X-T?7g7ir<(`%hx0(~T_y1#?#fM+Mdw{c!fuU;SU*+oAYKpldcW=^*A{fz8D7j8w6WP zKZ-%lWWWhcMu#A_W)}Ek*`3DP&qBiBs_p>S7a#Ebj_+va+K`cPnHR^0BX;MT(~rGj zFsz3{jG`t! zP4I}Z8=*&#vcv#8m?Sw*)|mu_o^L>91^C1A^H`=t4rBe;cs zn3RSX)~h?5vQ~(5v9@GbJK1|hEdu~H`9>hc9}n*TW&EB*?TcZHK$eZ9*p-!T)3e~| z@Q+U=Y8Rs+N+Q}K=p#t>3AI2Lm5ju9&I+SNX0(m+_f5k>YgNgx%$E-leSY9i#LTO) z&V)aB(F+5N*?INPqVo36P@g_Jn$9&GtCoOWCAvGdY%J%`TYp%vEw@$%;w#Cg*X&M& zWnfwV!qLWZXV7wN4R z*1zQ6U$h$uYehISQ13imOL10IC7TJ-c+2p$dE&(IW}_C6?yK;uZuzeE;Xu8N*@G9D z^kRSd15%_Bg*`vkKuN3lHx>+H>gk^s$xDLG;$cJ*MHkpEFp*eF@OTkZ$U-Z9<{G*MscqSRJ?KeEe(5 zf5p2u`eReVQw|e$xAD4rzc?>rUU*O9rBmT?ZinHBMHT5X z#x>{LmidpKEQHx+pVW@y^*rPuIBR*hoNzN=aGlWpte$q3qO1S3EzbIdSDB-gkz4(n zG1crkgNHM>-1J>)#VU0T8`1D0yRoXyf{rl~&8XN7QK7pNzSVPwqU&7i+aB*|Uo<3B zFZphN^B1DiRx%|NnHbNMgmJEQqsrFk&rahdnBy#t#SE9v?pV-+R z{JOgsUVHIi?x9VY0mZN4C>h*+c1ZGxb&9JK5Wij(8kzMW=dpUbUq|&qeLW%ij!T5vvHa@o2Jhoe=B<+k5W?mj|Hjy``~WF3uzDi`K`U;D5FE4-ia`6rFVq5qd#oo>`prD*W_FD8`V=9E{xB2;;9Yc5Vmuk#b(B z{t+&`gQJ4kP_Aw7d6-B!%{v92aqTK09K6#N0G!mN5-3K<^^EraS}p&d_O3G;&aPc2 z(R=SPL&QXom>7)S6P*wxqRgZyiQXAe1}_Oi^d1CJB3dMRC+Z+U5WNe6QAZu;$@`sk z);ZsLleNyD^XpiCSTpM}&))mq`?>Gyy6$V3i7%p(U-BsR6o+w$U39vN(-d_Wcdt20 zG*b=eN)p~jUDzVQJqpAn(bK_z=5fZUj`l@#KC`#B2HUJ0vD2tT^-2b@2r2@T)sPin()1k`ZruC;yW+G6Wx~T6#dh@B;D^Se(Ua^C>#P^-Aoy$xd#U?L! zUV+uCK+jucu|OO)u3}I&{U`>oh7udm^#>nc5MJ|)T6n$IsB$Z~6PYS%B4_x7(V)R6 z5)~wit+qtU6Q0-=j8cj-a)|Jy)H4LAHpKlfR?`4kPr9{oZGzw7S-mChH=q)lBQ8u+ z1{gPRk@&c|^o~FFey87-<|-^G$?7?jpyOo9ZN(PCs?f zKHTIs>Nw=JyObZW-0!DhID1tmO(O1LTbvwLH~??))nO>txcGsnUx#*;?azfylsg*> zNeX<}?py75Y&SrX_Hx){JgvvN|2$Oh09m`jn%vW_ls0+~Y~la3O@M1grPaK-(~f;j^TM{LJP#PWu}c^tqCJylM?PmQY6{+w~D?{1D`ljSMYhj(ik zOzuPC%3t=5q1L*DfXK)y5WZJj=rZcP$M^ag)g)ijsQ4A(c%v=;k+x`yG@BwDVP7zX z&`JlHPjYwPnRvhSQ;vDd*K35F2?EEKdWjnSq)?-Q2=Bu=vHiqlRC&aZLco;%a-aIX zXx@a3=2Wf6TcdRef*{t*cdKbJR;yuM?sZs-c0c}AZxX+FR20~G3j3_&s-5Xq1i#b7+Gv{1%>SL9N`#^GQDp4F21<` zB*aEw5$(n2CC{r;yUyqX#KnEu!VImsGZITA?s*ItWIan#@-z<8Va6mo(o#VsyW6}l z53rjUHHAI!oWnk?_jjwMfK$dDk$SB7)5-gWxY*extj8jSK*_RUXD&cv-k^mv(b}zJszLp5DHa7<*()#s8*sB#DDUCtFRlrIb@j!vc9W7d6Y2x zQj7sNLIO$gPA+$oEV3IF`*aO5@hSISXVgoI{wkn!O(x7boYd1M58=h1Jy`=wJ@Pi# zujP-^Xp=>E-k1uys`lAV>e*G@uC%m$$eV0t#Jni&E|dw6qF#R_n7BGJENLfu%P`Xv z3~_#(1PuIfu34#WF~~M0$4m(2W8jnAB5r@4xq}@mx8%6|rA_-1tv~NYMxNjN3S7A4 zy?a_s)tQ4N4ehF1n|bP=)!*MQ(P7>627HI*)OKSgmV#*SWTt8PEN}zfu|VeSM>R71 z5AKa#N_Gtph#*odi8!oLO`eWfF9n@aFR}ISm zPTOr7sz~}5w1v7|f0o61tSS^lUOgGz-weP5XnM*C;nS0ubI&4JXXe?*hFBDWV)C6p zVY42C$NKQC75b~kEtMCcS036Gl-(e{+gJO^PKUcXZ|XuD-67By*&lfj_3*ATN{P}M zqMME!zYIHmS_-a_D!Zc!U_`CJH|lEp`UfLxr2=b#Vm!+~H@qUWRht;*>DMvBv$i2n zh{Ec>IB;&LQNB`_*euCzNK2|#7dg1I)El=J$%vMAe*JT-oDW*p5TIDFN=L7VCR1gg z=Ro=^zh`HjFM%t0kbM4Zbs3WU(oL?zD#cMJvaUnz7M84>I=s#E5j%oh^(;tWu``vN zF95(3nN;5ab@<{d-+)NiP1^za(vad(U^}FsK67} z5x;%WxS=XNr=iAk(B_so&P9(Z@!QkDs#RLHp6fYBjX4g9yvRp(=%vnR{2mtC zNxMJ-Q=whSWtx2=O%Bao2t(HEuamyurGEup*)A+OoLanWCk$W$vuf_AWf)hZk{W3; zr;56ZLFBnL0ZIxTbym*yGn$R4xeD(!$>QSJRTKC5_3_bAhzUAlV zGV(q|OeP;0_`S}{NtrXmD49-DVTzTXm*&w`8IxItc5o{(j0^54_K4A&4Q<;+1FigC z6It%6B29!yMv^*x$;ni*#JF>@#*F|_rGwx`c|+8f{48YYOR@)*T~gjSq(LI!y@=`n zVfEm`7Pakrg^84(%m-lA{uYlNffyBT15nc%3-M0q&ZCUk0r4(~mHU<1sg<6d1guX9 zBGVQZjApz9!KBQLB|6e(y{z8tUA4?@lMLd(@Gf)q(}dnlVx#u=>Lts}mri~cpQqoy1JoGCaI1~syx)6`nul5Y^?cA`&gi#YLf^13M22kOF z*M#9A6xQ?8hy@JQG0~eVBcREE(<}P2TVv~-ZesAD6v?v)m=jKxD2Dr(s>A=`54+Na zXZ@LUw$GNa0wqm8 zp;H*1mbH0okCO$7WoDZv0ec4X`Osw`RhqZUB~$Ab7^0W)Wbli%Kb3XsGD*hhSNRN? zdnD^O$b4Kj=1hmqRL)~U6=d0XHoC8=EuYTOHR0!5rfvj3K6#E_pUiu^dz|zxQ=9KM zr|GX#7VS|tc;;#5$sBHx>5OcI=?aD`qYQoa1D>2-# z2b=E^2*4^IoJUBxGl3X%F6RI*K%R+yCa; zb3MO@a2CMG@{&CRs8pk5cYjJ2npWgBQF2Jw7Ze1xwIlS)v*YVNrUNb{riS)>*V3JX zv{PkG9c$itDoahQ03t8ViOLPeLEKUU-dG*)IJKCU<`@g;SbSDpdfx;AX)5ECW$&<2 zrM)R2-Fk<_Rym%vr!UaJCk5j2wPOIpr`wK>Owci=#tk9rk}Q*CVQeXXY#UJ!#_Z<* zN`as{IQGs(55Rt^cB109r=oyNP5gV6Q|4t^@8&0~faQwpNJUbgqkNLE>7$zQPZJDihluj&uhiU2>7dmQqQ zLQHOct8ckqSl+!jRbyAheB;5eP#6(LZdq|CukXni?iYk*P^IgjpOYhezCc;?BRhg| zu%*nSh-`5&PA`$>J6GJYv9k4w))rtQ_1Y^jrP18un~|&O(as0E72O61UMoxu6tg;% zr_mkDzZ6V2>ic%E?_%1m{?iXuIsWf>2QYKMSFS7qX2p7f)}x;TYU6X(o(>-^B_h|x@W$MtyjT)s_?<5 z)Josf0>v(@!`@ti34-bUs!Q-|vSe_Ad%tn1rAm}vfVN=)?^>ir&pLab&(jhPwg9eY z7-p8YDL-73EFgf@-oDLtW2dQ8eJca)Jk)qQy&l)Pt1;^SH>BlmC#Wme&snN02=kAa z_ErJf(V5Z6HR1a+hSav3H@sA{YJ!XK(*)4xFE%dZ>M0o29eECwb0r)Qav(c$gd|HgR#5KEGCBW zJ4s1!?OP(wrCY;*XX=mb1qAtyYWda~iPMXp7QaT=+wk$1A>PbNzVvB~f=-mG2U)DDM={J!qFK%ojzY|$n* z^x;odx;JwFf(xappriV=WF^bfY6Z2w1WW5bd|_{y+Szm|oo;xm5~em;(EQkry`y;efZ(AZM;U5D{DMC8$7LfC*`48gIh5K^w?kZ#f!+#S)zGQPwi`U$8_P)o zP69*}-FqCcv+g%DE;_58R68A95vp=|$@uhAjZK^%r; z!H^O<^3bwG9;CcwPN*ZMTqssGwJveE@ZKm^h+VVTnB@|QxtG!-h4_K1$YMY1pX@B9 z++smI@pAY{x24Jn$0T{b6VeiJSMctajYN!daenw4o=plWm(jGcsK17#-=TVZ|=y{n~@=b+vNQ_Sk-jY?b#k^o>&m0}@kp z9!cj0Xf)U0l-^Xm{;OM2FdHm%7ZfxM_CIW4{_IAqT2bQs1z`hOSIhgAF9-YIse#1M zVeuOiMcF9)c>>QG{Ixp)9nBGhEz8PS|K+a@IqKHe>;5iy zvqLJQFw>irlIrn3DD<4}p-!tD%bT49lW=Y(rj~%;(yKs<%|l0V7s_zhWeh5t+UzQrHS27t1D&M_*%jA?EB4 ztyHC$rCgxF5d63JS9@}VskzuJy&slz!ZpnRWll7+QK_Q8zH;pcg8NjWs(Y`PY0a~Q z?bro9uckI%rfCA%0B|^R@kOP9JTcpcy$Hg4OEt}c&OqD8?8YXOhf;3Vy+A`uq&MyS z^?<-1R)BkY$B=IHm+nl3A2P%`xMAWsgS_2q1@iC`o|U8t$N0xD*vbj4LvBrX+Gj$7pf zFUi6H$_0#9!N%3!&zYY@EJRUZPVT2|zb6_ny&t^8*S>*B_X#Gbs1vua_ft$;`9}r1 zwAV(R2&;AJ)+7;$b@qXhEr~f#uEn-!+d5a?XLcvCU=EgsHAW?@U8NTCd-tqF{b@3CHPt?iYz=wQ&+LJ+5fz&ddxB z+~@?@1pqj8Pk8S*bt&zcGu~q7HA=>`0i}bK=5x~v3`&`VJ)!wEebJ-DWh{%_RWsI= z*?^&Wx_Qy`6G3y!7Wnr`5m;Rf-*NG(X2JePy*_Q8%*>Ay&^qQv3vzkM=TmfqtYQ2gyt`8GxPw`s++I zljPNU5^r#gjROrePM8qD>^O-^q#g>T0~Ti%kY4T#1o#&(IHRM~RwqrmIR7<=JMqnP zZHS(h;LM&kO@wdui2H@ER@aT*8D>=K($nUGdF7aQ}5L^*zYyG`8 zpu2>qbH`kg=nXbuNiVj}Q7Yk4in-n`xKm zmD~SL6QpJ_|dqnt6HLr4EhiB+WS!e literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/mqtt/req-counts.png b/test/performance/result/aro-hpc/resource-usage/mqtt/req-counts.png new file mode 100644 index 0000000000000000000000000000000000000000..2c8fe67ae65c9a91c9a7eb5a43f16207ac5c7007 GIT binary patch literal 246083 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%0DAI`d2Guo|#ix1W{0HQEH_ z=k*?|LJ(;g|HU;kr$`LZe$pLhEo9h~Z@F{=Ipu5;G<`%8qB5?pMGcs}d;NujbH91h z0~KKw2`$_A#jfL@pshs;AZ&Ddf*5q4Aa=T)tdG?vCEMSUmpRP%2TqYON)kFB>4SCi z*>^sbBV}`IPsN?xnaVz2fb^w=F!bx9SSM#bI4%cOOvp;gK_^*^saA|n(0e#@H&gWd2DXcQ?rDk zNaT}2?n-$Hkho;(UBc9%;j?QR*qj!J5A~bGOI$NYE)Ba|1sm^oFHZzA3K*gF5X6oi ztAJFd>tsV33PtIz&mIJ~@4~?vua9@4=EYU##L;MGq%G;RnDRs~ZyAI!3Qi`~)J+F7Uj0FIG(sDq5EH-t&G~qEA(L=_46M`a9xSJ526fmb%Le%O0-a)O z>vshe0?UElEI3@H^5*NHoD5Ta?&ZwJmS+Y=4W2_FF%F#{IQlg7`SXuu{>#BA??R$n z#qH$2o9Hf-?DkQd3eadgbeFnYf`^;kdQ$>IP)84v-1mmHXQ6HnPJ!oSq|Xas%*q=c zSy8blb!m~Fe%Q@Ubzlct%twBpq!mXDiS@wyJDu}XE>=x+?Hl$l~rIi_rw}1MTIJ?~b9*r6M`pmxIt3gk$ZzAjy$H zQtSK{HRVXiUfV$Ty*lzP^40R6)uc8bpVsn@@X7i2q!iUj`ag&!GQ6$(=pnR%SWODm zZCaocY40qi()NUV!ThBNUSLr&Pg=NQD$>b~$tz95QibT&v{udVcBJP?g1#?Jv92GJ zigAu+H-g2n9-->6r{vGb?DB@>#9O2 z(^O-Dl&r&wq|$56=I{aqU>I!z$R}5{F_`OR<}(hZjR_oZHW7Y)DI~&IagQl%B0G}* zp!hw%P$uegICJ zG4Y;1%i7383z(jpj_StO&!d++bFOC?GubO0P%hmBKeFN5Jg%uPto0m&>|w6@NzbaT z#A@XO31ptKamMi(Lo{7HfhVPR zeZ`imR;wY-&rvLE0&ixDSjt#_S9hQV$nLl$T<+YspfF}(ix&2D+?PwugU6}7UbF9) zpFvs{T6DLjJ-{gjGAnetnTz<(CnL^hf~Q#64Rz=zuomu7Cf%pcyMAfPdc z>)YJ$iQ83WL-7>{!r}diYN1;x`IQqbcl51vV{R%k1Y4y2_M=0w!)*I&!HeZ~98;kW zpWlk7eM#iuzbmK_zx!v)HS9K8EFLJ=G+k!#noCZw!WTqSn5&v{Uta_1FS zRq11p6)GiW6uBoDmGb-XJ9(5WX4)bggXZ=voZBHiPrm!V+4S231v|#PFGWHtw7!zy zRdgZ9-0b{1O^Vt^#MvEKZu3WjkP<=;9!pC|Jdu)O%2v#iH(e+#wY@msZrC~6^=?Sg z4BhVT?S1BO(y+6)Cx5kDyI5w}m)M*??YwLET9{Gs79a!N8?~6n_C-s z!ruQ>ff|3fC*J6o6uN%hWrZNu1SsV&zSP7BThu$Fy;41|85<05X1uPBomBl2@f)VS zdjpy7(w+3FUR4$hPSf&-e}{2l`-zY^ti>L^NMPT&usg&R$>NKm4t4#E$KUGR7HLNE zXMJbg8xS$aC|(2aLjSTIH2NY(vG;$CJGra5|F3Z;c6b_=fF~lQQV{}X&&l7xk@QSd z-Ox?;oF{Pxzz_tb1zp@>%FY~4;VqD#WXfG!#s&;SG*ppf&4F1TADOhd#ix7cUE)>q zRD*8=2)%y82^a@@IP$3)7~eqBmise=t$ zo%F~;*13oH9(-scrBsX>W!L-c%^Tg_099U~vbF{sA;eK=sgQg04qBH7rO>VzvoJSy zNl?S}^h?kXl)Y7?c`cACRjC7MSKLrSedu@*J4XpQtft`g!dwD@^b|0VPC_B0b`E?4jDw(FXBUP*Vijik^=^q6VpD(3cjEdsyRXtE59DbBaJr!O z2&89q(xAc$Tl#!?!S;A(kB;{PH3tX2F1`o_wR9wj!x>PA9OEF#2RY_dTKr5fX&yx- zv}lQ>pdO~viarWzm^O9f_u3@_pl*rerW6+t3Wc+GN6P()dW*2aYt@*}SNumK0fKMT ze9}L>N0^*O=+k`Fg>4qLxrWq z9Yu={7e$c>8uqJuxbLNtf})&jJq(jpakuRQ&F}6>Aid>$g)P%0 zg9Yhm)_mZnx;w|`MmK{rOJ+3QC#l8=k$2dZAC(QcCUHmkOFQesJf@_sOmD#YMiJX_ zMNtg)HDxu{rKfuJt~&)@=EsqV&Xy9kp*I?k8mS%;@MLXMgzlL7EQ>FxVysp#A+@(@ZQk z$*fpy_t3qBbzdOzN%5zU_m5=`E3uTzcr>+!Q}0aeyso$|?jimLb85%#td4e78=56B z_?Pa-O)bOp3Nr4ur->$qEu63JiVx1Xa2*U*{!)8e!r_Ps9mQL5u8(rcvu3iRA9=Sxk z?+@t;-%erj=z!JT@@QH(N`iD2p~srMfdWi~A=IE#8`JK*M76ISdyGi^MmF49|9r*o zWZ4I2bDCoAF}z^mcp{jF`pepTEX(wApymc~@;1UbH^?-BDEGE?c3+25i|QR}r2-P= z!ud0o{?F3zX}(|_-G{s5I7xD4!}(i*+66?+x{=kIzjbquPmr?3116dU-OUde<7Ktz)-Gr2k`En#!~qPgspkzfOh9!Q+|vw=M~Bl)7T9Ed@AX%*5PzUSS#u%mHMeqkGW#wTRwQ zzqNZwUEe-5@+loD(ZVp^G&UtZ?!;x;BJu+=kGp&2%|svsY*DZQp+4~ztNYa@GN3y`p7Ms*PV0GTp#h0N(s=Dy2fhAq&VPJ;Z4& z;sti3QZ4h_OB>&faT8cSHMoo0HIDvN2!ugcsHRsBfhn1;ToTvBUD0lDbLyG?>6xAV z2;1BXRvG7Nb7_1u$5y4uW&h3FQm=`;I-*TC-)Ews38z~JPn1{h9p_1<nINTYN&2oe%Xmvjx?ozf*8BHajrBHdlmFocveD5-RV)Vs`p{@#0k z>c=-T_ug~%S$plZ)-5vjdn40_&~bZ*=8Hs!g?@#}#}KoGDxA9G;=iPPChrsdplK!I zC0PUKJDF4OxqnLWHGpJ~B!guG590$YvF2VY*?KQnl8fj-#h)`mQ?NQhz&5?y< zv3|1Bb-ystAHT`^VY{}_l<~GqmBZ)-KeZyCY~NbDsV7_mk#R(S`Uh>Q*XHaaZ6`vU zUHnG#VF)=vX>_ZmMKl~*VPG{&t8Z=SrEZ66y!HP?NBHyrji!vywz9Tn*fTVbm7MnPFLwai7g{9(|e;d6_*PnmWXs^fR{IqAP<@&SUgnes< zv&{GmqpCH)-kLQo@p!B?P>an&Ob&ax+!Ym0>@E^qR0k%J*wpXx(M{+-Hs(xk;6kS# z91#?d~+?O}tECBYBEDAiRqSC3% z{ntaCI(O`=i(?@8K@PR~F)BWD*TiCp!C*hNn_%l&^D*D~GJR94t;>SbA}N3HM8DBs zDo;12aHeF)iNY%4#N5855EOiw;@)-ypE)SZ*BF z4dHBoA>Dey_%-7}-btzY0Aip=qG0un|C2r}`lboB%2Zs*)^?6pUv8%e(0WX$2dYr+ zW`9Ay{+TB>L&DgC-I$o07e|Voe}-i}5)EKoa8No-IpMy?Qxw)qmnFmRNf^uMhBP?0!@!~s%^wdLx-0``LVG~+9!A< zQAmmm+S){2TK|?k5m>QX6;co^+veh85~`_lErjt8mh&L4!vQ?KwhPNvz8 zdEtn9yw073ufJ$uFLy`wdg`G2p`d02seBp|iGTHbrv8b?@s`q(_Z<;_h!V<#NTuyR z^F_`6YbVw~ol>KLo1hOL>jM$-XIim|iT9H>diavfcz^Y3?l)79t{RfOK-V>nhZfoYb8^A zn|H8mRB|=1l59}qYH1Epx0^?HloGMagRDA)6x$vniuc>ZdT84eKd%4a_I-51pCF}L zJeavU>?-uC{GTjI43+NDAUo){jZH1pnOZz8hckUlwLn5z7s2Y_Pu|Q!(ZfI810&fP zSn5oYOA$tWXDel3=c)V@0ll3Km*MMjywT@j*4Ky;@s8q22^Hdx_KE!ExBc%v%t za7#Kn8G-3?g{hosh1q|;ROWU9jt$F3>&y4HnA|6*9bOFR*yPeLf4pSUta+$VZ4(&& zh!M|2j@)JeO-Sfw9!8_ulr);;dGvbY^IU{R!GN^dujS`~HgBf&Y2*kWJP5flO$M~} zD|GdU1k9SzV`f7?R>@eGrp=xacrXdQf>0FsxFf}$m#q)d*>hsDemzs{jJ?xiw^u_& zBYec4kU4}TU>|N!+TY2NwgDx|j(d4W^Mj*m-W6@2yol33t)76uY3Aid)ot9rdr>1q z1mZ7>8JF)K=pZ{x*m4TCrP>ok5cyneWu@S3vHbyPjp5<6PidEWf4$z8mEn+*Fvd)6 zWi6*(<_{zM6h-uF!jQ3o9M#ySYx z;kbBT0u-~yZD!lk67*gHCkcf5QITJo!1`pNX95>P*Orgd$a4eI*IB$cd~y!&fqK(^NqS{__isI$(-A>^#FSezq)fJJ0SP~MlSIz#DV<7fjz)s+aKI^Z5LO*t4-ug zYr7FjERbh$2hvZ}JgJ4ezSV*18t7CirvLQ`u!vB_!@1kbw-hgfFgU#M;pZ34as-R% zR0d21?zD&%vT{%|?UG4^YDxzoW8E$=VLv1!!2y|P79VTT;Af+(4OB|_(q+ti0HX0= zO?e|J>xYF)`5)ON^}{JIAVr)-TGpEB^6Dt+JyV7T5@!AlBkQ^B>0N`~ssl$yn0L zKpX-`ShPLA>>di4tCgPdB3JP`{u6oOQQEH#qcP3l6*m8Dzes2Q?Q+$9S(UM>{cVs; zt1^{Sven>hc}3uYlv17oxQEG&Cj>l?W%ro;%gF; zHacP6(GtQ0W5GyNQ;TOQ8qSq|k2fz4$vzE#f;`OI{zIf30ZaztbfyExLlXY=ptkVq z;=tLr{x0Po5qHn!*}v(gOlsHZg>Xu8Ev4k9!!d(A;YEJy-IOpGZ$$3bLSrGX7Plkg zF{LxSCD1O3zQP>nEmQp+_mlYk3(NTYISI!07Ua*<4wp>`k!q*PO5Jkt zPAao=N}_xF4AW*Z-gZ)n4U1Mkn2*~{G{fj_Bk6|m3+DHWB{6rbAMP21t zx|LmfM!PshH9}sRQaZntUDai2gEbK2YttIF z0)Gdb6J5AdWddZv=?Y_dMRwhZ!X;*gLmot(>s!VlZ~NuoXifV5O%Kqh_qJo`&-O%e zY6Og~^HEWni%DM=6+tHvlZ@}u-v`D5j4dvn?-)xKVG%H?Hh~UC6O}!-HSGldy!r({ zEaPb1GRcAH99WpxWYlm_Za60uDO@18xaj}e=Rd0QV0<=hn8@Bs4p2SL<@=0?mTh?U zdUeF+p>1#qr$=*^-5n0bquv`J&pf-%0l(VYgO@T_dYMSd@VmL&hlP8dOdCUW9Ao)s zdc^lG9b!LHw9MFh0Ni_~r8T!@Nba z0)YTtn9Mvs2n!6J5>j!q)<;Y5i4go)-)R8#mgzwrxY=he$qW z6Ay&-4@aZ*n++Lec;3gA1JoJxIo=k=aQYD-V9>Co!kCp)1}5@DpnfMkz#PZmle)W zyK`NZ6;H1}D(@6;)NTu42kn`kpDOp5Dt*Rb;@o(2WhORfOTh4i+K@2(a80Blz(BAAl(c{~pQ4n2)dTA8ok4ltDjTEHxoC&>g=LPw);J>! zJ>O?KC~bYbgeF_^_BZ!Oghs-xjCKXn=hu}nO#X2!=VbBk@O@**K5zSiaN->obhSur zwLV@QMcW`q`9PtX7F9gy|Qj#`c7K+&5s& zjL1_j{wb-cao8-72$5RjH)i&_AU6mk3I~OFCNQ$6u9@bGqmFQ(e5RQ0Z92_}b3oIt z$UgNg0AU)K>9%PhI9s)bU_2CgOL5g==NNzXoIN=;odNzl_~b+^<1vYBb>cAkFjU}8 z2eS3QvmO=`cj&9y&Z+SZEk4eokE0b*rBV7Ucj=1PN;zGmF9H?exmaz6MHfp8yRvx! z=yc3D82x%u-NeR@h%_k*CBj4`9`Gfa#vpUicjiBrwqI1>sN3xW80mssrU>KFp*_(3 z(^gz!fulk7GuRu@ErB72E_V*fvMUj)mUATx!{)g@RGZWWZP~?jo6z>%o8CyYT)oqd zz*8bKw(o}Wsic6?2TaB0ql5=IxvPyLMAg~PzSxar&_hdOo^z$i@iyweS@JPTP;q$o z;H=|l+ecW~&&qnO6bp^?SN1~a#I6JH>(Q+msXm4<6?oR3?(bKymRWj|_%tvL1fD=f zkO@L#Bcqsx4*PCIb;p3S)LgIi=z{U$YmFyTEmZ}Zi%As{1r23rA9B9+I!m6>@k@sp zN~pHtSH+0=ga5cL>0Y!wg=ItYq5t`Cj~+Th#f3`~mTTLubWD`VGHd!)@nQ92*(9kk zZeXF|y97x0@BtC9Vu?$)$TCNCKj@gBkl*b{Z%vJUG`j-&64Lk_KN7_-+^yN99{!=C zS8rO|eHH+ezYA)cLW~Vnh@W0tgLGOBznS$KGsEgPjkwMrmhDb`fX+C6D65YfwfTc% z#8Ot@cl@)~AIA@#Ez)1tUz+gD)C|slTedKrD_c+)nIGO72Fwr5@;;@n3pavLuH-J7 z-viz-?8+yx34=xAZmr5*e`VWFsD#g9g4-VAj}-$3lZ=FZspl{{w@=Xi*T@( ztrDDb^eXCzLDUOE2yRX-CAgK+_;K{^N|WkDTFbwAf-S1%gj-;LH16_ zzuqPLf)^a#*KY4TA{<)FripF-1kQFGDh5cV7CkOoTYW{XA?T~A;9W_bdBsg?<=RWJ zf2R?&qFJe*mk^1!$IY7?r>VFO-)haby|a@H#I~5U$j_jwZ=ygH8mC_ zxtNhZYa8YvkKzKVZM@Z?nrV)yJqU1zH>>--*?;e6w$`PfmNRC4=i5=&FlEpu5PU(L z&$ig!zbKp1zbJ31U1U7y#3?c<=;EuRmFb7PLMABYGqja}AjU|$Nx(z~*@(GSaW1YE z9Tj2SS6h}3mcu1b(pz(k!Iz3iViU!`0swnVYE#T&hICiWFizF7km5AT@}CqQ+$dN3 zf3rUS7YLE~Fmb|Xc`q4-!EY)ZDMQx9p!?Uqf-+m6LjsK>v>i#tBBWKJ9q>46xy^7n z^$d`{8PkA==$f$n0fk#+I-?ns(IiLtS85j%rmtM8pD6O+GyxO)ZTtdDM#j zA81dFOh^qQ$$Mtvy4a5-6=914+Jc8H*r|M|Az3}x^?+)y=oPOO{r1YRh5HRIKh`L4 zMjUP0{_)3>*#`*&i)0yjV@QPC*)Keqo3Wo_wUl0%y^~y(k&kFSs80QULS+47DP|L} z4+%*MdKzl72S8GW!ybF--%HOXf3z80bk<>)Z=y z+s}YeHo8{43*IW}bdmaPV`)9l3Xi8n2m7#;m_oz=a6Xd=CKk23nE&!$pWWXzLhqDR zYdNPxoE5H(1h-za%5?)1Gp;vER5}Rf|LxGR*vxOYCDV`h6`0U-5)F2KnijcEfItD5~3jO$fmI1NdhuCK#b{c!-8*lZd{d5OTQy&Ol{*Jd$o7d&#usoBBRYq3X z4GHW0Cm?TlKO5vrSRn?blc`dhuf z9CWla9l$RtYgxYlrYDi34a@7xe$!9fJO1uMneQBB?h#;~T# ztMpTX1L4!bvYh}%tHZq2ACM;sv?{sl5>)J(*JW7{*qV6U;j;lo{%F<iy)XKuPm=ni@dj|CWV^}3UrFhNPvxUR% z%jLngzw?z6Q#7T6gMK-_hXbza?R1XoGa#GiC(cTpKix8Y|C`4-%rhhr1HQd5`*&FP z)+k5!* z>;3v^v)4iMbQJ`??1j6it^#W#KI=ihzc?l>&}xXo*|~JXWRJfzQX`Tyjet>Yth8p& z3LX&_yV+|juVyAIs<-9n)+RUn{U$!1Gd9JMpL(NP93A;X+i1nA=JjcQEbSZHsBe?G z^q_7>X?M#A5UMl105vNcZuWRl*K~>_uv50{*qqn!T{^1zl(x)|5gc0)-FQyutPd>T zH;Rg`2x#~)PvrT1v1DV^e3IvDIb}ZzWHhu!boT5#9`<*upyV)}-z>*^ zLt4avt+xHn0}wt$0?1?9NS|&6wY+Q8(IBr@JZa{SH>iOLdbj$Nk;Y;$5ajKi|_8R|-jIkLge^ z^(k&2z2z#Je^k0%GI=#bc%GUCuppZR8uhv;D~(L>^0JS5-FT;qFL3Qws=%+tphMr* z*@1JY(dYITvZeTm0!clkL=P`YW_beKlL`OZfyb4_GZDv&ji=}*Ru|){2AL- z?&nRn_B1l!p(cy6CHhQH3qt{Un8tnRCD@I#=_Jl%V`IxP9Wij&@5T z@N-kzqFHhFfdG(gxx4HD&H>hEEW|lg+SfdG&R9*)(c@nV-9+C7q5!Z~6*cl!{LZC0 z>iVOO!o7~@#_l0Dm@&X(!W6t@a7?I^`f{mLp5LRGi|8 zicj<>bae5u*0*{2+?`>LH9r|wG*DJvM|+NuW4>nhp(%VJkSj>noz=+~Ka(oB z749>SevzVnI{5bx1GKBR1xfq?A%e>Lfi@`Z_O6;kHS#Yu*U#c1c!x1z&!UPzGql-T=2Z6+*BP3CB&$Yjl|@dC^SJ^f!ia*!@Su zGzTY%>W596PmI91KG?q|q)!H9C*2OC6b=28&#ap&Uzt+w9XhmaVf#}r#FQ^)r}@-C zoZwbdu)IcD@TY($Q=_JBMpydr4Jyajcv?SNYkt41uo1TduIQYsqINNGkREUg-^tS; z9}U<}f9U_1T2~1oQp~n1<>kO~oNnAx28j0y|0QLiIx5JNt_&jtK@gU4ks5+%l&^mfF zq4v{!aBl^5>REA(V}(V9)s>t0weUS8!=uw_+W_JL%FqJnNwQ)fg<519tM1wkKfg2) zK0jeV!0-TO3@tfPeB;x=FOBNw@}2`vFzZ2WGA%PakQvnmV|JRWuCWoere@?c4O8?B z=k)YnQ&35ES*1nPwC}%^gu{nAN&z_d4DBeEo_j)OkskA0qVPYF_S@JreWZ>=5a6K<{xj@CpzF3$~$@Oxdc1Gwpg^{fxo>8R+<(j#ho!NDB6=;js-!ieR%z!9>0@#X=LdgDzq<#Ou1)F#b)$s+~oB zpmV#>)YDzIx-mA~L7G;W)SqM_y1hJj6u_Am==+tkx>;^xHwI8V06bg~;FH6_AWbrP z2gT>?b;E>{bF|Q#3QXhV^<_I|GB~UxJ7!pre;G8iQj7EJDyga4jKy2$v`ecg@oZva z5wVHWpkeQQtXahk{IOzuwiHCkN%bz4K9B-Pb`sAf7gqSv$jvJD0u^bj7=_vFWGv%c z5AC{z+Lt`MoP*u;KVBs;J*WbP(BVB=0Q-90S~&zCWmmzirL$|i7up;`VkF-PEeK?0 zRgse#3M&OxG?NSnNMf0bPUN-kbc;MIVK*H^f8p$m#i<(@=_uBoyx#78pBn@s^SASr zZ4Uv$q5_2%rqD~B*>wvv=FvRFJTE@Tqc59|jL9c5(qMxbSh2UOXJ zm4JPP@msH$WthW2EZE~+rt@%A8&U`WosFO#M#1P*3r*P2q~iS;5_9mzncJ<_-RmB* zSnB``6WiBk08m&w@lT#B42aT)%Y@P&8Vz?jYfQ{ff4fI`EF@08S8-xeRFSf!uFLkZLo=UmRxd=6|(F zW3*T+HG}$0_=msQjJxG*x88IWFD&g)o@EGjJ1-S-$e;(pbzO;ZlrC#!xmv+es1#*) zN@NAZH^3p$u{qTbKR=VYb67;0%t-U-mF!Ua#v8|`9u=ZpO%Uwzb8_#@&{E%bSv^qS z`wmU@kM_If=$5qc>jU5daIoZh64gOl%tWR;6AV0v>`gBsyk12U3}LLR=6Di;%(tz0 z>w%n>CXEV+S2E}>aDo0iK@4VaTH$`Hac7YYyQj7dGz(4Wzgdz?C2$SCFPp}{p(^lj z&ZEx^x5#vVTI_{M$6$WG=Ouu|GLZsw*ssdcvBBr8t5kCJcA@WCidV= z2Z^gu@@(RVLSiYDW~7kLp56KoY-V*Bq1srE4z<~}9l%PFRNv6?7Xym;3&K_cc=rh> za&VRi6f7{pHNeZtk-K)K%`+c%7basrHAO10xlX14&VWLwwq!&`q;}`>x0@WUu^SNZ z#x#Rhc&z*J68|HSI+GZ6EZ$=APXRT+)S5&$@Ly*F zJ*WoQbE6N2pMplhecxroML4h~_V^7kje&+R;qMrNw}0bc6lx%|)8rD;fcO;Z}v;sleLox+tMw*`)y)6kvMw7esk?=gRE+*65u zn!wpujT|t2;KG%N@fpsSb+bj(ZBvbJZhn4gQ=9GKAMmu(RJAAT0>-Zp233aHN!oX2 zw^sdZG-R*ban6O3ac(tjXttb5zH`Qn50lS@HpUJ#uqDOTUY+~aBUUDKcm8h3v3c##(h+sg^dz6o8ME$e6kQ6FG%a!A;5=3!Q1LAr304!ur>S{1 zAJyd`>@$Otuq&aM|6E4DtJ}=zl1ekRuV;YF>E-^#poegnASbj=0VgG!CyeYgXtXqG zdK!4;co*euz7$d`X+XZ*<403J++Ic-9D8nJ1DR6XRo^T8Nv_DZFLvKpC`Caw^C-bA#E6(Cf~U$MF{qmTO3gGT z-t^LAp*Y-@X@oyx0QP!ZE|67NnP$VQSaw`V`;L$TiiH}TJ;cU9=ZiYw3D8g;kJ62; zqQ~%w!jOXJgEhiUKY0}wr|U$we!E^?y7_xx&;ULyLTn*+c9b3kuPlN~oJWs}FDa8F zuse`AVY)-t=D2UqNh9Q~8y=#ImIPQf-ON3a?>ve8byY6DaM9_BL^vL9$C8DTw%wo~ zw;U5O?j0O)S!Yag>Rj;$ZbVi>Mg$;cjZI;lZ!C}@oSLFu|8>`87QFzqy?*1QmOcU@ zwb^X;!fXq)RLnknq*W{k#GIGI@kt1#WL!5G#z@?CCl$cYe(i{W1NUpYQQwSDWA(9kj~bBP zM_qhp6K@IE1R3%WLg)`~L?89hqG6TM;=*E&N3@aNV^uEeUD>6Cm#VXXzkg4fAW;-> z2;BE!+1UWSf}9;SLgwsH(=m$DK2uYmCaX);^Lo8&8K$p*pOF7$Vx6O7MaKcaXGexv zb5dBT;wgcQL)wm0`;&Vi zkzyU-|9a@g-kY1mqU&Fn#<Xt)fkwR z)vYSBJhQt0>D#e$8v48NjW4>Zx9(NwwV_kpD6Y8Z6B2Bed#>7~f517jDretXyh9jbALXdca5p@yXvyTvu5u42y zmsl;mcu}0ycjG)YrNV#>Tlv45&eS$?Uf|`!8DNl`J~eIAVWI`+RM-&7wGg5JW`Eju zz{;6xMmtdVrr5wC?=_sTu6)mzZH`xSuUA7m*R{M_CU`!7V*Negcq?w_@E?w$F&b8{ z;5r=x0(9y>G39cd_JrU#Yy_e0;a=ff8T}(M*KhzCZP4M==i-j_@ZO?)L~bzMS#`k#zpb3iEBN~A{TEAV;nbvw%M{qa?(B+H{Cv?1C{Kb!O1RUnHJQm&KUZz*nmQ>L57Rny>20c+MR9UBR|9F^ z?$~d~EVeMR6ATILHfuU_4UeM3mS5(296yj97bAoI;SNoi8hx#U7JcJ~ns;PE<{Gmc z@F3?gR(0syPPjv<8ggy{Fgd^NCpZHKp7!y>8aP}^Q|3Wn$*es@n9eidlO1@W@SH37GuGx)$pjkwPDv#Mfl+Z02_+^9 z4d z*nxuLEb4rtxST9-yMt_Bw=r4Na#o5HeXKL=NahqI(aV(Y^63VKuFyd%9Yw!m=mCj` z)yxR7P1=kQr)acVclq$gpIQ2e;*uNlKh+HUsmVVsjVL&_WDhvOe%7D;gK9d|Z7Hf6 zVXUb7t`#*OZN<&^t-kd4tp*c|9d+%C<@RT5bc0vx=Q^@lR5F9AEbHOl=Icd%q!Prp z-q+5yFTiRjXDIbLc#qKbda|N5{rN=_{v`*p+hmK_HTx;#LfcBX0Zz8(bcyu_Y5?9NEbes)tjL8K!JPADH=*(7N)+6a;L*dVsT^W z)k_o8pWkPZmRbag$<0-9+Q+Nl&{DAN1jl;@h$@5M67|eM%hm1euK~g{BcnQjt?qQ= zeO$KN2yZ@lgaV|VnGhdGeuDg+zb|fbjUdXWA-t54-$iof^Tt;w#lD;0CwvxppJ7b% z&sb00)Sl;l{jt*xMs9dei!&;3ICwkiKGEzaqRiQE�W<%d)=(eyL>VO7ntAm zgt1Uwya`>w_FuIVaP?<{B#B3p+T}MVa;=`o{SmGFg#+?#zN6iY3_8 zhCgfI_4*=dWDknfJCOZeWMTBZ%?-OM}`%?1VbRuyB`mH z-k-gBvo{3tbz!PL=yZTm%+y2@qNs zOfK93l7S%nf!xnK-ujg`yC+Nq>b|9Y5OZ z385-OGB0R-u@r_J2uDp81@%3k=R1niaiN2g7hei{K2sp<#BTGph?D&BN`TbWi|ucZ zGNImTV6o$(%4#MCEe`dg5!Em#94b8Byh#ckKIwIQUrct`r4qvyI4`VOa8P-;|0Xn2 zimQPbe=8u&+vYUoXj3f3-OT8V!?kBsB*pV8FoktAEt{$*tAOrGv$aMN=yj=a=9|nE zJL=`mUCVe3wO*;`RwYBf=8#bd$pM?=I7jFw0jr<@k*N|#{1`>TJ=D8pAWW8&$|z*v@xt=kXoZW- zkU0iA`z>RhwNiO@40mK$l;|(<9nZR1-`x0KB8m4u>KbxT1n18bV5bbu%Pjz2ROKuI+-x*y4V_GwTUNwAf zPDeJA2e&8YCIF+f>LuWFu-gM)LVKCBQaCZw&L`Y*_?($Sd;rg+Wor~y^JtURa1on- zzioVmrde?d9}y2ocvBZ&d(@1+gBO&lx<#O4#*Z?$J3%r2#h~?igJtf1)C2HFK5@(M z5}2Qunqi^_)+Pbhe&x*Yz-dv6$KJN!ceH5fG>gVpK6W>0xux)In(g4$x_!IC#8TDt zU$~^G>aJzLX<;YZ&*H)I^(t zx*Dd#w2K&-D&kY`nnh{8s^H5Ql=3e5RF^zFEJ`5MCR_C|06le(SPxf~Z?=q#wE zwWlkZ8|fc4Vsg;UC9a+Dsp}VCTDeApO}Xui`2^<%Iaytf#Ch!}1~r5}Kvm3$R@$ zZ1x|W&WG(7hwctoGY2a7VUoJG=h9__6W9eTTqfKa^ zv#E=pRP0_9FA&&5ekOE&hJg#?w71k=;dabt2zmTv4I;LgxN5eA=IK2Xc~}`)mjiq} z%R_eS&3mozjyWH+&Skj@XlbdyQ)VY&z{sz)?V$KkY!<6Jk*noC!JN)2gSd7~c6J*| zj>21shCRzMr@e!B1?@KTw3&ZpQHRKv2}@zji$RY`zhI?CeIk2DWDu!8Wp6gNV4toK z4~wI~^GYO-Ek(35SocSPv?%C!eKj_do|CG^&I{IOp~BdlKK-YD7L`yJI{9v5gmdS) zgzyx}OA3VxjG7l03%R_ULoz1od_T5_jmdSZ>MOs?3AyEa{;N<|2)`$btrFsZ_MD-} zOBr(A_IUn9BxXf_iUQb4Fi+u}tzCz1ulwy&Ou##<;+cfmCs`PLlCi;^i+ceS*mwZF zq%_snE0+tq=T1x;_MGr()H1?_5zI%b)Yb{ZCUm^P?SuJo_eitRP}85SN3mic5yMR| z8vhJyIMF36I}8D(^DWyP{rb?TZ14FMBA9HCJvu=A#YXR-jM+( z!zNJaQbqC1YH+xHK1%cl&r)q4Jx686{*Ws_D>dA;#8T^Y>S{n(^vvc+V5wN8F3rj9 z)(2WR5CcF@B>#3SLU7ljk$I!Ht1B&y7*0s~x#Smrv+D~UhsHR7?`j4x=PPN8 z_9oJ3+EjPE9YkM~AIfpzHPcxTAp)`wQ?LDF*KY6! zjwiC;dK_;Ddm>T@%F3v0)`?#FD0@!bRiY=p`qM5HxP`o*9*fmos9_#ilbb_J=xr

Y&L!}=LCX3zhp?=eZ-01Ji?^4 zRG0dNNq!wc)=`JiY2Sg^$;MQv@0#JChv(CI(ull~UL8WBxF>|IPcoc#F;m<<1JOEL zcI6eC7AA$-Wd%;nmYSJ4W|f{ZmwjP`FC0lc(}ykFFuJ3>p=JQvH*Iz7(m zeFb%f2MkK!AKc5@{hk5WsI;zC{t3EjANY^WhT-tb2LHocMhe(9C1;LOyiX2%&E)IJ=t>jnYi(8tD5wh|b@cchZYe#tV7 znC)YuuslU3K%Z1qvhf6&9GL@hiQol^m(m8Qg{KR=?YZpXGtm7a`B%#ys++%Aq++U zZiX~hkq|=uCqB3>Y|)ABkU3@YEb+?@;Zf>2aBV%0iQ+;J_bW~g&K4-?2>NFR66FPf zlTn%mbgrjS87_e2#?j;Xp%>-}ob%D745PnulG?+t`;*7Nf|;VFCv2F_gLs4zxmMNf zJLY!Hqv>a;D_V$5grpd}>dZE@Y07YRzVE}E7YES9PQb2|0qvf0@tPpSl}n``_HN6Y z(gg$)s?R)ElB_$Mk_<1^yuM>Ez5!33nBS18S=_K3O)l9gID2#pX~rH2+24aak?Gq^ z&*`Qe5(v5ZFkW$Ks?Qp%&rJJxr*4|mTc5p0ZqW+epu7KR`lZ+c7Fo^&RjX#9)X=Tw zZ%Gn?iB?yF*-dF|9&LMGu3*Yraly;|H#T{d2Uw`kZg8nx=)OJPt8F`b8^%XKOMn>p zi!4BTb*q(5Bt8LemHOB;5zzeqs4<44dJ@tL{=mzwK(U6pH9^B9-Kk%G;6jbR6N)Hk z{Tp>lIPt9sxh@wH6^CY6q?)N!kHRWwNZ>a!1!vlmi~Hr@=1TyA0sHcT$9S;Y$SA z2)VU0+|NhWO%7WXHm_Cz?FW=i+e8Ms(U@_r6iX9GlRMoio1+1u#Mj!0TAXl3sjkUg zr=}2+n*0&D^(f%L-~_eI!!s~3cI^QX-nEX3Fqg$fF+PLmMGTxid4Hz>@#<-Yq)XGt zhw2+)p~+0)rfkHMs4=+9BYa2;q7g20y7c#}X8|K?x9g-JE@U;*(UtAK!dELw;`QEb z9K$WGl6?hE)%T##EM1M|VpfXRVnzsm#eY81}}CQ&?~x2L2Hm7NYAzRR2sR z{Jf&7_hPoLO#D?w`bd+ujm8@j-`7|gfb=8-=VSr(M`zHkv8g6zaW{%U>rD4}|KyK^ ztu3X8LO7@VZc!I83kfbP?M3VMWAC4T5tGR+0y9~D<^;5%z^}3ogi|l7s#n*x80+?8 zv|$RV{Sm=sJ)2>BdG@Qj#eDzW{mJ$H$=*3H(b*m+|F4-kf8H5x-ky(zb+F%V`Gr+D z9a$o*@NAf*O(H7t`<3qpkMhwBAG9>?ZX}*bCZ8-oHOE)8K6KJdq*1HuQ{u4&gn*oV zVnug7oEKP zEiHK#+ey&W8oufj*cMmnc4H4h+84iHr_>%@|7YW2-EO?PArh!SXD+)fdbdjTwf5@D zO76^xu_q!8Ewegu*rT_GCX~0Vx<4`Y)TQb(p6z#WB?>}Yfjlv3W}_|#X;Nobr8-9D zOw=Gn`#Y$hNP`GDKYaq&Ps%_9vRhWs$|Q*SX)3(kBDt^6^o43Y6Q?pDZHR zSlu{PZ4rCtE>i?_9P{W8NH5#=6mfY7*In7cC8DNxp0e$GgCm(Om8gcg*NAj+Z&*58 zG5<|2K{5a^nNm($hc2U4gqmHco`##gv=+JQ$1^t7S~I40iFs)|tpk8Ep4;~qO=V++ zFCJYXoMA$RMsZQCS=OFJ<%2=aUzVEEZQw#G7qP#%wk)%)K)BkPkkObY(lTL=ttrAA z9`ERzR-zpf`C53d9(er2#pkklUnbN6q4#<3H^&b|YF+(ZcRh?{sfKz6mIB)|0u(F5 z8|N>&FfMsvm9AegIgY0FcG7b=rj|2n#0BKiRz#IJ7zBv6|HVJnw=er6HavU{S%BG@ zekPNFi7{u{$3|;?9`@Yd$bARfo801}^cNi}1^%?)7~eH#$H+ws>EXH$IHH6t7Dq8- zCV7WHZZ7O{?w`;WNZwdZ*uQL5KhHGt`}>f(5ioAjquyGnL@F)1L_F|lHok#D{PqD{ z^x`NB$LwfuZ~_HYGA&my?i>A%j>=MH=~(%-Q@vt06Op>Qj~DhL*$~Gc+cgoC+_<@O zb$>UW{1@@-le2}zSNkAR)~k`%+5@{$tW|p*%cp7Up1B2OQ$!Ga3~Z|+8sHKOza4}@ z+fHl*p-Gx*p$VGWBbwh#5nwn|JKyvHi6iCupWo2vQwD9juL15woj{}fno8W1zS+ft z1_piSWE^w5n5yUNDTX8Gw$~@HHx_AL(x=!J?Sf_t|MaOi2L^UOi*5*cGp#jCFZsr#pj` zeVws(&XRvBV_mx~A3`_%v6e;)e{~(NH>c<{3DQ{JJ}i>k+7azQ%Ks4B0KNA!`7*tp zb}m}9!{I5@kQ{?uX)<{6PJ}@Gl=tPJXXR|UFVIvcz!@S|Ye*IIR_0Z(Fd=xzMN0Uz zEQo=WTNQ(l>U+uU@4Fp;jwclO?4ey~0LR<=z$Pu3Hg5eRwba?6SINS2H1Fqx+zgEX zFUelpb~!=M=c??(vvY1pvC}fxv6CTm{u0BqC_V+GsW-5b^zrpGtV6wr(U;0A$CG-V z&GVKw-)Du-)@M=uRW(wzo zwbD-d+>4`>r(>3$bpi$puS~`0EIYk{`Sr>@>)TC!^t~T-z9fN&LnW;Nph1UwiKXn! zaf@B5QPlr#`;Ez8Jgg$`5wJ0=og2}G7MkWXdz(T{}Ak>eZg{)cFDq%Erw-VXj`&t z_-qFXn}~u`by2s7^AXSfBjncxLb|&XX9NkLhZ-$NQ|yA9+2#aZ>yPy#Er7vTS+%mj zzHaS`L1Zsr;`+GKS35Pw5o`!R995{!9NH12RSRCSH=C=Okie+!1X!yiz zPIZ%`?{W{H*16osbeue|7`Fu^z<^!i5Md*}Ssi>FRaaXx^;BKkIj45Iey zGXB$_F9Ohp3|uL%7z!Gje>Q3mY&U99J9!g~x!}G(WVb8WJVw%Pp#AQmzfhD`DVLf|H7WF*+L$`vLhOh#zY{5Ln2-GmB*p z<0EIK9qlM2EWi%aOmuE*G)?0Xz1mBNXy*2CR6Idok{Lf5l@6XW$$3wy zzdhWU%3RR>7Q3CF>Q%_#CETwRL_$99g^kZ?iMl53bce>;x-C0YEdmVdYS^L_h zC;K~Loz<0kx36#q6v6nc;Q_4}MLUyR{51}B+tH-r0BBZez<40P#IN@=6-VKQ4P*Gi6`KgHiC@vvCEo>P5L2&uB5N;>Un$gxJmC1`L*^Hkw>}ltSK4<*I5tI3Z zq|KZ7m`5J;BYZWdLwEZ|N0t8TBO{MwT9KXwA%;xfy(4!W>7>Oj$m}HMyd~mSO(JY4 zQ%BywUy$Kfd^;Opw8(@4gLu5;8Y+}e*YS)GLYy(W2YCx(B}}^hL`=Df=L`8X+raEJ zsze>gNw;WBSv=$`6FJ@Ih^i(u1#bY9p5=Lw+@xud?AJcw6;IcsbvVUVp2bsH*OaNd zlhbbkktxtnLX9t$bO?ARD8IPb@eK=kD}7oyY1AA4-W8?*OL&kPMYRj zl76V3QWxzvf|v-pY4X`KC93(xR~IFjM`&lI-WfOdjQw_HLc6<&q z-q@k@eS0v5#&0os@#Nyx%qT9-`90M=Kb4Hz-%hz zvE^geG!+nmBm1U&3Tkf6_6xkN>!PeoAwXUU@RahNfHVbsAltGaR>1wczbt^6EJXkg z0TnpU?EYRJj>-Y$0_rh7-V#t&UmT06*cjm+u(^une52*H32^uCqYaH3a=b&kBL2$Q zz#+^cPNUEqR>VNn7(Sh9(mnKv_#&rEY_0#PArB|#5iMl?NGoHT%HG(2^8A;^sc=1E zz7i>`v-w~>3}=&1NiAm5C@PzKgHGhq`f?y1N@uX^>9o?(UM7knRTQ?uPqt4*L1t-<`QL41Y1hInT5A+H1Yn zYrS_8$A1${rT=$>-Q{$=V)?l6{s%7)!9uc>c<|aEV$QfSIVsoi!j;gUKl<5^3ZTik zKlm`yT3?&fXVXVw#3|C$e-c(ck<$6?PJ>6`ImlG3vSIYh`ayGD{G*k9=)X2{RK2&s zhYr^&-r=)4Z#n)!FORlWwbb89q&{4%mbUFfzt@4=Xtld{;Jp|=7mActEhJUd#(vc! zUD7Y7f@1P}wa$D>evQMz1x0WAreeHdposiX*_?=+HX;a}`b&eZhO`|V3t5h-!KUG_ zR6?xsiNk+Pq_^H`_1_eFWH`@H-29L zN58j=Mv#5Xk&Pb;wV6&V>00#s{Ax+^!#FE!{0m=^y7?~%!=i)-_)5}2_I1LKQ`fzV znrF778Ot7WmGJ*MwQVsx1@G_8^e=Uz)IkCkLtj2TmC^h8HJ-p?JQiF{8R$3{z1-it z$mgsm3><7m3+3%!(IqQWSThQ+!9rmP|WfV682t^FWN^c z_h8t={Pp)A^8U@k%oe2$i5Tl)avL7gw&Nl1-Ds8ON!69>K*FD@-J-3;X@x-|B#UO*@MF2?Q$-? zfHlR_8L5(Bbj7&CSp{8bC?n@na&DwM zfXzAlV9m?WcpFv6pK_k^!mpn;-p);95KRHT#c`r5!u8PRX&oZQsp}lwP+i_TR}cRx z9)wF>AWZHmi+98}RXs;Bn?651cb$cpbIReo$-gM0wPJS<|7Ou(;F!i1cC+%!Zy;WC z6CB|T3qF0&XVtE|2{ZgO%~gk+)_i_HB;uCB=;n6vn(o;!Q@qc6Xzc(J+W)gBHT;f` zqYLQa8v9dNp1pciK4CbPnRj{8kJnh|>~mxuE<60bAu99(M)%M5yMxX3$BWWma=l<* z)Ogkoi&}fDA}g9FR&rnaaDTlyToiP4Ar^M`Ws_?3NbbflmZcxJ<*C;=B|*Z;3UEum zXrX-Wf5&mj6hXv+sGWDklu1L}(CBH62<8scKp&V(_fy`^{TpV zx+rs)bu3h=-n1?4yF$WYv_6DyoZ9ECG?_1-($fQM57`&@+uN=xmJbfX7@XX{vd6Z3 zMOYP0GaN_^;;nXS0Zf>VevWM-bb9^k$0ZC#W-3f2K%(Yy=C{i zU;!A2cI<$h6Srf1v$(-sx>BSV$4U1Ri#n?1HukF;?p>UXto4O;_mpfq!-E8>X*?z? z%6Nfd(=E##Kev-d2-(M2ZO`4kn#DjEq}ZjQ3%@dV6Xc|%K(QqTwMJy^gFD!R=BC}i z#jU|^aG9ney<~1ql#WgIk^(Is%Nu5MC&_anl6z|G)}n>n+cE8t;;_j<3lPsh4`H7%SyJ~=zE6(Z0%hOG)JF#XrYY# zcS3tZDFJSO{SJqQ1_pW)NiO~&LET7$HD6OwQj}hpz_6 zri%+{ZCxSW_2h7e25ztxZQ zp1@a7JiI9dY3+0@>Yz@D-uZcVorW+&^oa>pnD~+R9f)ix65m(vQJC*cGO0iE5hTD^yC-_pXR~uPM^yyOoD3 zKji))=?9@%7w}FfJGNdU%HzSH04Fxhr7OG@yvSh2N3L4ovx(=gbZUGadsbO;{eG@ zq4?6s?#}67|9J@)iu5F?2O@*r3J@`gEcd-5v@lk`$5QZD^y9vOrF37d{b67mQD}ymDX-n z6V4#hm0Q`gzTEm#D2|sM_F~QsC)u@})4j3DX49`-<>82;_M!QD zbGm6~jRaS=-uNQ9Nu|lO4jnTiWqoXGk*sEfZCzs{lBF>tiv* zs`%OGmy_z<4o~|ejvt+x68kq;vU*Xm9^KO|be~PU>+>G>$1Al*`CEshP+7lvg}RE} z!(6@mliq*ZY@g(7KoEw_x?r*m@3&^6;Fr_Rzu(p%eV>>SdoQU2L`&IPrqm%ec4BJ*4qS}1DhKWVJ!lTo!7S6Dg22spp} z8a34IY4yyN-$?HJ$;ipc8JBI~Qf5wi6VwA$p*v0L?2_OWU1ad!^5|qB-~ibN7z)m< z`w%hYN7G->bd!qOtNVRJMx({f3T523HM8LQLXQ01(2 zvqbxZCbQ;c`&r}RvHX4Z9s~D(VGf4_tOf_+=9~GvX|MEt!BUe&tkv<8*r2*;GWopw z*+pE#TxL9P(RhuOXHSPZzCLH#&B3wohS9*oyep{X!w~8%)7oJD-#hS;+*(!~eWtACvISE) zR^EbX5lf%7975!AxY>@HK8s(XH=8qCwmpBrs5kRQp-?7mQ>bibhZhY`H$9^(O|2?F zj?;}uDv9SS8PW!}TM~y#xjkp|oh82#y}Enn!R6E8+T7|SR#EEy1DPnVB>HwUJ^EfI zPt~w24-|ZrX#B;2nOX47mgs6)kg@tiTE z;(uylXj&X5|3U{+w;%C|2GcXxs8>r{U7a{%@pTUdSyqWo*?ObD-|E#qb;%yMnrhBo zIC@fi+yqb;R5f11dr$l!19yt`CQO1WktXw`m2y@3OfDMmC z=x}Y`IMz(4R%I@`TOvoVB^;)8cXTKeGL)f?bNiSB2Pc2~UD6atF3qF0TNYH68uJXU zr8^y_qAJSE^71evtjx1rR3e27A(|Q+HD-%jr)Lc!;gb+7rW*2~CEiJsFvs4R8oCFc`;?#_eo>00NYrRcJO+qsCW4AOH5%MQY?nHbSYs7h~i$QR}_C!9F?`bixQ4m9SGe>66D@nsuf>eXmMoAyw@yG?3cdVS{uq)mVZ2nIZ+~M&q z`!=)KgoMC-weKI#Ocl{tJ&^-r1ZEo7-`ZmmnVv#$HC~Ubv2=HKYkQiX7)lN;N1uyYosuNHdv=|wHP6*G2-;`> z=8Z9xRurLDP!uyVn{n1O+?}X4=1ZSJu`7+Wo?G z3zUv?1+Q%5GNV~vsA>w|m`+ZjO>6BJXrt04u)kAM!sb(ZKzM->$@mT_5CJKYofvQt z{-)V*u{52dZuXP@Vx`1xqw0mY8NHDg9!e)9w z0fw&V33no-Zp4q_lNV?yZz@QoHZcPI(O5sXxk(2KSr*^&@aJh$3i^(1HhiFOnXhN^ z{6q>!Wq2FJlPu6!Z38JG^7dfCke0=kwXqwCFhz-`pd51WU*k6F1*mGE51$6EdC=CK zzkXh8zjZMFhLj^~`Pp;&SW!e|%H-tJAOl zy@QM?(fB&AeK6h}{Kxd&+u~fi1K!QyCK>=6ZHZXog1?e^e23x)=2z5&_)b0JzWHO9 z)x!H&SbmM}oYPn=_ zutJ?UYAYz>+{$*!#R!^L*RTHoIYL4C^dsq8MF8 zI|UQlSZC79(5;pJyiko9-n!O+*d9NB+to&Rg6JRIOj=R0AS|jKKCS%K5k$IvV5)aj zcK`@&w5Mh@xc8y*5$NTxQ_?Wk>6-$}jWMWTXFQ`=WGJ|2lk~HmyN5@yOZD6wPZGZu z(OQ)`vnzSL**&Be_)2vptWt@|YkNKIO6Sd)gEghSq33*8hkzv0Oi3Z3K&@@-E3}>h zq=s2yapa2FgK%dDEBksbI z+4GjQ8&~-t7RqLWj_5IgqwPxqG;R1Ag|&2!3JnHX6on|5@x+!AmTXj%QB=tm&4-q^ z?$u(jU-^%`*^{lZl^oSaU#sW&#*k?mJx-Q{y$n}2(mO$`dLOe0&Mp2=oL5ng8w3wj z^dhQc4`O2o>!!c2Vzc=``a3C>%C2)j+Xf@ zWedXV330>dY5}r$6#r$G@1Y`N-Yf%1eAjnT`{$zLfnKpR?4HJLgnj+2U_fUerLOBs zl+xD779hgb^ZatQJW6;`LZ>*BmQw!6yNNoPDcQ6yNo}7lZaU-5p$DONq(e6i5M!Y@ zv9pfY80upKL!(!k68aJ^;v@gZKDz4h8WM|7d|<;2N*WSVte}KWSGT+@e&9G>c=Kn@ zDdK39st&RIp#T6jVU;nqC!>K5h(|B1Ui;6(+r&(*hg2LyA~(E?agPX`VQDEHbbf<7fWm4zlChge_w=^JV*$$V>I-f)xQ7F%vPcf}>&tbo03>_|2(*iG2v^MeSU=Q~d=t&WiKBK+%3Hu-dO^xDPuFZ9|+@_p61A>Cmlb@ls?>|K1`OoqZ_4A-bz^|rot z>cc$mV)!cqrFxG*#jpoyR=VAl)bJE^#I4BB9UfW6PrvG6Kpo_FeHYLi`&G)*<1HHh z9es;Ddp(N?Qm)bt_gT*3*OfsP=~Y`^Tj}!ZR=;=4u>J^6%oUo4zt4|F2OD`1AMx_8 zGDL3mmgk+*&R6wjK#`j-oXcL4{h9R!Y>ba7BMXEp>VFq`M`8QBFu;g;{$lGIs_+0f zi}7|2B?F_KVte=FtfVBfD#($a=DeVG7MX9yS(%L)(NnkOqjH`~sN;B-!Y=2V zXIeA-TYh2(k$8av83W0n3=jx^OYfmjA|boN=@GlZH0?TCTm>~=w{+iF;YxN%?Nx!= z>=V{Jzb+gLVwRS)p;7MRzGe~kp6)xCx}>T%w0d39*xg+NQ3+N$R@E#i$@}Vc`|^7B z9%yp+G0ZM8LV@|7__ZQAPUYaOVyU5m%SKYZnoYWTFG@iu%~K)EJxa!>6POq6=NM_O zT9zRmrYDHgCGWG$dmB?eGTEYg!uTni_G`8-NsGafVg;PX;Vy>8cSR+wc7ng2GFp$w zb1csw7`w~HdFnv3mccn83Jy?j!?Y4yQ{jK)`#z1jJ$5{1snd78mfeE3O9Du4>^@D4 zMk{;L`VjNaE}WOEa>muExZE9~A{f^3Lxr?aMMHWmf!qv)A^_E)jCL!t-8?YdINajP z6~9B<;+0?rRqVcCZ{n+zfNycX-4wJVHpEE)~4VadYmR!FAnj zX1p=wrU?9R4ze`HCSm6uwu<2gkr(q@0h6<~e7)u+tbbAbC1c=A*;LZ>9)Vt+Kpuks zxUVi&+QL)!x#5%R$^}8c`^Ol@x~zO|*rx2?!lnCzkIaCZ58(}SspBj#=0&Pm^}rb(-vgWY zOBH&mipzLCW0O_AedG<;-hspmBFnJi+YP(Wq(}%^Y6&aSI6-K|(s+3R{WsY00cVbh z*kkMhX{mg}2dg=iOpUL*txqH^aYs~(NQmZB{()3ufc_fHH5teYZdT(X33t6&ac`8c z<0&?Rr~Xn9y{_^-fXTmXQ!@Bn@Yknf5uh?dpKE90p_&zE6?%&Pj2e$wHMXvy;Ns2r z{hVnP>M!>u;8TF;elH0NcmTrg^JT*{H0Q!J<&V(vm-y>wqF44AYWuKkoG{u1-0~Hv znG~hFTA5}^q8gJ)osr*r_9uVZrD+Oc65M^C#SG><>yoh?udJr@)t>Z1Gp;3=%i zF1rx&m#YSXrTinWGPY(1a(Ms(SjIXz$t%_3(1bAt%(QpgYjD^Oe?)j)nyzlR^sbi} zpE|tCSZF^PRt*0R!JZGJMo-^o7V#vh>#uzRP2lK~q%z}tCwyw>M+vkZ+kFJnL=Jp4 zz>@w*qe;UuHCDXk!^cqIP|*M#`=QS7HWlU-tsD>hJF&%P_GdfQeI#Yzx*iX+_$JQc zW`3BKR-0lGW7}-ax1Lgo?|l>s23g1H`Ytjpz{<*g4*H)j_L#g)M68{F=GMHAp@fXO zR#&p1^ax0eg`vZ8r$7|Kc|?!DZa2^4u0NE9O1}-K^vz^fR1PpS&f9^*{GiFu#R3|N z;ylUMR{tyLz<*WTHZa3_FO{QolzI4I1 zYCB`GK}Sb&n@9?|Oqg;m*6ucj43Fav?l>Te;(}%kly?>b=CzR7_>MqwdEeXB!gS0c z_*S_hFd#ejTuNae@$N6T0-*zetPKPH2tEby9CFhneZQ8{O5id?4T@{)db2iw%E#vc z=WiZ=xOrkrVmf)s7^*mPwYy_q_@E(0GTAbU0brd^odQtm?_&n90(%#>gZCM6xp?vt z>EzCIUHuowQN!)-_)eChK1n;vh%i4=2aO2lO5V!^vyMWK0b^giS;un>Gb zhl}#in-659e#w@*LD;ByPDM&qQk})mm)!;pkfI7!0MNXElGankvv14>o zEcd}HHuxDhQvT^5(FjP&F$UT>s3^WIC2D8B3-eKd^KdR1QxYXTfMSpo7K;*>BJuNhwz%TaK60<{>%)opSxKk& zcK;amtH&(=-mHTNyvPXufXYAH3ho~7r7|6j_rgRS#w2G86ZmgFLMp=0 z?o@^CV}I^l8&~^KG;3stmHvQbqBL z(5>ZmAJ%I?ibCw^tEKR3E$6(f7NCbCh`DVPNN&l3%js4DHd&hL)Y{@`wwzY705#Z?j{@iaP^A6C9aEGW>DrCw;7$C^a;+yqIG z)>y0rWrw&2{%^3Lw5F#=1-AZ6-moEYLMfTju{6r6*W&w|bR4ZPk#M;;yb8pA`LoUz zS~~XOEIeYdczEQ zr{VUG+RUU`qO0>KBk!^SauJvl0dygWD?ZQ(g;hW%1HI#=rs@+G7=@MV|0L&dJDyjYzLQI$h%Nbt~(@L|jZ>bp1}NynwGEM4sSWtEPw8{UHsYM{i6dgmj=Z}90C9P`q{K7gK`h_JRCsKlgV zA~AJ*MrNBu^6&Q{^-WzMAalM>BxXLE_@>~YlB?KGc&BBMNB6Ab4R=hutMD`l6ML2} zJ_vkeuE_1leA68CFG2}Gnmq!_FZ11{KxRz{n=wUgP+aV6KtA&2ZTnruQeVv;$F50=%%J<}_ zC9bXm;`?Z=Hu+V$kxHtSSXS47!HJ{Q66PHtRJ!jQM0BZs1LsgNSzl6|Tk!|k^mLY&e6*!@fZ(=@@X3Rg*> zEtJ{_^qw&>!dx3x4V_LsMCKuI`x5&4T~oDHL4g4wGZR~9s?d3L(nqbdM*%K(oCq|& zXG>ZK9@|_{V5Wcjx3EA&1j~Jyc)V8ksi?^=f&&rsW>v>;xdWqeT&e>Y5?GI!y1EEw z5&TEu)4yad%&?sajec9WP8(52$E1H8swuOgZ2KG^E_A`z?)WDO`c3v9e9Zt*`G?;iM z*7IkHk%0~63luq)|G3h(P`YyFw>%wdw$+%Cjx`P?Mi5M&?1MolobKuFP zDFq6Gx8>5X)c&-Dr0RZwdmk+b4$M}E)nC&kO2Ua$OmFJRIMDPG2Qa^Pbp!FiqfC}F zg8;~v&Xc=PZ>(2vK%zI=oq6pzROy^)&{O`7#qZnC$ywE3p8_u49xY_Eqo-0rVg2X5 z?)`taOX&lk5V-v)JkxBc2CntNNjO6xO_UX6%X;YR((L= zE2z}3(g>EV2uxH8jZINJH8bnm3y%JUwibTIwpm3oCpXU2TU~gg{Sp{pn)Ley#xJhd zegs2uwn`m*umSAy?KqG`zqSuZ4sa&zsgY+nsELv_@v1H2@2MZ3W&cxhQw6pF?ls$< z_X_;1mq?)8ng=`brS+d*eY)DCbzbu4)lhb=zClB}S)sXhUxX^XnBbQ!C zL89~}Fgnc@gLOuv2;j>*fmS}3e2k;*!~*O_$QXH~=6I5X(w%GR)8$D%BY%Ygfv;dY z8P<;kU1V!|{f*GRor{xrzyKOBnNs${yB1}|b<;vHMMl_I6`e4R@R|wzMp;+nv%H#1Kca#@8y0`9WZObSu^#Dz!!tjEyPRTbm zEWgladN>i@ON6ttfIWr?^jJ$?YY>O}Ji!G`P%(=RUv%-TqZPP!7cQo55x26$$u zPC0$=ZXEZCl#&C7z__XhDy*h>N2sk2kXW3sJd<)X=w^NiK zMP$_f)~}Z5N=_LbqM}bWkr)=sV)$Iokmi5d<>HS{Dp@nmtB5WqJYQsxhu-nCVKN~OOY zu0(n|12dgZ^Z0>(HHetcW^=9hdkF^QCoY7=481{AEfhNP`TmywLCP04O;u(GmR=H5wtd)$Yhzwt-I^V{}#zOLL@t?r=X=~S3X^@>GD zXQ%ePi;fOSz5Tv-y~94;IfqTD&8U+3O!;#Y6ECl_`hR$G?vL`bK%Zl{$1jD6?rbJR z-F)>9ww0p|=LDQf+QO)V{Vg;^a(g~T%x8KJzz{H@l~S&R9srVL0qv1J&~DqjlhYaY zv;I4=1PKEjn%vX%nUy(61dM3Uum?s~GQWCVY5U6c@rHy+Bqj?l-vBQ!%>e&XMM>*&N=2Due5w7^>EHDij1Fmck8%XhR*YmP7Po_V}-2l^z|5101=HGta zhWG!9qzmc0un!v6SL7dRnd|_D8?m=wiKAi_SOE;_2T_5VJkOY3H zg`TLY5XTuPbvO>(4b}Rr!d!2zDjLu<`vn~6x!QfXsA9Mi|o|^Ul zE5foKk*S?hOtL^&RD2jzC#PTnzCX5T{p0sM%+xPUVn>)vR%-jgaKb)HN_M8Ey|y_S zU}ZEv^zQRYh>s5-YPw#%zuCzUtD)~2CFDKFNY9bz{SK}AwnaFFZiF>6{jJfkBJr!b4qTx5R`bC&wey7>Fzh0Na^!N{8ibs zsLpozn`uOy%Y7RRG64@1L$w=LEFP6Uq7ItJtl#uQsi^A5#0QDGX(%jwig3qZC=hSzqT|_ub94NRkH?dG zvl!(DyR`L&E{_0`$BnbEHy2YA>DpldwGoT1I@;$VEbg03s-e*Kwn`q)dOy zHkgo=pk~pN2Afs`3SFh*5i_PeF8Y5{##nB0U>*vPL?pDszi2;16*R$u8bv^u_cw=| z@9uu7wDRDH9TxNi;HBoaVp@#vSfMlnCb6An;0U)JD?#Z>SodU+Xl?JKn3AbGcoE;l zsO{NHj5>M39I7~9hP-P6Y7(v&Y+FZd*Ie$;u~1{fz?9DdbFZz_kTf!D>)7ei_H%2y z{@2DEq40h=a66y3iO#1i=c7ZVo1@}ggk@6T_vPy}#Tiyp_dJ?59|8c4(o-RMd(zSKWSzo_bwQ;(=eR=O!0Noweqk{O}2P{RJT!3x)x~Wm$ zK)DO2hAn_5FmPG)wut_c3<_xe!@ZM4RC3ML>J0*8d0C#*UA%tGWu_UlK5`{M<;K@7 zpsC(SPG>cCh|a=4v*IA1uyJ{L^49&js^9#qAEVj$K6NI(=$@)H z*iJ6%Dt{SV+X6j`R3J4FjlGPu@brY_vfmE8KHFY8wQ6Z!97IJ&U*_<*X4mi!5nAmg z7K!~$$iUwhSfjM;m2%LUA8pk(P;@EzIkF|WZK@|=bL48(=dSgnXWp`3((EPASZcMfKx^nE`zq_ z9D-MFIp6s~xTgdgeVgRkJYc<93aF$z2uXF{{Qyih1Ve#(BamsHutuS87GJLH0xn+U zmu#;;9*)e3roOC`fvJ zO6-0${6l-k8=w&#UHJL=wQ2M!F&Fo5P%=c3-|camzKf!Nfv2lfqUI^Gl`gN=+P_(b zK@ZpGpNbc*NKQ+OsV9col1`CWZQh=6!PnZq6)BtMUPt3ONDS(BdY?hlwnRy9;{*Eco~K!1zH}J<0YXJ>xJT7 zN28owrCgQgVi{c9v676i9e?MCeUVf=o$wdAq1Ob*wHv=DD0#nP(XT^8b)x9U|7H8C z+L@CWoO%Y!kAvE3ID^L)wAa`r+Nn39n)8?gjF2{3v5$p!M+m%me!kw~X;Xh`AXl2&$=%q3bV za_d!(`2^N41$NK~#rT6(zBWyTr4w;~M?<2%fIoaF_PdeL89>p+iCl~_cz5TX#H8oH z8sjdv%+-9gEJAR})VFCmx$#Wq0Ojlewea?mw3(N-`wW1Xookb?eR#XR{%6*c{b*r> zz#x>ycC(l^itn8I)8i3Z$MQOx*_pR7+Ec@Qo61n_QBPQ~;DO4LEh*TEh!x1|I63J? zZ{!~^@!1%l?*f4#pXH8U@+#%lmSx=mzQ91r>g>U}-dcI5@@?qf9g2t?_rfoj)@8$K zf|2gTC-xd6B&NWh%ecV*C1)!&=}z;@%iYIY#9XevZen2>Am?kN^2jI4GNHK-t&a#|m{J)Rbpmj7SG7+uvs7-FFG z)w4ieI8<5xll7c=w5mc#N+d-By(r5ep$vxIS8malz^u^alniBt|t>p zvV#*!^4z+8<4TGbA)z$Yw(bcrXEd#l<(`}?XDe|}=bH!&XrQ@GcvTEU|L<`46k2&^ z8u)OKSCEw|WZ2{t)xR!p@uy{Ur9o1qezJf|hmN59+F?ix`18K=)k12cQ=H!$jhExu zDSj5O(xhsrtb0Bn*Rl4`^H=9lt4_VV_+gQ9hk9TfuSqT)EF4YEj^~wX>bKAp9R@{Ij!j?O0D=qQ$Wwox^*Z!PkaV%*ml_W7o- ztHaJF|2lYH-u%rF9dq?me2g$x7j@g78%wF>4Vj+#)12IsdhkU+SDa7u_XkGC&rlkS z2HvZ463npY58R_lZ_T|_oT-vcOA=Y9 zY}eJVSd*#xkMugm=YX*6@p<}1p@)Ya;Kn2tsJ}>wl;yiPYl{Gkd*fF2_kWU^GU#R| zF%h2BQ7GCpjBSou{~)4-A3hHl6Xc3PU;N{H0GkQG)UDsa*wE16)096`&#zxU3m9s; zC8KGUF9%zenlAW-L$=46T>r?dPB+h-u?knm-rR>Zoj`=8Z?_%#oGxIXqhZQG!o0hb zH7EH@s)O?r1zW)NIbr4nwImue7A7RpRH=8aN-NZ79icL`_Xkb47tjZD^RE!56XvH6 zc)}Lq=YPbzE#k3pJN>?DuC~bCvG_ryZQfwftsWH-AwDWBCm|8+>RoC&z%_F*jblHk z>Ey2;t8{vh2mL9nvQFd9VCB*|T;N&Vhv&4|0uaywtq9O6&vm{Zs>S~7WhjKu`*L~g z$K!e=sc12JpAX@>OTX$GkH4Js37JF&1NwA)%t5!&WVXTyT>}`NyI}?(C^Fgoag$fh zlo5<5=U;VWYNoKexV(^Hl2p%9Xwdy)I*I%&&#~_2>fOUT;9EU@F-qv~5PHk;5`#Ud z27SuIM=4%Z%C5_QqVTP1wQ_5C-rwJ^mwzYrDv#BguMa7&u*+2{QX4D%^z0?GF@z?X z(LGvKWo4AsRA~U;jXQtYkBG1^_9{yUtmm5#m{(WzEtP3s{f}(WARy6lZJ;((yr9Rj zJCB%H7Z}{^1+*izQj_~pshcKs==JC z1o*^E2uDPHUMQN4vtIm~@Zt?dk1FK_Dic&Ahu;;0)J~t-!EeBv z{Cl#Z_z_ZM<=q#*vFy6nA>k11$qTeuG^-J=e3%cJHpHfVHt8^sXr;leM;Ko#og>BJ z>uzHg`6;qSP({w3eJhRBd~s(W3!?rwCq zy?$>WDbr9Vk)#d%^r>rK`zS9Cr1LKRG1c7ogCq5sN&Il}8vSIfDKD%>hT?~RCbU?J zc7_^hN*MkF(fVR1b2e&d_7vrXbp7{Ln;gf?OQ#fzh>m@f3-a+bZf8SMEbP1;^ZQ&} z#OIECH^tkb&r_a3KE7Gt$ND+cdvBYN6K^f>6RSn@$sBu;P)n=26CVCXbsAQ$O->Kc zDnF?Je_R^hirS52JYE1)?`vzGrxFZ$1tJ5kd{r7uB5n92U2f61H8e2F>&JEBz4Rt{ z`P5@Eo)aM_+3Ljznde1N=F`usf#(JK$2k}(6|BC^H&oi(`|@q~xgn+RnB{`eOc4s@ zsP)bdjRU^~CU$(fh#5a!!O6?a@RwmoU=dWEp1t#?uWawcAKknp{;C$1+{hk0qh(U) zB|WpG;r=e=OO1&z*7Tzwx_3YwvOS2?I-E-@bZC`RN0oaYU;~3>GVl zwA|`gA4BN%NbD%0Od;wWsVJavt+lni6980mu6OofUi}kgP>-9rTMBm6$S->3W5u^=`@3jy^e+D| zQpqT(s3^Jm-EoJcNAq4?#X@&WiIn04$7zjF4Ak^C8Zbs0`jDL>m~w@eH&}#9!fEfQ zx7H-`i3$18g}vS=SfCE)S`ul#`ptcS^fzb}i|h1tJ5bUnt5%-YUsX;o@+$AukloFk zctGD>hm|X~q=|5`T70+oMSrM@1i$Hpp`}3)##JK=!;HP#yT{ktg38a6OB=CDin#fE zC;DaR?DHN;ZVd&EAht$j<(;MyX)0dNSt^V9d7N{?z|>W*yo1V}4i7^+n?)bcGJRYt zhdfZq+8$Lxup!X6emb2};P@~XFCZAmus2ttAiFJ$B@=eu6@TiomcbULKzWBK<6p$8l!nhZ3`9kzrvu{;7J9ln8VgP}OOsK*G$M;MVRlhqrXgy*@^lU`rP zYAv>DZ2hkNsE!@fXZ^pE28K|kZw^5XW51x-SD?83v>eVa*h`V(646w?bjNBHClWiM zyv-5qfnDMY4td@c2%C{NDYbXn$H(P^i>x94`!5v97Op|9&2Q(_7-+}5A>t3 z>d%nG9^lg%LWPaREIn;dG@V2esxAM(+B=2>GOvXUJw}I?4~kpA2JwmvZn))xNbdJHS|HE;Vem&bCnLqT zXCpkWohM1FDG*WeMVQdFI^=F~f*xwm&hmI%vbef+XtD=e`Z9pK537`I?PN zT0rHw!L4e;jW2&21P8$}9-rMgxtE;MSk$=V3ujB=?rIH^WQ~=zV_~p-xi6y4?j>*w z;H*3%BoFrGTYL|;F(ovu4wDx7GuA1hXKi~cxBvse@s`x}btKyp@lGp+YFN6o%*q$y zk_>5>WyvwBg1>Zs>VNKhms@QwHHusu$*UtD~D`5;b7onm!)H7H0e=fI9_w+hWJ^?P04!mM4ZWvz&} zxoY-~rg=6y-o3^K>IDTU9$DxQ%1p9Eg<;ivb@@X`c+vx)&n1#35v z7$`)dS<6CQBQ{hkUynv!yv%uNFn^BBb*R@Y`mlA=z6l)PGhColbZPBJ{ONR!>B{0r zfRz)Ovw(t12}@pSb7dMsi2Ix)4C4aDfjTS&q3v;6L08HH_ORcLT>yse=`z(XnQI$8 zLhu_rgD1Ev`X19%NR-aj)DioQce~z8yNFChMnzP}kSxKX+0Zm;noDU{%zIo%6-%j$ zF%5odOe)aZHl=uOeO2WpoEV+2woIdS7-+bnAgymgTZKYX#}>=}xe#L)jT1zgBC ztsKa7j>w=lxl{~&{y_3aWl_Pla8Dg(NY6=$Z+X>n)qSst_WF-mmi17BI=q9inY#g; z6Swpx1N_(fZp-4pmAu11G__^WqT0}el7d0 zrTkfTzTRvri3oDePZ1at=udA)W)!*^jhZk~!u)Nq$(FRoKHK_YE)!BD+Pq0b5XGn5_kpmC*8mfxUf zba1Dv56!wMh$x4J{v5j_A3Sae$u|_|KaN^gR%^}ZUGVLM!HiPq@=sMrBk{E=|;M{yIZ;& zq@=q`I;5L(1Ny$-IcMgZd4}Pa-p|Fp_FjAKwbxA;aI|O8WS>bD=GgI_sp{R`J$(v( zP?LU&7%gp`s{yvCN(ho&GzGZ~DK<@5cqT9UVKMP_rT5@Zr{7R(`spD#E02`OVsvl6 z?6HNhxeMKeKwl9lL#?f3j_G~k6s#r!rIsXV7W9SU7~{34v0*?#XYQ|;U+jWKzG6H= z^$&wlKT=UbmM_k8pL_zn!s@zl3`d+%m40i=CxvxA`lilL{((I$`l|!CvLpV>(?7RD zwg5z}Ou?*ut;qCjUg51nr0zN&vhD78cWJ59yff1_8z+BByc4%HKZ&^Gj;Zg9=6R}2n4(0>tq<{~q=`vI-)(Vbb{IOA!l z%MW2hDj+sKp|5%)o&*KmLlxV6ZlXC7pSkE*pr-V`e`iB8n23LbtVMM^d_^ehSMvp> zQ*vD@@qxXnZnviQ6uLIz^c3TK%}IXi6^6u8P+L>o;V;G}nW&AeOZLoe*DIP1R3hjI z#Q$VA0-X=QB~}%OO$RUuaGdmGZ5}mP1=# ztz|qB$dY<}9?2i?R}h*v>gB=RWeC)E#%}%+>T0q>JS`S>yqqqv(9>N8TPCf^*84E2 z@TFWTm*+`oMxZTiZL%@ZhytwN&j0~1APR4&-r>7ATFIb3Cs#VDA<7Z%j zs|qJa>ljpound}Dle*tjMZ9lK$b-w@C2c)Ff6$Fd`mA|3grZqbLsNdg9>}XM zKsJ~_)_dMS6|zDOH)`fsamnGFLwFGb9KHjCs`6@}AbdXf-?7_CjeTUfNA!yd2Y zB14+llLiWTOjJj(8#h&pRI8?k4WDTdQg8|fd4C(ZyuAQW~N7}LYGkd+?Ns6~r znE^>bVy(K$MSLm87(hPJ@bl!h(LWN^bwXMHbUN_|Mrd6;PF$l>7*vE#^VfFVl(y>I z-lg?+0PfXEeeka=c}QqYyQ2TO^b7kIfJ`7@!sHoGE?nxfDT0lW!-1sRA|43aMFS)y zSOW;hS9m{3m0|4_H8e*2d$~=XR*2sD?e(i=x)WtLniig(37cF9edMH7-q5v2e=HY! zGgB)(JWQ3lW*0pq-IwvMYj;3miP($3TzrUkT*@L; z->EA)DjPjP24XH?Xm5B)NNOwGBgptyV-@#$W=D<5BgIt}edR5Qu0S{my}2~e)>g6q zdx^fDsJ05Wvl!JnE+2Tv26sT|3X>^4qZ$YKNnZ-uhB+JdTO94S*!mxd7+lZribfa9 zEc+t1sCR0A>tRJKZ(E_!kVEA&ZfT5Eo(;1f4H2v&Y#4VOf!yL%hSQyjFY?CMSs`*) zsHq_rj*>(Jhs8Y4Od5!j}cw66a_wKEq;g-B(+fL=a0EjCdm7?w|2lzbN8BCGbddh3p!%9P} zCza19ZfFZJD$1(uc3Q4aodaq8Pc_YH-TP<-*!}^62?f@4&?s;5BQv#7ksNBbe8rU! z)~~3cY8?iUo(#8RA7)OS6R+K=a!YV3skPb&<_Be!_v21FjQ+8Am;igX0Xx73@sbrh z)sbeemB|jDw4@ff$jqJRwGC6iF}N{r``7nU2;vgM5K%yMi9mCHP*71(c^IeBk#X6pInrS8XP*7W7`_9n)W-}Q@JHKBAH>S3!i8kZ#)HUJ0IeJNr{GWSl>b51{&wzc=^*OSKZFWHoY5U8avtSury>rcq)fgZ2xhXdC|Bty!I-V*)_oj| zHc_1leL8#Z^ue~F8O@1wSu3`goI9Bu8dsIZFP4!in82pIPaN*v#VZ!AB(ypN`Bs9Y zr-EiE{i$e!%T|O!b7j8OkCF}&jkmTk=Fet}9_^~Q{_xwMl}`K|F9l^X&|s0!+_w>m zgHR=0DvM$tCOWI6Pe^XM27+p!=;#yMtvX@Lr50H#QjnZ5jP(5Grqn-FC{(t1Nn|GgWXxhS=R>(oTpc%Le#qh{WK}}>m{S)D?@mAn#%}AxGUou zI}deEckg_U&xa2=i@^rvEw7vJkVnbgocM+8g^bKLn{!T!xNo%Vi%aIfbbch5vxdsK z5fzBNxsp!0<5d(mMpPR63x<6Am8$>#{Z|#i{QW4~gJ^c=8On{_@r;Hfo>t0o&F^2s>#(s zp(R?J4-;rVQNOka;#@CMuq&Yo0osMA)36IA5nb~~P{eU;C^Lcd`-|v>PxxL%rhsD7?z*0qB9s)%r+Y{)~ zloElCy{oyLrg=%Ee8mK(oG3ns8q|{|g?2c1QB|Is6OV{LGY*ORUaG`#NLk8!qPyd6 z{mEd_T_17Dsmd+-db4%R`!5BSj{@MYd~Hw+o|oj?{t5hCNn5yJk;f>4`5H_`=g($o z2p<3U`ljFkM2{;4(9*dgN(sYsy0UEn{q(O-@8)eejrrPR+IftEOl~Q2b=INc!16ZY z2dVc*TF)4ZvK_NjM%FAsiBh#GN-80eRrUYO5-bd({;kE#e4eqqsz`zm3rQ6%fsq>` zy5-j?6`x}|;!4bi)s{xBw3iNlU45#B+#BbPVB4LE%zO$R2>g(ep*MoTNF}Fw6=%|9 zfGz7%G;7S!>pcOvV^PY+SN!y*tn|I#r@|t-@aX&?<6zOvjZU~nya1%P*fw%R{X*3# zo3?z_tT%UaGHyXG(J^X7(AjKWLL@&8;v(WJ0$^_G`g1wwdY;UGz>v3`I1AbE&K6g0 zHNw(XZ+LV3FTqIfVo{V>cU_-PRH&=jC;hwO6Jv1W(^RJG{K@ym-EUh^6c63eI0fO~ zXq+weN;HIEz`hfm+-VCjS-BOl<-j3I9`I0f*(y1 z<<+*1S9`9*3L8+oiC=kEj3j{1gmrUfV0%q;W{{jsjDFIj@6D2>@eqaVH=1kgse#d9 z`UJnGUX6UbwG#f(YjwC#;Mv0z$QmpTJ}(D2pT$%V_4Z1%6j+&3Nh*|{wtK|xYUqU0 zjM>}#EDG8W*<&zKA5=t32kYx3M4g1HHNIUr3~~Srou~Xs6xeuCzQKv0Jw(d%iiJEHePd%lubbsu=Om0Me z6?40CF5tGbv2BnF#Oa&#l2at_<-Xdxz2i}ibaar7;Y3wqC8HNpRVU4(*iUR?f2%Nq z?XBS;$cfM~lMU;lwQZYjZ1x>wMcejAYKX}?2br|%48ea&@qq-uq+M?A!65eS`~|DBECtFEo}6dAmbsi78Q+f+EMoRZ;Y<2ozfU0DhV+5gk=q!VkSK zGK<*4PbkwuNAD%H#IyC=&`p=VP+=>h)`;M6$caj@6q1|_`t?j&!%*iPjJ-SPVgLv5 zQSM<=Y|RJsHETVW(jvP)oQXu!1EusGW*0{$q3^oVMOZr;kHiu^-)3dVR&?Et;Iqxt z8dttm4*CecdxeXfY0vEVBQglcYcz3rUHgf3E~qH=Rc^gi*Csd+(dkV>z2)GOQVrij zd1gxHk3m?DKG3y=^aku_RER45uBfXvnVL;yeK&E)+GshI5DHn*@D646NdV8nRe{vD z8XXEhJg^%vjeNE~DZ6q`mBx7sWZ^^n-g^51!m-hY8b(HR@)H^X;%rQ z8&U^_XJ&v5iHYGIEgmfrQ`_+<#WmnA0BlZKZ==!I?K7X&zgN#6IIIvmS_b6T!{R`~ z;AZU~>eL&ZIJddp z22-mf)pSWL7TbnJ?~l&xy<5nPKTM;b9NAZqb1LKOcuiPr9r0!U2#FpWFmkwIyrJpO!Vs=o@k??^KC2 zKRLm-{D~BIZM|qDXw0v2A%mXt@gKW<1s74}aD%Z=G_Wa=qCGuD82RkVM)U0ztK;D3 zSD|qGw}?~;g#XJGBw(16HDH`u4Z7q!3cJ}Tw>8Z0;2fw1y5W9|%vZ!6-S`X{tG(T#?%Fa(TqG==n z%9e^He_~A=ngrgtLY-o1vQ|%>;!xmucKq_;Ko%9F%lsn|Rm1fiVkYk>u@~$YK0vzVlWU!Dt+RTm_$uMvO;4by!`*uvy^397%b`4ytxYLTLLB_Vppv z{hP9afZjc`G!LqJGOw5if^gKTD9L=4urx8KAHpSF&0Tf~A;hr48KfApp8uJXSEbZ| zkU<>5Mv`)OuL+3GcH|H8AHhjxPU{Tn2F3(J9I*2#VG=nAI zYWIo|)79JDQ3p9({G`zlZZX6%cwUe4@q$)SQ>RYXgOq|sd5VetyZ3ksiuLHB9_-^= zc$ew}95hwFy|nWEGMCl*8V_phZXS}PH)$hU1LLh5XUsC5DBEma(h%s4i>Bl-Gz~K9 z3-{iPdObpzk9v4|yKJgq;&{TwKns{R32Tr00}Pg``=b^}@ejwMsRL(0WhY6Qd zNQTXJ5^2If(?OXZD@*?imdUwd4twcdv%fRfZd0$>j|KWe{)_Vj zm8&*@7N@-Ii`?%6l+J#E2tVv7YN*Ix&A^{lU0H2+XS9~s0FOdDV334A*ZqG zj_rAVOx+TUH?N?;4Eg#fA55)E=`%ttz#2eYI%uooOHh#K$Bz2uQiA$UQN4#A)WS?j z;4spp{Nq*%G`QSryA(la9#x@;&Mp|rPr7IX>iT7?4uG`9f;C088%h{*1M!-7R^yPq zvSGcuB2ge)bAX$MxHzVlS`nI1m#}6q)-=TKJ$)3j`p2E7^vMT(I$hR9xmkGP|K7F# z?~E+9KES0HlVO8Bn2oJh0!oYS!YLJPDP(B+3twbODdD7oPE7KmPRU}@hNPHc@lWR{ zXh4M^R_5XL^o)cwcl{WB`4o{4w>!omu-mAdW@ck|aK*278YK_B{108(aZPlDI=3=7 zdZ_hd+Af+jF!P(Z#$Fuc% zn*6>DIX$K?&K`2+j%BQh{ibgbiOzUG2H9AhSuSzDgqNzLKHr9-DA!rQjWn6#b+|E6 z%s7PgUb8GkKb%`1zl@K7Rf}9Q{ktRT`4%3PeeY!j_nG`p)pp@Y1v>zkJ~~9sa>Iim&;bX# z6{Ks~3PM(x{_gnYj79B&alknVnInt zQrI>EyUq~#b8%TGaLDk5gsmYY zNuX(RAlVelJ$*E(4bmlfg;}{M*<5jy7`rBlsCkXNf*duTZFow$;6Ve8K>0~$+Q|VN zUAB|HHrA=N?+ZjHr~rCQ_FMH#miHvAvNvy@nfIt`^Q!jP$v?qEZ6EOt-ix!=)Et6_ zKrH*AYb_^=rMnd?dN&68hkXn15C4}$ts%VNtPDm~{A1j@iNE=dUzCPEU8(%gY#>dA ze<*>5x=!0F?sDobvdHG_N5fk_(;DK|3ZR^24zQiEj zl?+0{7Dxqen9(Ns8h-z5soHzU3Ne<-nw}iN{vuZU5S!4Wum53mwB~h<(WHADp_XYtyDtV~4+@NwYp; z5Pp6X>$hMU743d7jAU?#ZA$B$+jY>z6_r@(h8=AR!WV%A+CF4kKj4UYIOCA8w}d9% zE#%ERZ_a?JJqF#D_DzSSsQS^9c_H}v&BN>Fl6A#W8_$v@9cCF;TmBY#a9&r7;S3pX z{oA2VHWw?<+qZPsmE4Ee;xWL#p2Q3(KuBW$8ZP^`oUc;btlav}4QyyEJ#1|8Cb+<< z>dR!yf`y{IJpV#%n;7}yb#!k}IBGfTRM`FRg{GaF(uLj2GR=aAnwinWkAc;Ha)&p! zl#;)UIL38$^4E;${ml!N;O<F>GpFl^O1zVk?X+qs?EHp1n8w z5d!}yJL0{S;#EmrGckXQ@%=<3+Hzll`>)jaxkiUo*s~SGVzNHDLp!UbA}&dH#9@RS zLk)838a%XVHAsErpTD@woJhN8Ypi4MZp#t2CvI`Y*9tUYJoa2<5~gLSF?>9^BP(-d z51o56iZpxK^fBJPrp%`2oDge7{qbY8a2TeHySqCeE_MzB8=Bm$qTrzN|MDw=-@UbU zOC)lE$#OAZT?CHKgNBYS90C?c_;9`^7xW=*()ny7GTnGO<>p-HIBhapUFFc8`n6=S z#d&I3)+SciV?e9F^XJnhA+z*&k5bQg{XO04J{6bFd?drleP{-Lp{Nl5!XsmyvRFz_ z?;IvtJaxIwU)KMr;k(8U77%JrPdIR4I#I^xv2>oIbpv{A__es?AJp7~8!D(X!Tu!S zj&%F8mu$H9Fc;x5bY?*54+-lR(tIfMJW1iL`P*ZcE;Oyxsc;h6n9H&gaht*GZEx8 z<#S1VD-SupK{QCm1k*8W^pioH3pk=GLmVuA+|pB(53H_JwH^z<9suwY=-QEWN;d1i z-iV8fOJ{zG*H*UFtkzvJJ-y<&Yo}d1H^E{s#ktsX!e4R{VXY!AQN7@FyP2A)w!P7V zhJ(wMxpWmb({_x^lS<^3N@8NUI{>yzKTuEv{Qi~n<&s_b6;a`ctd5Snt+ox0O15xH zEa=?Pv?21{a9;c5;tr6lw*cvC(ayyVu5bnaE7r{rJ6i5+m^?y+^F3d@rYnn=(*B|c z48BLKg!;JU$&DNBHXQg)M>G`t8@6uvu^0CS78#mCh##tlY4(SI zsS77zTx*Ol&qEpXhk8e^V2qN`S0-a1%ohdznj1k^1I+c|#NGhQynkqVh#8ZUr}K=2 zk-ZKf=dRKBr&2WpQN|OVkq}__!~fr7evvQJ-~Vo}>xQBS_GI$P+qikH4qg2vQFILC z2ZweQcA|o@lW=v9TSrWW&*(-sq4Wz)CI)vJV$F7%juFOSM#?kP4(fD}iN3J}? z=&Urp{c<70?;?7=E4WZNY*8}%wI3ShScV^V3-1V7%|yDtG~K@H=t-G1QGS%)nzmu+ zUN8!%wkp2wlY#92BW0R(5OvFqN=He9^o+Nt-z-1Pef%Qur@F|rsw27Nl^j;_z~5BA z&j`e4b5h&E$EtWhS|Iq>n6^iPpU2gp&zxme$~Z4u{V^$)-&y%6o_OR{M)=i^V?-|3 z^@1xh;l4&(vh_8m-tq^bB~R?0(23851?$vfKs=x5O4oFGo;d&OP;&C1jrieS@LQ(v z4Nl-isw~WaE#c z4h3hG1%-j$Z5T`0=``>@rA0069II+{@o396PT08zL%CPS4;CB}!;9CQ4-+o6)cmcr zTX9uVw2Cg^{8tk-j_YXtSx1p@If9Jp%WKcUW z?~8uWmiD`|-_DxV=E2;>RY761*1%=FYjT?A+Ske)s1qtU>#xtt<+*5Bxb2KhG?U*g z2frY22J-dfDnEXMOEm=P$x$ng^FE598`?{adymS!>?0*8i$rC3RCr7EHBf?_$_9?EdO*xOs_ zWq*z0H;}H*1mP@g*#M7b!#D=2TD)l3R`}Z#CAhCwKBLVJFXP8HtBc3rs{g}5lPh-< zdadNTAO>bibyq(JB%<{y@ z7n^gjAHGt`DWxNz^z%w_(PN4>5mdZtF;}g@oLwTqo?vpc>RhzOW|Q%aCS20DV$|`R zvXE1?VkeYI321{>S2`H4)99J%zm!@VXpgdodA8R3g)`+@kuWzF{EkXzs|-eIHn6tE z9+4mn5#dcAb!wB-ZETFFTBzhbb@#JI zT4!a-&7Ie9_On)G?)gy2WwOcdxP?<7qg0}Lk(6~BSG z1y=B~la)jmz`D|>sA)hKs`bAqy+dBzgqJ>zKq4<9$e*%C%Q*<9s-|m66-)Ps&$rJ# z=F*)k^J}X;GJ$c%dlg;mzmV-P(PwV=Dxzc=vN9 z%LcUlo2aW)C-)Tl5@7KpNINIyM%61UcBcf+O%8&Zx0H0(eWCQVWjrW1RePI&7I?E# z2dhl-n;SS&f={J6i{B-}VE2ln!2csrNCk>nQU8e#0#9COvR0;Cm%r@(w2FzkQVd9! z7*$I14~Gj|Xn23PfehhB+11J)#fc95IYIBYo8-&V#G?eTB1^382{#vKjlmXOVY2XxO4ynlIff zfoB{l;F-Jf8B7a8qOA&?bDi4j74;Y?WoLv5ockrDtQhEFJLZalSdB@B0_2lKtTM-m2MjRg%kUAI`lj)s&B6?_I8O=r z!ELLBY`9H%QCRpUyFhyAW;-W@(LLnN-x)lP5Wp5q5hN!j3cZ1VLves?ecnx~qCt+1 zq97%WrERJfYls?b2bGy{IX=#lqO;0;d-g?s35Jg8?!I-TjX*gdk=YGe)73^mt=$<&CwHUj zbk|gg@|OJjg;XV*i_>3{w+HGRf_@k8+oFHk+~_Pdl`rNrOy z!GJMKt;X}fn5+exg4K(?(Z-s}cYdNZZ9M+P<}U6G6{>BkOt_6FXX9S{PB|sncA6Y{ zUd_#-(Te)71fN$3{Q4X8lU5|d0g`Up%+F7Ik*5j9nm!=p7Ivq#ux7D>Pxo~JU&@uB zRspVdv_3xqgth^zg$Cu5VhNdnsn=Ao8Kk{Ax+<}N_M1!D3p zsCQH8$9+ezxtFCG*MJKj+w1Vovjb@3^03I+sHl>a%RZ~Gk;|ltXLNUynA&WiZ9&nS zTYNpw*Jsk7=G?oxCZ4>BOCGLOr-@R7cfaE*b+%-R&4D--G>&Ek2#73R6kcxKPGx zR<@`2B93@o_WW==o`G1;%+_u%OB@f|mpkm*j>s|jMHFu0BRHfq0i9Q>NFFQAojzE zu`oQoq(zx!X-n9@<`{YQRQmlPR|e;n%L*Pp?xR0AhKT(3yZn2QDJGo5hR3n^hVFi8 zM(Wsx-`$BFA5#~M=2WT)03-N&L@#`@pT>56JY4qplc6LCmUCbqC^A?oHL<;o`y~Ly z$Ty|H<3eTB`oBmgML;Lw8cxd~s=Jj_smdt|h6Z5GYw2yG6{hf03FT)Z_<6{T1ccU0)_@p(@eP`B z-gzRDdY+Jb-{GOnY z02|XAt@;@Z_V{u`=5oAPy-v=-0e-4TDHw~zoL2w>E(2zL$m*Abgv72NT=GuU$W<_9 z9FcD5rc|lArqG*P9#VG$f%VZ|1>fOk60@BM%o%fw{1`49SYS}EMsS_A1uNE;$UhD* z?9b~vhR!uB|Dn;^$S%SS=z3^eK7XeD!vfRSEo+@&2$g@!y`feJ@8;S&1?76LL~G%u zt<>(&NEYF|{2f|Vg~y6{j_2W<=>z*RQzbt2n(1lE>MTI75$Gs_8ASz~oZ5YuKhY!h zlj=uQ(#dP_dK*q~GO`P-eyC|8FswT#==NMx{3(^3e`*m!3aLl8IL>g93uj}nWEXv~ zQp1DLeit6N-;u~*X~UTNrC>b+;2i?d%#eCXGw2|LJ@^X{ru_H9ZARFHUpPGifZYb@ zb$Y}9u6C9+I%gCVBp@Rr7f7eV2qMF}Z?aua>RdfPqAa0TZ0Frw#0g0J*prvF>C|~i zPpT_i=>ycxRx$3)=tINs?)e7Y9**|Jc>3&*u5m|oN8dK$=1#*!2RFneH;Ia8BGpoi z_sQzdCAQDbuVfp|rmg<3^7$82*F?wZapCAn!C92}|5C{%iS>Orzgn{#=?~V{pZ>yE zeoDSvm`xL{LBWH@tFU(J^Jx5^Iu`i1d~-X0{UJx;=p#fBkv;3B5dE5O)}iI5S;d^% zdM7rFcH*Ai$`ev%dDNU$@FLVNSHvDC(mm_FEQZ`bR&Ap3fye8gf%y5Bf|LCFzp)!) z#q)%@#K@oKmDh$91&P*Xwv+#Cnn3Drs4+hpFU*ZcsB$=+7bsq2BM~LGnQzK)R48hy zI&<1RVdb}ZdFBwYIL+?;7SS3MY=LJeZ%MnLo7U{0Lqi8+$2%IznweW=YjE}0>Jd-m zUnp}yy)IA6#<5y-3+(21cbWKZBaapvs_IMJ0g_$z*aG*yibE;Qck_RokLGM2BJK39 z6m7Upn!R8>+SHgVWSRW@*vO&$q8r&7Bzl9yhzbW`0=J_4krn{`f9?#AEM-Xv|1fmd zKROx&@M{5XkF&!p^6Pc>{7cWiHzDp4;DqxNKv!LlC#N&KhTihrLK&iYv*l7-z2IQ< zyopnz`6`R5DlIMSbdxk<$3Jp0%?DZUo^6K zYQSDOfxUt{4a!rn|9z@L741KJid}C*i%{#*kTK5rBxDX;0E<0nr zZ2nV~QMJIyA7z=qiRnrmNwBsDfFGa9H}$ES{w1{l`meDC0sl!4MZe;HM&_YN1g5k3#eG^oHbQ2z z=8S25VxBZVIZQH?9TXPN?K+U+C`Apri9qjZ4uI88mv_FeRj@@X<%5cenasL4o?@10 z+?%+FNl<4@G-uqIWuShgXA$df_lj}BK%wa2JAzVQdGUHGubHb}IkmVST@6=xA5qbY zP<0pWHI7D)HMM(33k{S?XM{L8EhzA^=BdJ-&;;+`Kd6)PtjIfG$0=-X89pG@9tY>f zz{b+sZ`+HZqMICHT0SgSl0vejw;#QcJKx>~Ic!f|$QkXiKe#%UU0`?*D?~s#;a}@f zRHX3GbG4scr}tx7mK@XPMf8qNaI)4xaZAkiAiXVD+ zYq<)3v?r`w#%ghM4R*Le=+!gXG+_eFz|+J$gEbuj)+r`j+@!-AuX+W8zOLTOO1Gl7 zoa*AjIY$5soRgpUfK#=BGG9R_FJom!pR3VioC+UiJ@WiFnM1q|2Xct@hkw@_1yWKi zPBO4i+}_|e!Z;|jnoyt<%8g}!aP};rCEW0Q2T^i~V|IjJ|3%fsNBYtJW%nqDQgq9P z#)P#wl202~J{lRp9w8Tdp+L+@;?i%#+mi}W^@rHcpXstiDqVP?8F}#qBy=h}#J8(S z;1I)-Iax%xp3G*dOhSGe$N6SyH0RLIH+?Z0L|w2#$rpBZN*p_&o2LcZ&uX}LJ1H=N{A*8G7Xaq)L!A6sH_zq>9au@Dv} z@w~^MYp~z%{(v7wrqb@?S3x26zwwn5>*~ z449bl@ydAObN>;bz?4}=7Y6Jp;{Qt#e*pt#K`1;iaUBTXZ$KG3?VxfD<3?wND0SOk zq&@iR76k9Ye^1QMOmP_}|9(85e9)a*#=~b~0e!%E8-AHr3wo}@YUe`YB6q$0l|f3o z^f%4k%%8l#hpdAdmxDe(DAzxlcoxp;b9I_dh4^sJqugh@w4CN&|1ECd2m>u3yg)GS zYhMJI8vI=>Yk$%Dc+MZOq1Nr6@fdX*gcnpqbqs)(5a@(E0x8q^=?uq0B_2j7c#VIq zbNX3v3?LIF92S#RiR|0iR&Dh=zeB!uHL#H~$xMa7p84MjX@OZV`YnLy&Xd;=eEF6n zd3hcT@>M~5WkLL^T}VPXbb#Sic7zC>=deUbDw||qUw!qPc9T}VytoAID>~G ztRIBRG2Y{=D5fZ5Eza!C?xXsjyPjN``e=?iOF-JomZhkDbK-*!olliSarec=e)p=) zk7x|0aQ-MmG$)h(zOzk_I|R+&0Q~KAo{+xYCgne(0R$B0xj^yjT(iB>R+UgYG&uFn zA;mut!^qpY7v319WFjj~ioLQ{7WYnV8}G?cRNf6Zo`=acmem|83zfX@F5+XPE@g{Z z$b1W`LfHPKEdOz`4Q+O|ejw52!5!x@*Aoz)&#;>ozV)gl{8tn*z`#B=KYr3(5r#KJQu^B)>ctOMj`4m4-DfG6a`V{`udn#C|}P>jw-kJ~g~cbF0TRlixW8&*f%VuY_zo(9=%NxPOr* z%Tm&4={@S$G(R9Ge}|dM&_J0YnEf*MwXwnm4rR1hhXz&2s3YqZXxX-jBWUm>!0K9-KFGK&eJ(#Y5vEf98fr?&u%cE7`_Msf!@o^M%V6@{su& zPrq!WG8mVzH3VHG4i$nQJ#*R8cnDe0R>RnSs*Dbkoa(>;*~d{4MA1Iu%Vj_-=M z7dbzO-NjW0YQ1tx#$-5p-#yQn2>^R<0FxrB9{gQodw@hmiyzCt3{>lDX)zrO5-Xsb z^kmc31*Xi^Pj{S$qSQRYjFYw9R85Q~D||IFE;2+mws7QgKdobMek}5+AzG7oJ&vR? zB+qIxFvK;tSSaY)8hBJ%%@EO>d}bugqkNmmAR{QBeal@oC3X(+ih^jMc4Cp(#L}X- zkO(Twtl$q9lS{pJzDf~XG?zNF2*YSgW@|qxUfEt!w2uM^PXNi$MTVv2tnkO(X2(S% zu%hueQhNifAgYZ!kPnRejp;N2NPN49n^&seF$-P`B~*kUg<7c7|K;E;bnI0e#P-|+ z;tZm@ylxp<6N8nkcbMWag85$jLe}l@vBvX~Y5kQuv#fx3P%C|1kvd-R_BS+*249aD z{bdl%@t3h>s~Gc3E`F9f<)2>`VCXJ41i^Yp4VkPP#lcEQPqma~yrAPyWV{yeO&`Kw zZ*MD#+FQ#dAnh%!+Wf&R5g^~ZBHxN65b}PzAI-4JyE--S;E=Dg^THfZ33Gii8ub3A z50p;d=2wk_g1udF%ZluvDsEwl+bgg_VDaTB=nFkaDv4sbykWl8dx}6%VOC}#b$$f? z4a(L*EtM6+P`cC1F*jl^{Syq*e>f`<_}&Mws7ZTr{7~qZJcEzIDMMXws5L5J!Q`fr$xc zh=OT^knje+v0#Qg;EIq?UzQUKDNVjnXiIZs`waK>8uH}{+MOW(uKE_beno=Xz6$EL z1BbkS5t>Mk@xHDGjLkbM!T1=F$?Ha*)_mqBjB|C%a92h9DC15?lkJ;VBAV&VZ$CVV zX7_$0J&Z&dv6fl&!AFVLz?$e2c?>b95AO>J7F7Z_E#eBeTjNV;BzXU~(Fg%ffO^AE z=C4>Y;ibr`7Fn`nceWT$SL{ipU}6L-`1eMKb3%Rau{u|g3?Vi{QLcCXUTkcjvBK_& z*U;69rr7qRDR?GGngFcB1mvVXPLm)0d;l~OMku2)^+LW*V<~Ib@Lw;TthYBFVr2zC z&J-MX1<2aKg|;(q{@O-;cH97YPL5DQKaT{6B9yBFpP-PB-DS?TKc%@-l-O6eORhs^tWx@dGue@35n`=;qFY;G~ zA~^f31oa}i-wFSORUlw-&l6{$$e6rBf;T9Cy=7wcUks;sNf_DgV(gHS$%*?DW@Q#n zW-9N$rx*Va{w0w`#6U=?zqx_*)kHwM!8ATD{G&l!65G~5`8HXWcpt5GB}zVW`?m}Q z8|+gZYB(NMSN!*hit;14NCIn_HE^G_U|%2*Z@Uw?a!Zml4-VZZ{54R@0mq`Y+OW4H zWc1JdGqgQCX0%@r1(ls58bC@gDHS;V)WJ?R@v(lQbIK@9X-_KMJztX9y9?kk32*p* zi2r2*5NlPxsTx2l)+FTgZ?^*`Z++U6H5b<5vW>vv$q1-tN95{O;Cyb`sJ_4 ztxpw^hMl#P%CuiLO?+0$szwg>X2y5#^!L6$RdNUvx={^UUANs6hHJSh+!$3McbI2> zS%bV$jVm;~fW=H<>w!`P#xmq!S>k75?&C)JTBfmDfxhQdMRdmOD zQFA}vf3c?y`7CAdcvR0h)cd+3YU&yp{&D~no4HKvmraIkJYne+IX%haOxE$*2NGTQ z!K2faAYidbKj|p43$q-9Xd(@K{U-AYM+D_`JTC%QoO6qpm-q_=)G0K@decVtlswB& zD0{=_KljX{u<3<7CwSoVyleL6@9!u0pzb<-2uB7?$S6hn-QAR(4dCaj_pEg=Iqw?P zj$B$4CA}XF7@?et3sM?I6lFgVDF;xdc9AKu%Pf&o%9ppl(H5!b<;E3RO>l&)07n4D zc{eL?*$hCU+f_TIhWS^&q0?h)gbqL5*W*`=Zl4wEkBKY9V;OmNKS0u&TExQt$PPG2 z4Q6p^Qw5g*E*^OcRwZhmHeQU(;0z5XUcHQlb_(dZIgqY>g5UX~F;Wo>7~3S`!yVw# zs?b2RQ8F0F*P-wcuZuRiKaDuBlR({n7hRk&R;>sn)e*X?0Fu?kME&p;ScFNF}?AOWhaA*8XvX# zlkbkJcdh+zwA0MD#8ki`>rp^!(R5ruF==|hk3O%2d*_HQorr^!=hNoe5OJm9{ph<<`{Q9UX8b?Rx2K18ALgK^2 zN%8S3J^%C73s?Y#SP>hI8}cO>biRV!b_c(Y586w8S6aTzz)mL;8s4%n*QNQrynalZ zn^3t-x%lC_SY!USH3`I!gQ%9&R?+oLpSz_(QwgEAS%U=ryt8J5VtKY)A2I`ann8oh zqI?bjZnj!cEar4_DQ&KgD>&pJ8$=_BqAy>KBMC650_Ph@&N@O7F%OS zU?aVZ9aNPuxbyvD1Oz zH-RQ~zgafs4Cxg(81>T+YL_) z&yQRK4|1_MQOxAEh>pc+HUsC@AIH zYILD=;e_<9qSHQ${|Q!%LM11pMk#_)dOOKdl;v|(BtbyhlH*F7ks<3u_}R>_J8sc@ zm`1<4V$+hkqyZ^S$TPUO{-=0vOQ&>ga7C=p-wqc9QZXHf>!K0p^j8lQdN$COTTmC8 zs%^&38}K+tsv`Z)C~=5|iV9o_dv7Ykdc9tz->~6%0Tp}XqY0MkOIz*=BMELXN@l8n z*%sIlzs}X8#(b;#2XcEPG5xEcO$KmCRdJnH0FzXGXbCr~x68}RVi-TYuLC4GP{bg}QK{sYE!8U&pCbu)h{KAUX>gd9!a zHMFeRfv{%7{RICS)~iK-O-%S6+R=U?@c3@~|6z3g3Ym9=Ta>@riMM#rL$fjdy_MRCAc6XQyegt;UbN)ea`@1x8%h&axA6mcHV+aI2(>u2Q8ivq znw{AoX$bQ*5~#mhs?&(8n-0>p@naX?2^x!06!%CFs*Rv_j{9DfxTV+bC6e`1oF5-x zV<~4e)tEnpnX1rYycv47*|5k8*cON;N^_vOFFfXoBlQf|jFB`+r2Js^3o_FHI|w|1 zvIF~M7}*92HpS-qwTpPK_ZR~zvM(J)|C@i_a4FB+&My(j&jw;95d@rA_mn{Q5P{wcAXdANu$-wE5JYkiDT2`vqQHzJ_%*%51~ovIh8QTZF27eS12J7ftT`?lf#$* zHZ~S^0AXCs#yy>t19*lw@>0teyEf3acvGV|fEw^ z3O;RtLMbc~6NIEbU11Lg23|r)Z{)q>+?nR6x2J8brFgV*o`O0Rd@{?(UfP zoWbk|4emE_)g$=p2<_$@`PNJGh?ZIbbKM%|b?z@SJwN_1vBT{XxFBHy@?&2YAVyUUa$=rchpBE zUP?v*I#kE1SrQZo4Q<%SgSR`l%O8e6y{8GD!pq@;p4Q!~1t&19t9IxcP}J{M`rxsE zjt9waiq{q=MHMe&-zzKnZ@G9R8Hwc29mqWNb(5Q_uOW_0iW2a|bD78NJX&_NxO}0c zwegZLK@d27G*EShYHnQq?^7W}N{M(J7}>gKR2en(>dtqig|5^V$hf|{ywLk=qw`-U zvK9oXnC5Ykdr-sbVmmDh;}3QFm84A6kFZo+l6wAR4Q_>+$v+ccb|X$Ix5u7MH!>P} zlb+E$eZ=}lJgeeMoL=mJT{uISZG{8sWY!($W-<_j%iX$TVV5eq$cn4$4EJhITsqF1 zsherjl`#RApvh|55yXnoWB(@e^%Z`iiBUc`@ z>+RlG1{D%aOy<8Nqmnz&RKk*Bsc@_ySz{ms%^OSF#}F_FKUnYD3=aMSS))T=N!PLBJHI zm+moDq!w<{I{H!pK#55ry7aHNuSm7J$IgRC#s`O6^CuVTMShFKJJ@~tOWgaU^b|$M zK|WtnjKy#YhyWN=Dg;drd`T9fdcWX@V2w$2J^&cu4MKw#vYU;QAQ`NC`zrvvw%*WV z!+Qus5)Wmj*1rA}U6OF0B>k;gmhHxcT$b@vSW_O!rFK0usrHxKj2BE50`vx6_1*fY6fNchsoG z<-Wd1`wbHXd*cO$0PKv6MnE*)_PO;U?aOZ>AMpU(Q zco^pv2(Lwu12Ha|>B_t1-9PNnUT#lD;KAU(I8F_|4_ZSH_wV=N0}0rIBY$LML96yp zbTDm!=i5J%zgH~&ac@FE4_;?Ap;BxJ%AZ{IC`T5=|2 zLr=o}<4pyrYjL?-pzzvORZ&~?=0idMqd>)29xpSXts~RY-bnlQxp0onLLD%mE&Fm? zyUH}~VcW|h)z77K9cK0DnBK405z<#HOvaj?4~S;d2_Fi{Hbz7C?!Vcrq(7hDRc1$dv#-kxo z<$8qreh>e{JONOBxXJsg@Elk54{#|5wc}wiEiZ47&19M2Cm|lTh)`gFfSBR9m}+YT*~N0`>%O0?d_MtpIB_9bw_jWByQvSy z3pF>_=Fl4M?`&v{KIJLl-}kFu9{79X{Am?~)a~miNR7)|juiXe_pQ9z?W0)lN&N$_&CLmm>b2 zypWS#O>J@?VpNcU?`yt)Oy2=zW7%HBX}0y>e33A*7@=)Dc8+x4}H16axV{Q2aUw*uX0*I*JLRQFkDTh{ig8uIM7>- zzYua)w?{Pd57(lDBOEP9?nd>39z)$9bYoi;vLodx; z9LKiSFq4_4bcg-vz-d$OC+PxldKvGQ|ED{MYPYDP6Va5;9}Ug1=#5V*@^Q_YT@wE@ zK3i*Yl)xCCsH)cc_3Dw>{B9cV2m!8vODK!c<_|(sF11`{`7AdJko@0f$LtHNc=a&_ zg(^yTi(Z>E>^>@O>K2=*Xdf0WA72!3pP6(7 znXyL39~uunw=34Zp}w!l+EZltQ$2J+Fo&vPi|nrzD7{_C=OkJ9icytu=BfRr7Nsndo%=G9r(*vyg(9uuGG zlofpb=#5jx^6jw8Mnu$abMgE6vMzxnR>xzy4z>4LBiG96;Rlgcq~Lqx&NM9p%nPwT z3V063yJl=)N`I!TbzTECB|)9BJ2emMyKmD9_`gYE%zg zB8R?On|9~s*vmJ+`M1W8+nj4j#*9n#PFpI}u2OW^O_jcW{d&@yp=!O0$uU~PgkK;Z z*PTb1DZ07rvHUs5Irpz>gZ31I}_6TPRo=oP6SMc z3J?#cC`Ujk>c)yJR3g8$>GAF}F1@2?NV!j*pc3uKEg}Zz3A*{O?lam&|9urDN;J_Zk6i%!%?-b0JVj;aw)32H%E?MCG87y_p zk0TeA;hdfQ>RbvSY*28-k-#fJ@0n`)@lq^vC66zh7)q{ zipLo-GY#;ciVJi4bE(E_)Q)eP@-J0MP8T*EV_oOdja?HH8=t2J1(ZM9xn@zxW3BN{ z)NW=fcl9Z*DBokhPWXW``-!lbhlMqvZzdPL>d#U|GdfiO5{Q(}N%~azoybajEzj*A zyR`tkEz)G35M&fQjGY@coi!i#`4p4ewU*H(_hd}yNC zL06vQla)nrG>3El$i>rdDW{Us*sYyBaD*I`2-Nl7#4Z*J$U663N~m$%vzyE1#Z z7Z&i}MyCR1!y%EV3QltFx5FakhD9H&{8-;s{G@Bj)dt+vsi1!~wa(=-EybkO!xOkR z+`f}A@|IEI=b8PAiT2q$;Ib7w3JPlc?g*utT2&&B1nuJX_$ltZ0=pOPs)16NT*&`6 z+W@PIvTTcRh(e3Tc%olnlwr|CW5YcmyQx$`z12vB>S}ruIYvOl-cT{q5j)LYM#Sn(MuE`ZGdCcOK$z{r!Kz9ZYrXw@6t|G5+1+r@l#I-*7>$WV_(ALr9RbT z#4FJ;IWhdLI!X8GPSGt8S0SCF|NYbo37mrxSumQ>m8RfL#1^k8<66b-JYP}P51 z^XHd6TIt@h=J>y7&2#`tfe0XwqkS#_l^>W^dl4BfGO|4q#<8w zygOQs6(kCMZQBNBwQXni*+e*+&!(`SrxXMiogb@>AH9a2qtxw&#CV!Y83?&Aq+jN4 zVxpG3e~2R&7I3}4UDt;^S{7p~3$7{2+^2!din%ISvPf!~Bp)w=ux}-1eqSy7g?Gm8 zi4gO-w|DE>=B<{@5R9Xp-&5lAj+i;*&-m19*F=)1piQ=enGQv+(`Aqff%a`vNuLP0x>D!LxhSk~4F;EWsi>YsBOZrnL`aKAe z18y{1sg&K8yN;Zrds&n8cw@5vs!ag6iO1m5d<2hF%snTbU3)ZbfDwL*0mLZm-GVvC z&xMd=CdbCz+^pNE7cD1AUcCLpdZ*+hXr&vA2?Eu53Qh;( zC7f%PXM4BGK)W%=T(fI@3eWz_kFWp!{c9fHcl3AO^^7uEi(13 zo3|XBTG;-e2C;NFBg6?o{tUk zxytKV#lvRAZ-_&y0SV0T#TztkU1Pa4Kg9DayBj;&>gSLzGYWBxp75(xS>rIGTkd`g z;mTEPE?I8guMZu<;eN9rUZ_|3F+7uB`cC+RoaJ!RPE{I3^6mWf(efGj(bBAb$l8m0 z757D*-R>u5NmC5+sM-FUzdxa8XoGrh?PhAL=h_zv-@h*O`nI1_Dq8x{l4V$DQoJfn65ZQLGr@0ReZQnMgmKL z`n8?*CYj|X?F9Mj=Rbv*K1)5ml!6lc0&5Be^x46EAKV8X7M;8o${+pdb+;oCFUp&K zq2v$FJnQa5>)%zhH&d|;NMXy*F`Y!>(><_2-nm2}>e51R|5(bNZF3ojxA{H#k%DN>cK ze11=2KLs&i*iHMX6Zw)_u(_YxU#{#zFhjk6Lb3y$d%vi-`c!6-$a#SOC>A{)-Qa9| z!$=&gThp2fiO;E9y+WK#tNfo7J zWE3VTd{;Zr_Tsu7dARZd(?#uBuYbq6_`6}?49G~7TtSWNBUQ|moaG0d&AXQL(idbLrCAo2NaTi zKnnI`p|O}5c2CUh-a;LF&|-F!d>lva{{4305Kr2rH~Or_sSj&C@h$wfTIf07n|yx8 zZ)YWyMfasXr+UE)`-Yqme_d7&&0Vrkc(mRE_dU#eg(2bfx8S}S2}x)w2>*Axg+KqT z;lx2QPN56L*6I`T*ic^~H^zj+Mtj`pLjOyYnt(Qeg9bUHigwE#r`g zh=k!pe`>4Ypne=e0{o{oVms*q-eo@Z7R4faS&Ip?_SSBlbO=UNl-FLGO7%^MxQln# zp1xWc@iwA#zMK}V7Q18N^zQYXYF*fSeLGZ)n(Kb*bBEa(liwV$cRKCtZ zL5)h)evCYo5H6HcQf66R)IOt|fd}_4gNw#IZftwJ>&urG)>ei;^wuuxL)2r}gpl;> zHx@%0&CitCPS5w6xAsk*g60YS94t%gA0?#66ih37<}Mos8uL!MbXp4#Tjz%WAWG{I z;o`nIF`XF2$hk(kOki&=zfeD?Mb*s(TE|yfxLe724k&e~lrAy9^GX2#*cX;ZBcAd` zUk(4RPMkW}WzcU~;cj%IHb}7Op(fOFQVMo2)h0^*JHh3(7ek%_b)Aes-A* z*XM%j7U$>#R>Spe0|5(|Ti_k;TudWB4>b-I+I6X6|yepxru)dboKglJB>V8$C*u2FWPO2IeFgHb@ zKrWR4q@?g_OGU&oL|H2ob6@!lGZ9v?-+omL_~j#Owww4)zjEngKUTzsmQpCu(O}ab z^%32i8NFr*WN(hAw%nG8AM)un3RsDNB#)wp;=LEu3<7k;;ypwE_3bKEmFT8x5hCwoMwO}xa!!+)k z_C`n8?*0?B3C~-QtroOHAwS@g>^?^Pw|qP)Slz%xt@Z0dBXCJ@9$Mx+{;#Pot~xZ; zn@2KD12GOSicZuSwL!ghVCJmX*^lh9s2AC@9+B7@2IjUH$Ez`xqRn&;C>CZeX294J0?#h$P4jlX^XF| zLvx6T-Xi=~`rh=J-tpUlXF}v=yVG$V=?O>lZ{Z=$0U;Q5TS0MvzIpwRp=w(64f5G1 z9@8n+GumxT)@e13Z1(A?zzlyXB?W>?Qz?sE+7)!f){jaqmcIob?K%i8=DsN;DKxyc z^D0Sky9j}PUB0yFD$AZ2No1j5iP>_DJ|^C2mo)KS$su@L*FUO<$qf%Dh>F%piN{@@ zRExOmTQlK%$!EX)T^;GTV?{1;$=*-qrkWIX7!p8VamuINw_9OcSL)mtrm?OfRMBS; zjX-HY(DOyS)S$MdDjx;ro5HYSD9@%yO&yvKKhEmT4e`c~M>00=?YERG z^yglr6%o}*J{5a!1UeG*xl;50qbuikEA(gjXLFI1LWF{Q9<}Ym2k7QiP&CuTn9u$0 zF_)I7k@6X{ZMU#;C5E@hlS~!wRdEGAy!>@_);d1azsomOyHiSfA7NkALOFt8t>oXH z-Abf{>OQEu|LL?&9=(}%@@SZj={iq zi(0hb?Y4r?x5pyrOLsT2Sjp3*C85TP3vrh#+vGn=dM_W8^%!nVkvu`{0Jwx1a4R|@ zE<1d15fM+s(QBqR(6Ou7elh9IDQEIwz>hPA9;*}E-Ffr|{qlC7zp>RhpvKH1^^M%_>2di+Omgzf>N||va>(i8dn0JQn zFuE+<>R;sjqk`BCgw8eQ%sh{fn9PA*Z|%s3#))Z&np~#gu9-K> zO`S=zbI2|b5B_q%&wepaeaxArgiv*qQJRAv^~5Xv`#a8pr`ss~)ovf4DMXr%KIheL z>Q#O-($%Bl^;k2eyYeCGQX^UY-5|hq%s*%$%Rs;Np%)0DHvHp znSIE$C`f%d&4ckwB!NoOY8w0E6Ue3SGsV}*6Jw%Ra9eXg2^PpqhoravFhHBV$^Ga& zyxRslZ?EloeDPU)Kg5de#%I(*M3JDMO>+9Z;~G9=pQ`)cKEjxxZ(ULg{>i1L#o0DD zq2brRu)+(qM5A17Wst(HzvmZ2zkA|3FIE`8II~B zE{@5n2`1duG7FsAc>PY{Vq#s@`>jPspIq`E7Oe!U%KqAm36p8>IHxIU``~FXs=#k{ z)oooP=k=po-}j?s{(8Z0@C@j5 zn;e1@5DPH32fwEb>hJJhF8#DIn^U1xm^29|jBIg}TBu%~QC67}2>GuQoqBI&`{}+! z;nFbMt2(Y)))i_{^=K;soT!riJ2dF50h9Q2yF}3UaA6L8YeQ4Vh{VksbG2WnCz3+V3w;%LAZlvB?a#*Hwy}Cy= z?&XqmUByQ7qhnWV90OwKTfdW0NI3_GdemFqv6D{Em$B?+GC!;3L!C91+4LXVZ~bI) zJO9#Z4z4ab_)ah~uZq6k>KYb1S=7-_!9Q%jnFBr8zHP@IZZg#A`d@;?WghL!60^7@ zX4LZ*_LGa8wo@eoi~>)oWv$O>6>_^W=4WJL1Cx;GrUpss*ZE=%7(^pRa0_Wuja?kgF)cA3auHy_@I zutNDV*r>3_*Xk|6oY9*gSo#;pQuVHe@$aWfm(B7)m zsk@0*d)IJ#C5*QXHgq!zTnNc~HX+c1wLMO122i6WMAlRdqTgq@Zng9r8Z&(Z6m{_HzgQkn9v7UYi8u$Vwcq8L>2*y5I zz3_mf8h#XF`26n$B_1m03xCT@cQ1eDAhlxQ#^KJ;>(+j4BT=ZGuEHVzmvf{TlP43tyd+U6^Gk=-LWWs!pfbAt&imR8v^KvL$v`mS{J(;and(hW__LL zQ|G#AZYMd|wa-c9(7++bv@6hsv;E?|TkugI{>hL$nt@IX7D(uKS9PNb_OMMcG4g%^ zG3X^q3lpc^gua0D=-%e^(qN~??OKWE{7@=y2^rkVd4Lzj7Y5^gFAQ7K3Z*l3te>LS zkP|UrFkeixp1w1Ya%iHCx;F2|J!pb@j?3r$ycp|s$oES(^Q==*t2#~wL!}d#O8ehU zVxfL(B8clmbq0SzAQ&W&0`LZY5ATinbMPUhbWbMi5Aq}96oN!U<|CR&O4%!PI~b47 zys72+5C%pc)7$1ig~(@{)qWEn#SKvEc0ywUi+3o#VE-QAh{*i5=3}6A>CguXn~>_w zBPT9J&GdUNm*F3uQFaf+11K?XE)+|AE*fv^kBy67+GA>GCk8=J(I01$vjZBXdNRI5 z9wuMe*}|%V()IZ-SQp!2RsrUJ|is3T7OALVMB3>qV$C^ z-K1c|3k56y)qBf)`6&;i5$=JG(^;kA#$}-G{mxYOms!2Ud9#dxB#&KC)2!^|i~LoM zw7KJo!R^46NalE89HMmMNg|X_%qTwBR93&(e`j9Y`hb8m6fnsxG>a4@1)o&h4w(Kq zdVsgG_z{FjgffNC_UK`mq*>Y4mkLQYIVVSMwD{;Wfw_FHNbzoTpG)H!pTpAI{j_5p z40ERmGkyWEb}D<%mh#BNj?nmV?!=Y={(qX>gVg1Sa4bm3l4d;v)y_Nd#-U#UC#6wl z?%;|e#|MtmmF@EodRuZj_g*oe#=55q1M@Rj316>Oz(B{ohO#X-gmz3N(A557r?G$3 zYLs+4>3C&`TJxHSkvoyT6TU}_?Vzys@Ysl%UDns-qNFrY3$nZ@uv_Vz-JUtv#JDZy zqX7W=ea^H0;X?*~iT(`1)(23c|t#e47fKvskqXv`kn_|lokv{O1nDu~ZN<0{mB z54vW>eR!`4`T>tQ?|jY#+!2mMF$)&YjYs4+^^|h7tRVh5;9^lb#ZypSgQ(N3d+eHS zV%R_B^iz-E^eBNXwmEv5O5KMmAr#n&j4;{3%K>4=yQ*DwW^SF6A1o6~XF!%Eo%W41o6!ds}>c&Z^?40qhq0Ix$73|qSt;!^PeP+fOHd+Z^Y%jf}48-uTgc&w1$L;Rm!BHt;AOi zd**8mM0|Ch{C;#B~uO+Z`|snhKNPiy(er{bpNre@ObolM{EfH2uz?d}sXlX!a5 zDHy|qPV4o8dh3lf;^B8}zko~*hM1#=3dzLRq|ZcOT|WB5n9E=r_&^TGT`#Hs5k*0a z=~FRNsKrxSbn_Z$ChU9fMHCI5eVz9)jq~vnb7>_&<)uJ|=ihs7IA}^Y1yl2eisbK; ztI!1ij2xbuBK?el3$Yn`4J8G``$PBXUrfHCWT!4m5>z6n+1cfC=kN2S^NV;4%Za3O z-sn>}BvbfUwm=7dtgoy;a8E|oaIm@&IGAK>f&{S;#A?cTJUP|Hii8_kad8ZQl!M3j zx;u|Nxm?6CdgaH}{3xw)oUn_$uD()v-l@ zj=pgW%s*59O6=_x?^#X%dzBq+BhYbS%FI7Jb)yH^S~1bfXM%7b62SJ$`4^M7)RRF9 ztxk(HT$E8ov!F-37eAQ(EPkE7T#c~W^i48pD`7kZ#SuyM08CN|hr5lDUeUZ=GkDr@fiG~A*i#ebTr5%7C4O9TxG+mici{%y1{ zBU1=6pn7ZsfdYgnUim!sws$!dp;iJ%fOq-!#}&m*_AH^F8!B8w_ThbB^wcb5a;Tly zK=(}aw^Hf-X72WvzF-xd{}>=YCUK;2(+qbk1n`6Ei|42A@{g8blu?E%YcNS#qkm8o z&o3A+v>BAaCfEEpJb*(Yyj=1OyV^T^6QXowf&T;?j-v+SwP2^R3%Rqq!_Pr75LZnet(xtiKf0_w*<(A%_bi67m8OfK%&-vAq$VEgBgVLtF+(w|mNN zbXFQynUHlIcfhIbtfbNz{}ysAG(Y_$#Cgyy3H@Hgg?g|^hUmG_dKZUA`1ds7dvTO{p5tIs$QGTjVK{?b3{aYSlcwfFv;Dbg6u zL1KVPhlp89`m{)JA5^4Bv0!Ao-*Cpf6`hXpm&J*7NMt29Uc^2wa|bwQR%Iw`bCYE; zBTyOU&0p*I-m5i_gWDEv0II^FDT59w(zVCRFm{FO6aD(at_O#t00dGkf{ItWIRJ_{n>6_^ zI|YqG5j7!aTG$P*jMRht7+XDjcW-d1qHCbtyTlfU5cP?HKEfk~$vkt?x_>Fa10lFm z*^769BEGx_f>A_4aQ6cZnas~-Y=tET*g z)AJnsxgX0~=;gq4+THEoQ@u`jAQ+DGE0^817qeRAT&_a+m{WvE85=H%$o_aql^ba{ zN5OMptrnkNX;d2oh~YYw+^;l8fr|B}>Ll}xRoze_UX#ieV7rcv0+_U;S;OJm9BmJj zh4=F2$3BpN1C$06uq2RXNy6SiN+RoDjmdB%Zk!)K6hSGIU(`sGY>E_MJ5+H?>Gg6_ zc4du^1T~$+u!GI(pgscT*cQVZ&}*nIXrDufW5z$CcEW#n_cG^F5fupb;6(3~3nX`# zt~p0_h0*7}?IdDd-NsPtkyv;Rx+1PLy~wt#0cQPNy*l4%gO@Q(J^+Z$^EO1B?^ zi@52b@*}Sr;l$m2SU^P;E0f;*Aa`ku`hOJaA`W25?_BEybl^%36iA&F z5zLHf7ui?O=?I8V^DvtO5m&$@K+P-`hp2SudOEL1ABwz^*WBiLuLIBp!mJVxhbtan zD+I13O4u_YukU?tI7e+N2-h1S-X+d>U_hL}MepqG-(`o02ccFd&#+=9BvnH0ek-HB z8rm>@<;sNi|J%{5ezYyFkCvEhv5G-%SuSCl9rvXL{uls^HeFBshJev>uguol^pdMj zT6kn9lO}7|0Apz=E;hT*vs9DjvbB2EU5&Z|IIY%J>xrlUYNv~LE#WD)kbq(}hNu(2 zU_7TAVJ;JKwCt?_t?EO^uS|#^Srh|ZIsVOHeh@x&pYi{?_WWPoiz+%ifW3OoS}Vz@ z@|vKhfc-~~6LM7ny=1pJV%O|g0aK2hZWQc=>Hhb-JO&1aIt=ytS4JfZ{P53+{)cjo zj{jQuoTLZoe-L*fx_AZr17roL1rk?k0|U6cEh=%iz0r)VzxGcyU?YKOiwx`^^|SxW z`3`ipirz&LremIWoJxs=7K%^=1~A4k%}P|)`w79PqWCm!dyi^>&=&rO;!smSNe*MU zTb;)tRY1{3qtnusS(CZ$GDl)_x2`}!+JgflE3LQVsYCrIfH}qMu zD#k`enIL9(@|N-bY_z*{uG9+!|BK%teR)F1$6!S+m&$a8%Sb~|jV`oQKytYs37D80!t{FkU?I znn^zm`xp8dgZ2Pa(L2LI{P`jHF)^H;48|>EYGyn^PsoC%k+yNz;UJdef-)<_Agl&B za=%EcH_0x%f0z;Kt%J|+#RWhGLEByTf6+&8FI$2IBEAU-@CRbRxZZUE1_l{}`dzy7 zSr#xm&9({eM|xIe#!Bn0wf~(-{ZDjD=9-6Bu79R(G$U z_)U|sP_ov4!hwtEABV58w6e|%W`dwi+6qtEaG$E~p@37h-J7HC>Xvs3l*SXW24Hm{ zF?TTXVcV9Cj372;9Q2=EsH%tdMG%`0S~kDj;KoMlb%}B^O>7+&l)d-w8KAlDjKqQs zmI>x&UN+VQmX+H75i3f#?Omz9+3gB@8?*x)dd`G%VI_W{23}UojxyD*n~C1rrEfNTYQCnYp|G zZ=@`&yD^CXfZ>z`%Iy@nyn6*~#|Zn^VocaV^_K6Me{)B0A!TOV0+vY?R+X|OA&ws= z^3s2J5Iu*gV!2)~`8qlMb%Rmi>}a{g2tnHqJGg}b00#uIZqeWf656FDT&~x%JyPCB zy?=A7Y)&Cu-rWRDY5^HhApuEnP0NXc{^bB@N_QcoH9!T9HblUiHSRi}ptTq`rG0+k zI;+66zU4P=q;$quAwdE4D6`xSEk{ycHdr~~>xbj@&Frez$;y*OnWOm)K*`;-Iy7w< zVT#4i@JIx=OP+}&n~`f}dW6Ycj(YwlQh>#&hW^kCb|ocez!K`H2;Uy6rXRK$Kp5>F z2LP;_ACc}(d@DzJxCWvAbVWZM$Dvai^CQ!b;jQeGxGIZ&x|CrQxbimxVI(I!HEb~c zfa}Bp;$5^`pTR-}E0!vv)gY&mGhMjzpcJEb2>DsHNM$&=QR8IPkBz=*_Qn1jrc0vA^s4vWacRw z5G7R98D#4@kd8)b)dCU$1QVLH+XTIq-q))iozLxsNw`HW20nnX6Eh*1XVdNS#^olH zrTO;^yd#)}c`tYHm!?jXTl$mtKnZLS-G?(#he#~A)j|TF5b4z(ek_@PW?!m<*1lnt z{$Btn4WxpVM8|F)K8|T<;3xf7)zZM1ek*MSzBJoY>dlNI#@!PQrv*G1&c*qMmJK|q zrkgPDVlPb->l0UGCX<(t>k?P;%+pPQspDp2+qQcU*Nw7}vkk7OV&%y4ZrRExA1XZ; zlFoTWs?jc#%9-W|8Y51RYxVyFyQ{U=lXGYf^oNbACh_FzEHuQYF>!%#8FwQXuHkzFJeQv`S(K0j4Cl=*c7o- z+zgDF%JzEM&=(Rm4ShO_K&P=`?B{DABJru$r0nECLh)dIxFI0xAQ zenZn1u1QAW+7Dn0S9Pp3eDT>X3IEU!fFP)l7~+Qa|BvFWJaN~)!Pc%vc?^A`Tw>Ll=9utU)OHe0^kDVsVv8AL7{ zB)>y{?f98`H%uOb!|GH2z_P^*!uGx~U-_LZFz7CufMk6vND5WD$NE5lVFdJ<_MRRj zm5(gfLKy=Q0ifJSASAH=b-t=%KD)?jA>+2fG9Q_NceNvIpUdt$$>wxp>+dq{u@ppX zwWy3t9$f|7=f9Lr=;|r7DP73^C|)#|ru*?|T?sOHci<9U^2bSHsBnivzIJ;2xc8Rl zsGmfwdpg%*rE(TSpusF}fN( zF!2{qx=H(Z$(JG*N~ut>pMNd3Ge|D29ZQTtt3N$HF+i(lVWtmTRhfBs!3(k`05V;j ztNQ^A!^E6-qH@bNm-mbcHYTE|t#Gu#()*(9W^{wJiYkTTA9oS`6xnxJ42IcUQ?j>_ zFLX2VPZZFAAk1fxbvR8#w{50M+XT4Tgm6bgGLl@3`k2`7jk*8kWPbiiUxFw{hVP=< z6o7gTB)~nGy5aNg?G!C^?RTC`y&}JvxQgfFb&HCsNUpeRcYpaG9&PHXAMGDr(6t)? z=}qQCJQ|>metW)_W8xx`Jt1DJ_}ombDM5NPm&mmjwffXnTdOZ&1+`+c!>Sw8r;c4= z!m;_CeM4V_XRgaz3N1aV$2kU6GP$C6hY*rWKacQdA{H?3^|tI0<5#(A$aiP19 z`{hS=wqnJBe~GJ}Jvi9|C2ezF4Q+uf`Ai+%@@iwznE(~xY&^EJOr?gcw8);jkPgv` z;vEoBcZ82j{^e-9gMX@+tCfy8{_mz*aS`NjT#G8)k7>WqZwH96ET*n7vp?y_+DL!} zR)75bxY}WG8JEJ=B>ZzrxydN@mg={sgfUTJM_dOGolbMTeVpVaqmtfgSDK=MNrd_! znJ!Cl^l^&cgvB}is20GS}>f=p#@!Kv!`>Y&I%U$ii$jB%Y8l7yl znxu)AbYEYEVzkhAL3EFI^yPqHlTuLse^oYl9g1&0p%moVc?8lop`z}fzOooKNm!DG zd9ZVBmM~AcWKl~9UyysFH!<2Q&K<#}3f`L<2{^>a+{hvcMk$dM$oBsBVz`rm;8s-PLAV7wfkb$H?{ zv7Jn2a7jb!MiNVvy=sY_`jp8@duB!oR?%qg`d$7V?Qs|*)0#z&_zr!r>r+Aotb8$Q zh7)u`a(+bw!P=7n5@ZZKKfay_@+bVn-b`6jM)LP*=y&%xXe*p2ty0w))NuuT01arSR~;wFT_ z=hsX80?wVs{hH@)L>#e-ot?X8c;}aJ)}VZxg^E5jPc-hwndw`L%}Mp_eqQ=<*HF9L z%)8y(JU0M&)Ig@Xiy?L$E#}+;7Xx(QefRF3pT)aggMw-jXjUUQaw_8OFR%P`!*`Sz zwiA!f_nO!;M~V%sPO_;N!$4h@nQoV4ImX{!IU8D-e7^eI_$CwX&rbg12KPm->)Dwt z6x9-WMeOv^;PMgR|LB?8up8r0HMcDhqA+@;G1mX?DL;a2YllPm?Dgi=EKPma;VFB- zoJfP6>0SDFnNjmpKIymB*gj+?CpnstNEcvGIqhkt6Li}0GAMWyZhc_>r80f{vh9+5 zj>TuS8?$QZXV_YfD=ZCwjLZ^{CaM(I1q_{ya}e=3Y|<-S$ak>A)(`ukcqr(KK9*g; z<9zp$o|6*Ror~TLN@lLu=zl&{Gv_^dr6j`78;J-Evyqb9HRyoL%n-IwgJ6S`W}xSH z`rnVhty^$#o{M6M%^Z_^#`n#GcLoKzGhNH_ZI{cg+RPY zjW+Xelyz0nw_(>Y8IOipWL4KSVW>TYU*f&rtoQm#+h|9|&NzlTn`)FTz3IJwF&fdvml<=yUgB;~6(1#z3v=ztw=3 zDLH2V@%p3Ub6o|b@bic%5NJx7imF_)FR+^gnS+lYO55UN8An`LwW5)aia<8#b!5g6 zhin&!PH=+VHeQmRxWI_lV6V{KImZxP0U@EYJ0+ zx0_Y$IzYMA$X`Ac@%!u5K6HNXx5O7=sAuF@iKXp?oevP|m8@kHDy$|J%art^hlQ+VFzq#f4wYk)OkK6LFo@U1yz z3*$Y3w%ST%u)iw+)ZG9tAr}T!UOkeFs_z9Q5=pj&0YYc)hP+2Vw*ELM&@}N*b0}xH zPY)BJWy9!dpx)y`fFrNQc7YS^1gH(viZNeM5&Lta6=0i_nehP&k=db=MlOqC!UJXt z!1a?7(<%LAId1sA3>YYp1Q5U|de0P?~ z#28oq8VmkDz;{2uQw9IuHvGSA8}2#5`%o7y5dXJ-L4U$i6o>fV_x@GF{5$#kbNwe` z|Ho(l>m~pHJ@o(hAs-_+SP_%hq4*~(|F?(!@6Z0XK>uIY{C_+ikn{ib3gX=u-+%t> z55Z^5)vJ7iN0J0f;q$pXA`~F=)5+$LQhfKW00j-r^QNq8iL(wL503`uH>7}AFx)SV zl=|Q&CEDs*s$;xSqceSTV^R`{fH$v^0)(Ajz-3Lzy)oW$W7{n9nSd~R9%O_qcQsAd znQhz6B;)n{_Lk``b_Qa?dp!AO)rOXtJ85a?s6{10iLp-`(vFq(IMR7Y5QgT!0@-)) z>UdG2&|o!@z~k7UJUv6lmF?VTvMT(TSEIS**n<@D#hyFRq;tBHsZ5l&O-6=CP+(y1 z;quR1=heO~5sR$+aihtWw?89$a}^;g-DHj@7q=T5?*t0U4(SyWU)~)zRLm&(-uT}f z1|ODbw>zHxKJlJp(IOTQAiRx7Bc8d?EL0xukzs8@M-i*!Z8n45Ziizz(Rm;I_wY(oJsi}7xppafT{$m~G*{xKBy-t$gEfat0 zH#HgLVrT*f_5TaA_CU?<`!U#}22>v7W%SBq?J+A?{5upv!EMLWD8~gR^ z?RXjUy0d4`dO}u@98ki=OKd|fV@flMP)N*a%7BFIgrn4~gWA^;2TE}HFJ54xby4>*VS=QmF?JF4vmzD*|?q{ zZ-j{5_=jl)@WjzBE(=tkyS0z?V=CYR<$vi)5LQWnu8GHj6crR0@mt@{v$RKZ>xFv3 zt%oClo%<||F=gFiw<$w0BBso=EnoeMMcDeZFMhQgNXrgy4(uKlQ#V;n*CAjhhYRVF zhVva!iYZ?642K6Z5rb@(-;>Y>q!Iz$&5yQ^l+OoG6FF$n)5%1|M9()yP4Ibf!?$j< zy+`o%EdMTz!&5+ZotJve6~JKsDRb`2J~NZJorS)D?O`M2;oWP)o0hh zK%cBNtQ(1E*^kfj9LVif^>VTXQN_F^mp(snul8EkpVNOknv7$pd#F{-U^bD8iA`6! zbm$F_5_zMXTv8NiK#I0iltl)n_(Bc9p+4$Q&J`BuK(8jOqD8t>)m;UaHxOE<3;0pa(_` zN_CU~pY6z~Tt7-QYi%Zi9g&ohyUtSUiet;sDb4R0QXo++*ZI9F$GShf$xK|ID|vd> zn2WeA>&zq!rae7xldyI>?TmqIqO2ck(Mw`9(`lyFc_GSYiCdcoe?3!HHCDGdiU-ugP7x209dP_j+VJik%;MYRE+Igb7=F$ zzO=35?OrB*6AAYf%R1s@tw+h1`do(|=1Lk)BGr>67iy_Y#ze^^Y`I5}f|_JgVWmZoZ}rMB8xx4K2K_rM<396%=r7Kl+iwJVgW zlNZ3m9MW9Z$Ca!{YMLcPrc52a=Q<5!4@++SAg)zs*U~KdPWF|>1f6DqZKGN-zQq`q_t=AbCvz?mYtuM$FVXp$sbhS&25>I&LKg zFfv8;hZHNa4C7YWm&SMwr=h^!`eg>t9RQG|xw!bXM>MgLUoZ%Dv=vf5hqt>*$HJGP zcuA=;HV@&>epEj3F1})+b4^+no$N8mE9tSSyPp=tW{mniX4pkS@59I7!KvOF!Tfm< zQG{4#mh|X&r!<)PDsanLQ@Wasr1i_s-|5%J>oqAP^xL)bInlNmsKGJd{`Ch?9d9oIFDOg||k6BsKJ;{ zYg4sMgQB*hw|btec{#H?aUQZKQ{K&l+DydG0-vBCu8xuI_1Q#a#=!5by* zY{_ZgYP-lbY@P~DTi?%&BCq@#$uq}?+asRNXK*8aI8Q=Yb~rKoCj7=};?8tD)$dki zcKjJTNmr-b0jmGfgFOv@1hG_0_M}jWR#jMTYRxcabsi#Y^`?@=@9|{o-LW#7tv@l_kBIf;)EY;dHlKAI~ z4qmyXdjZos-0S*l5NPQ+IHbC!K~=8fR81jyqk8o@DL*x6U?i>l10%H0??<0ms+AEA zE|m3D^BZS4d$)nad>!$#X>W>gD6ViiC^NyU``C3!&{W)KRlPV*{Z2TFa9&a&EdIx0 zZVKt(pHJjScL3B1X0C&#H09ff-ttz^`)j5QKvpSXUdpkJ*+a~}c2#6SskOB8%WAGx z*2fIs#vCqW(Q_}skLMZ?gTFbLt>$u5yH_j9<`j~Y`Eg0Aq{~mkw$*|8kCK#V^&w=B!X5kwnuI8eZ>lvcrsD!Ympf%Bcw+zZdMK6Pm-W+;T+ z{Pyh|bv^Y$wqPqg?m2@~5{EISRK51;DXny@`*q#_4mI;)qz;pScT$F7Tk*&P=1UnY zFY+bUMk+JU$sAk0$#|Nx##@oCo;qhak`CW&95R2;7%$)wzWG)|RyFGnF83{<=)|INZ^3NP%c*eok^mFa-qRx%n!+rJIC4I;%TP z`LS3+!(i)`Yc9K_1=~$!%j|jb=&II$J~owDCcFy|-_>Nyx8Lq160$tnjq4<)?y%?j zBUg*uXXbfY;nu{HGp%*zseUg*3#PY&W86|230W2An*RWndp|fyTD@eY4JDIfRjfx> zV4Fe9I=N>Y!BtB?fY7dzun@^Su%>R6_LvR<+wXCiH(YX^-?s{T;;LAfks0Sm`IQ6( zuACkhD5=A_#s@D-8!znjkv_moq^GBcy5(vqbrd&UQXMNZRZKV6Id>y=9p~`{z?QCc zd*e31H6ppqOj6-AqhN#N$}v0Jds7BB8kZda22i63q@XD9#P3nGyE8yuqZ9Oyu2yYA zy;3u%I04^gDp4_=s`z^gS+DPs^5^xx(g*Z5cQWnl?uT!|=^57={0HlYu$ISFw3X$H zgIVE5KIbJO!Me?I@`jFuMinFN_qPcnERaIi4b_F>dPsIW>+6!;?FH6urN2?&%hSu1 zD}ft%`glLN|H_fX#2B8X$0Id*wg&ZH1XdA0v$Iqn&FH>5ZVDp;u;Loe`c0Ayp`4{v z75Cn>{Yw(~UX#f(lx2bilQ zLT2rkO(okRSTrif`5KM~;&POw^|xh+$1aK}*x^m!(e*-PMz6aQ=I(TV(R!hEc`N3eX z*-Gw9tt#7ix$XEr^unpvO!%2`$b3%<`{T!tN3y$Y%+_xi&H=3lJUj7BSYkcvsQ>_s z;1K3uJIwQ@`Oul0ZQUO8iPQ(mfQF!8^5d23nZ=1|g0_x+vFpr|zK|Wa3a`QHOaN7N z`af=#o9gR$=af-+w0d+S+ojqlzsgo=X{@Ls_Y!}4Il6s^^IGP!&rQ5I)8CE;fNs71 zAwuJ_4;5^=1355Tq`+Hn@+0H0{3J0y=-Pa8k1wnN{;jUo++1PExFC za2)|=qXG38*atiH<5_^>D*ft1+tiNh>dub*_VmVFY)Y)2k@vS3J6K?tP>IZ$%##WY zl?;rr+aVHl4rjA@IXv>Zvz|l{Ag~R%!Eys?wSaCbN@= z+k#fdmNpE3Il%hJxcKFCM6PQxJf9u2NL9O<1w`2etp@JxhHq3}=hl7DFX%Dtm9uD( z0o`A7i_gJS`x3l0$I7Hpey)d+6Cb$L?%la_Cta|yy_rUKMPz^3GEv0NY`!Z#y^~J) z(IbDfpzO&(22y>RgNrh((hdsr55B!)l~&sNb)IGL!cGd-{L0Tdg)jOO=4HOV)y@2h z+&kH5rdg{n8_Ly8Cwo0xjrA2uA&CLtS(8+OIc@CiZkm(Qx5-;u(*>*-RPmE1M0(`e8 zITolGwe#wLh3Z~`ac)1I9HTf&0W&xO?e&PAtdVL{<;w|x5&gdM(dYz+e_ zFqDFXXW=@Dwao0pGbX;{C~bDNc-|?b>nE_V4LufH<`SDLs60^Z;emjA3zL~V0R6d6 zbv!?o*rvPmUChxVc3Ydr`$b>XT>NzO?=6X%e5kaXmb(S53>O#g=h%-8e)gv({Kz1i zruOgeRoQjXW=_&dmvd4{%c1ZOmSW)?)H(kFpe?|I$!APDV>o$OdJOI}iQ2_jMYV-+ zp-mp-tUndCJLy@JxI2-$>l?hkx!RuC>HnF_~B2FR*@9 z;LF6CQZq~F0G*;;-t)A#yY)ACz`5Zc^svGrRs(W62sWi>&w!-Ks!cZVOj&tg9;>`g z44u_jdDi#u-=6{fggNnqAP75f^jb^{ng#j~LB}7DOcSUp^YkmS;miwffWCqWUkaeW zg^t#Z(K1tc^EU$Fq7Kt_&NE@6o&Ka}%r<^}3yuM0eKy-)n_8B}17xO~q3epVZzC3fWD;1kiq)gWVrX|@vb*mMLGL8>U2{tYoT}?*rJtPCU z@rT>z&)0s>zjg7o##6z@7qCCRAW!|qx^wK&q^&SbQHv3si`3NaV^Q@`zo^fqtt$Jx z%)?KcfhOFG@#o1v6!rG+8;_uNV*H2oP1ue1Xfp@Jf6qr5J&phu*5@*f-@)>>9aB^hR&!DGU4B_0xVPg9; z6q(}nbxVwRBrdnuN|5>+rS>>x1ZYQEOMFr|-*pjS%S z>d6U~`pKUa8dQe$O$G*l;dUXnu<}5Y$kPWHA!skTXn&NRn7XnPf}H08tL!d=vY;6C z)|Jg`Iqj+EX*yOIqNeCXy)ncZpCFi+hiK{s>apDvn9OKvh1`5_6fj;Jzamnv| zK-(vYLv>xqDOy(%?qR&r2O-{){}8RwX$8UVyF6( zd0pSfUC9rSZ}~_I`NzxLE-$OGJLLNQc{1ma?HVb+H_|AG_i1iLW1&7C4nvy7f7Z*}w9-&>usV45jG9p&4OmOgH3ZjMSyg^+~u5(jfMSPp-M z@XaC?QdG8TIo0Z7u0BIbMez=1o-yzGO7Bv?z0gaSeCPE-Pcj$UgD2zW0LlkHTgOEe z$Erx}A~2(Uz7Svz3{MFA#)zNqnIQ8^pXrP|zuot9T^`Dl+fER5;00!k2`f+H;sYsY zBRNuGTCQKip@U;D^Yu#Xza%@S#wIucg*~IC9EgF5k~N%E87qV`a{G9@MFF#AQkG}z zr>dfKp3i;pcCQ`Rez|0kir%8-4r8p8AkT3bd?Rx7)3SF>FV-!k?JvMQed8G~3A@N% zWTo}sW9y-srxH~TGv!QJJ59dL*S*m%1Mp~o>s%D<^_oS)ac1AzLgXwy=jp;fZa*;f zoD#);L@7vE#4B-;uqzDb4ew5{)DUI*;g)WEM|n|g`j3UqHr`7&|I=*8o|PhRT$v!& zUSbkZAdf(0y;Wp!8w=3SFZ}8oFAB{3>xklrK-Yay0NOC64}Str@ppc7lf*e)%WgLs z4uLg|YDV%IKT2;-lrXJYnW)Cz575aqd2H&dMaqBvdU+h# zdqKyE#@}ibhjN1rM7P7{i(I;dRrFasV29*+0!LDZc;fB0}g zF{3)+w39XImi1nVE0e{IIFx2Dy$MWx;Qr7r2cDr+;bB-@=AE+KVgXxN(TB?Jy8dOt zSmL=%N9O=>kx3vrrGs!bWr>W z!G#?bv7!DM#x+WyEsK&E`QWl})8V208ojKOwN^!#mF#iNRL!jt2)q^idg{m_%t|r* zRt4~hWC-WP!PPjkE=k898UUWGE6y;Dy~R67|2y#T2;g9dCwOKq8~6;c`T_v;PI=>j zWA1ILw%LxTBCEAC9+OT%GgTAzE~&Pm1p|*-_p#nM9z`7;ok;ZJesqU0fw`WbmMFqj z{b7?@oBXTT8WP7F)R}L`lk*mOGyh)X(`d)??7Rnjtw*{=U~}Lq9QjtcE)9hD^*xVW z>S6UG5~`n)cZ*55Eze4grIpXn-vW)9xPK&Nv&1CdsJwn{C(Bq&dr`lNDsY z(HWw3`<~p0!|449-vcG2yFH)qS{>`yl+@1tOHI7 zgJo%uo{mWf3_v9Pn6f*|MuNb6#j+6Dlgg(uMmu?xHd9*mh^(vovC}e6g)FCC!|f^Z zx@gkZ!wK-Mj&wHO_$N~yM#d2nmFs4c8R0CF198bZ=jf%MVjI+xWze2IlD6$6v7pbS zt$_hoelyRaZ;A}6I{^UyfRvPUAWMZVL+2B3FA6|g@xnGS$k^JJ_8*a=4o1}uM$Brw zXF^j7-Wte}H=L5ap!chZnVK02092PNQHf<7V9?h25!{t5Dca%I_We73);rf=_WI=6 z1PZY$$*Xg7vBo!OH||QfbbWmsFyw+|Ew`Hx;m$w<6)~*vp#347wK^Zw*kFoz+QONm0Ev$gf3k})W|~+TtH=qZ7ifCH%R_uhq6*$Q;03Uu7b!Ez zV8K4gMMlph{jjR2Y987JZU}n)k_gYySSyvIWFow=#2FW5S~| zlXEcZTLE83NH0c1ghatlPqwlvRki^D|KH6)XB%rA`QM(x^dItXz5wr@Eefkuy1{p- zD*Yl<#5zYW_xbew`X8`}L&UOJT8XipK?64t`a@>ssEv?Cr*X63kEy|f)PcOwb+uoy zC$A^CB3nZsC6&E;=CnQFa>>2K*r#Zp2T_Wo^hdxBKlaC`_v5Hea~Dqf%%uFhH~-Y% zdv{7r+o=25{P$MIOkLk$Le7$tGh}@Rh&tA9-`qK*_e-D@{sOVdr@F)LV)-+!s9bUV z=&X{LX9MeY22@5Wam;;lAxAq)fS3JetF$%1-kNXzYH{A~7OgGRie=Z*hsd4JT=Yml zf^wffcGXV@REHPnks<@k1+oD&?ht8+g6V^+?RmI_!uzktou?WuF~(l_*snyMG-0)? zz89@$^ck4QJ3Sgso!&pe3`iK;uQ1Z8BwcQUoAN*bQYSn5mdUk#+Z_ExR~qfY=4E-r zvJOb4thFKAWTzzkhm8vzv9hVxX?RjzvC|P6cfJQ-)5_QB(82h6O!NL>+b)=8HpW+2 zv^cfA+=cYE+g0%VK4)jk6a1COY|RKm%&cz%0wN~~8y_z80|Tp=_G5b(Fa3`G{g=Lt zy7N^i_NJ8Q^N-g#?*d|wFqzVTORwuZE%Vt7$>mrsP-kahq|rp*ey#+!N=GDHnCV8P zQL^Fusitz3P5Ig8ui_4}oqbmhKhU^Lhu6H5PBBCu)X~0RC8W?;&~rAU;`?k@ye~)) z5VP8Q{+f&Phray-eg7Zv{I7o+pN`DJ^j^mQ&Vu}5Vg4`G|G&P#?+yakkeYz1A0gHC zXY>E_oBmmyKYx6~?bPN{ zm_Hl-Q5ofBf6hIg?_2*{zl|AS&5HUQl=44+jDP)a3-2S6?9uAW=>P3e{sbIlRfSvL ze$jfWeKQ!E5o)(7J#B3(r@`&YFDmp)7;_@817E z7vbNpssE$@T!eqSUH@|u{`=z`z#f+ams-()9O%`tP^X ze@fGTUz+}2z5k!ekxpqNK!Fgh4i)NGyp4S~_J22U|Ju!YH_ zzP(gpt5%6&ilOL)E34%3r|#9RsH$?p{`iC5JpR9vU4O3e2LAGGl5PBGcp>>e-j*6H z-cSjWWNfGqHL-M32a$DYwC|Rj=fdBaM7})uJrL#Z_3*n7pew)J?(WWi1aPH~DQrKH z#=VU4Ev?oiKdD)wmrb*;kA4b|#h<6DY&f3d8~KS0uL4Nb z90-fV-BOveDL(Eo(lYLahCbcGBc(q%#k&Qugg6pa^{z|**OLEh576E&eSFSjeCNQs zUW;nI4643uGrsc*kESy|Q0~3L%F^LI$qj~A0#3O;YN^HBOrrL%&dn1n5%0IRqpdME zGjpq&Mz=_rUg2kKYgl3p1%`X|wrH5;;VH2S5Ow|PStzW{nc8_!$=$D_t zvRFT9iubbBgd4^%BiY$o*5r{N^k^wZCA8u*t{m%&*WXu zI81d(5d<-C{l4ayWkwh*Yx$54@}sSP;S~=7zY8xb-dgS8$N^_{Mu)fwaGN2D>wZxf zl$(`NF$fMVi&{RvgKku%?^fq$}heW`1F?^>7SF^xDmu{nMh ztec@gRdt(;mff*u%wkND#m7vM+3ky3QstVj^h98Xhb%iuR1tskKle&9$Uzo2Rj&@7~1YGN2ucC_JXAMCkJmaN|^=N?>;H20<4oA2_kl{S0!EV%d@#TtmaUJ z69B8l$%_wb&5WkwLwO?wdK!3uC$$5-z8-B`FROM(3?>qUZ6Ig~V^8!sDkgBMj890F zd|ayUQO9yJERxyRQVFq3!Z@T^S*_3h28J&UoeYq^W2Tby(s{A_pb+qkU4-RI-OT)@GweN!@iaRH&f zbi03@pg*s4{DGeGK_B|6KcdD;8`qy|2BzUvNMt~QR&p=@+r?3)fUzJ38Q6E3O7 zBPYi_O#5hYdR5&3>6%AV5y~X{tvWK&YJPRx$OceFO6{kR1{L$&LR8>%EMPlO<9U?S zpZl5WrdX~VvE2OvDZNjbA7MB7D*JvIQP{O>g~sc;R+3F_b$%R4W75#wn*`6y#-sm(_nmkupBg7Zu^Y(h<2$m zt*e%vjNf|&k~|KV8XGV#p|j)XO|?VbVdgtLcYe$1Wzw%3qn{!=VEZ#LGJcA#g6P_h z6suMzvc%&GS&RAc{As{F_UjCGY47{eU}_adw(4em?X*)+Lz}wjgQ?$U7_j78a-=xI>OfICq;U(W&>s7mw2D+Yy8RCf()0I0 z{gu4P#V7dVir$qU0W@VfldSJVrd$Vg0*>sNtV!4l`>tuII;ExByZ?A|e!S2kl``2& z?auQUl29Ln7dQW45(sz?HL(Yj{<4<>i97d$c+&2s|0Ba`$dRr2}R$M zl=BgT#pu_^`*c%Vpdm85)5SHfywe>E__^(isFplCM8%$?-m2E$J$s=sQxB67fBmfQ zQWklY`zm;lkOr=m9FQ(vLQ-S&;jH1$==I+mv8foTEXJ%gix;~|2ZjjI!mo?(c5o0f zbgt9+UeKSFVHP2?9jJ3yzxL=&Gc{!GnHZ4HfG>ZZ|>*z(_T8EO1C><$`W}rL^L{h7qtXlXHXO$Z%dIY)|TlMG>2n`rK#CK|zATr*Hz_kOCd4KB#b>Q=afHC?d>+^+;`Zy=!dA2d&q#Z?ROAG#J^G)bAx2rLfTCer0g z#%tG6xV@+;)d?M*IynPPt%4_%Q-TdRE)^N~h`SQ)JO;x1o-DL#PX{}*?|*PVc4|9v zGp_Vh3f7eHSTn0g^_#8+XO4tu(Gp%A##_8T^1<&6_I@}YPBE9(rq7w1*#_qva#h2L z$UMt7KLk#c>Oxk8%yFNzwVj1z{*mU%&8lW<$uBQ-2om77uT|9}!rDKIzqjkV_PKkG zlOO8DXWwwDECl82mTmVoeEp8fGCf|K_LztNiWQU3LCKX_8mY zKfD=je-e+xA=xqelVzF4yEsi4g$w6d+K*iC*Vm>dfQiT%iZCJ-VK?6iiqMUmj2c{V z-?xM>BAzVR6Y_ll>)GCv2lkNS8FNTZvM+MAqF1KBW0oL8H{(hg2a9Mc?HhYxZM^Ef zkbKhbBB7YK=)@s0vNvhddzB}1&Rbd&=OV#@8wX`6(jZ5Jnp>sC%^O+%)iz8BdV=n65WdiOk9(8hpPGm_9|55$szsz- zltk#&_h&X!M+slv#PCnV6&%_O9H`=Fqcm(6OJ9zRNUw2-lVm8OALbhO>b=v56U!TF zW3(Di2&CUlNg{UMWhDao{MgCZKfUp_UddDKvtlAGvUkJK!c8`P4I;c_ZQ z9Wi40D*JxQ-Xp}?dqtgd!BwtZF$A!?3x27&qh1Ae(nrp*gPS-5dHxz#R2{yL$?&^A zul4CM+vqX@2&vjfAU_6XOqJMXuo)Xj$0$ZDSoM{r0cjib5u#Dc@<;~7qLXiSjYBP5 zuLnoh?p>*uzttE(GnSW=l8~<#Z2xkaBgye?82#b1;1eLX1rLJEMU1$0#g*x^TuXR< zM=D(E*E3?soEfo=g=L{vzIw{NfCzW3^o!;KtqSbF$hE7UD*k>1`OzapAtSxal^h|x zS96uHy~;mLATywiq8Q7Si&do6lxS0U$~<0j3N2~0c3Aiu;i`ipEVYc)Ziylzd4ovZ z%1Vc-5rG9R0w{fOctN$uHqTFlO=pp&W?iN_tZh`%p<%VU!k4@x-D__ZgJl%8hrDvm zzch@{Z*!s7UARqKwEyGIQy=srQ~;iD#bF$yA+dRnxX80Q)4x0J)W)n9!8QSunr2I{ zdYP^EXV4!fc*03q<452UTho%80HQRLA4E=Q|3YIm*68OR{JhrtTRLNT${O&q{4H=U z+K*%b-HF03Y4s&OIg8%5z%sa}LT6K&pyr$iMgW`6LZz(7D&RVO6}sIS+Qs%;1fUhU z22al(8L~&_g>)y%_Er|B)e(AXy#mKweFwdGzbv|`;XCU0_kvSBgjL0i-q-j@BJRqj z;@*cl*v+^uthTj!|H;LwEg@JhfbAFLBYCbHl|hapa^1w7SCHAt1@_utb$Tu|&k;3(pZ37oEhM=V8xKRmmBI)0@-qR0``NH^aT9Q4Z7 z55Jt=vU$0@Ny=uVFueFl6O=rGc(UJs-)>Dp@ZFPoEA+AvD>LNy&5+zB5sCZMv`!(z zJt}I}ZZf#1tz=&&|9E11svcQ|N3HqR1Kz@_bs7BlS-P8p;#zEnGI1oK7C&YGk*oNq z(g-rLbIfwvhnMXh^67mQVoJVJpoP#{3E@M1fLnVZ{2GpTG1}^{JASpGh#)}x_2tK=OM_KqE2{U^$Nj|z!t^o&Yb|rQ*K`spxJz|jj6d-=I zHG||sXzzx5xbS2j{51Q85{vNQTU7)6%EzAISl1S~&d;DcaF+85P@_N4>}~hTw)IHw z-^8wu7}y8b*T0hQ3RHLne6=vdM-ePxT*U5GaXG(C`1Aw)@_V|g8~G^W8JbC!!5#B8 z@S|WuZ>8-x%7z19aI7VRz^j_|>Dqn6{+`YKHN9CBaVaO6as9@0jbrdSX6ILkDFE=x zjeCHkaLXF1wt9WK^f4h0&*n=%*>Da|$tNbeHaU>(#pn?_KQ$1QT@ znikKI$Vwv?D^3tM=#Tlc2p((V7I>%gRCOhlj|cYv%4B`Ucif_q2U2=x9&8p2+)OYU z4fe_70vK!griWYbWO0}5)Oi6n-1mouMGY~J)q(s$Ff&xu5bL+tcW3j^%4^nHufzzI zY7_w4LS1FyY)Ledh8}GWuGRwkOv*;qdJyT>709Zk%I20+?tRl^MWF0xcew>JSGw=< zvo?;>$KKWHtsWFmgII-{NIa>OKat@rcK{!w2d*7T0lR&oF9hz#Y zuW6nY(DPc1RRm^x@qiBwm*~T9(8X;`xm~Jld{k)Bd#kJ^gsx@8cNer$iw(a+cQ1IV z4^hF=LwGW|PPv9TECc*VQrX*IM~vGd_EO8g0JP55_NVHeb>0i~F5j5^9t4>hp!3W_ zZeYAs3g`QUk894X*Yah%1ob@LHi8MDlGUw7Z~vU6-P`pB{3>mJ4Je;i+ z-ex#ID>WtDXO(z(gSlYb0(sZbS!P; zhp*HaMfavAsvQ=3J0vug#?!V7vN=Ros}Eyfp>9-|I(V;~3aZVtI7Wg7(e~lMyw7>D z9?6EiHtQmNv8|*hYCK#+dRNC5u;K_X2S^w>^8j(fJ#?OF9|(;1fnZ9lv~yZZNUJAd zE=^|5o9P58@K(J&#AO%c%K#)nt|dc`2|%6^<~NlphZe=cuDRTiz?Nv|;0SKYcr24c z-Ic-mcOy#bcR&v6OPhJ2k#rAaA>9ZMCxDp~J`! zR%JPk05lM$$Oy@;57q)xbos=MAQp9#uK60*BE=)8AS&hretWOAwvt+xw3BFE$cwD+ zw*{%%Vn@U$pe%;6!gVK8q9%`mm$H|CJjoPTZR==}j^UIk`bNVxUGWYoYiK&{=VuPn zq5BXFui4R(O*xX!DOkM`qqYyf{*Sfia;_&ZED{>PjT1Uf_nHHz1Lg7RPK#x1qP?nk zJg#JY5npik$s2O2#GC#XjYp8ix!Fky`Qa~7M}o52`YfdM`xin+J2;Z*ZGa{hMJ6`5 zC5Ml`;ol#N`$@TklW_eI&PW+e#ynmfu@r){)XWMDH7|NDSDEC#%!z`^(zQS1EnYf_ zBP076vSvwyaaZV!)3JW|183rl; zq=CO=mSXbVn*o^E&x4ucV~EN%tM~WoU2 z9=qCeI?fmI5k}jb#UM)ARffTw9A=-Rot&9F^bIsMKI;I04grj(JlU5YA+;{hkQb)Q zN4w^K7<9gWGZHdcGUy{qepM^FKLZo^^ST(Pj%MQ%TEmLh(US|;Yx>IbwM3D8fyxHE zEQ{7 zo~0By>(k&hoP+~A9Xad?xr4L3)mCY|Opr;Ijoa7nCKQvFP&I&Q_LNP|m|FxdalO2K zjofF*_)gICC+%~m)FEk6pLE^(&PC`tg2T1*P?%-r$$1lJ_>l4m5QX)fu)*VeoG&gM zKuS2$(h1+Mg-0M_WFt8e2QA3EbsiU9j(_{ULq1K*&V@jk_K@mYcTPdJ&Uv3}e!fBVkV^C}3c#LJ`s;5?(F`j-laC?MfD_dgmeFSFac(-q~35 z?wcJZ$!^6*+>lISfwL%-a4zqMP`1ABdk-y4k!Vq|YBRgAxi~E_EIl2iA#(+rIzVnB z$Q=99C#n}WhhVW_@(*TZtM5k`;4@A*MEiVKv|f1uLqV*RXLg} z|Gt*ZB}QID5_T9Ozf`%3tx_y~x>EfJ;;^7?Nw)0fh)LUMMwQ z0xeJmssYWee()xGIc-}zKix-lJH`O`4dPNODC7#G-nZ0Ukh;X?Sy_!_(Wk+>B& zm-wAa8IFlD!iaK#9gNL|oVvsL#Qq-fdK%iJfOAx;;wfOOerGv6cT$eao~GihE2ng= zc6iS2z}~@1Mei>{GpZP;lwTTlPKRD)8!*7y!RjE`cQ&87&Vx9U)Gof{C*Mw&|9OE& z!`V|HiQ{^bD#$gZ?}*zmN}~fKcJoZfLNCzy!XBs;*!J#wUnS$uf5>N}UuuHF7F!c| z4K+jVZH1moZQ6_k$`Sr)@t^H^Giy!-G$a_lXFyP?R?TZwS*t?rF@ctGN$HCU`>>8+6P zm<^fZ?oTka&iR^4`&=EQaa)rSXh#43`mhIXB{`0-t=N*F!s_(&dzeGT!GVTF zEQxhJo2$m&(1A5A-_H8LT=v1eW(0(g&eOOEWI`R9#gO}7|5-O}Ji0Ratb(&RNH7}p z(9RoXc=U+;<}1&LDVKxy{q)Hc9srP!WR01_v#^2MxNcLwA?0f^Is0=#D#7t%GKZ7Rxi>Jg3~M z2zwI~zt~E$n1_U~*#947^dNO?ej7kW7Xi0^cZCcE5yu~2bppQRCEDzM&sI%Ia%TkY znPrB9NVwagW3pX&2m9tvh-VYTztIm>;NgHDeC_vfpVGm|;3xrM>;eXIzII)sZ9WT_ zmu}|nvr4DqWibQ1-v~s)|hsE!I#Q9;2d?Oia}**vElj$4;lv< zpl|JwT!&0JG!Rw}$6TIRxI~ziv#H#u^<5YfXuHX@ervi$F?*ER!xbJTGTuH7-mJ2# z8heex0F1^8ppopYM~H1blbi`v@HNcW$%{0(lAVD$+@6mw@NBQ~?f;pvZb->L?^|yh zaBj*WC)G)zQcrgserv7&N;W17ZBz}s8T*`PPRc+Zge?F|bi0{5Yl8!Cl_u6snsFp~ zrialBlz%^laC6T$@lCt7OswDA@rb@V&sF$0ug<=Mo_{KKUey`D{#o%BX!-tH8C8{K z|6M4qNYrjKy`{=}81H-2&LLjZa+F^ttlZlY9B`f{Sc9+5DZ-+ZmRompv90w55K(+; zL1f&+o}m_NOz~MeeCK<_?{@;T!4?+{7wV&Lv4|F*Dh3BjIV^T_o%^fMYMPUSL5)3{ zeTPQ>6W?;7DR-HJA5V{=bX*VjReUDgC+t??S!k`E5l~lRL1y`#r$PFJqg`$4!QH)y zu0ZeOvO-g^dFL0->=|A|D{PuilfcdJRoAwzMa_&tKceqQrM?hux;`kiFh&I(yL9u5 z^~ps?!z8z9(}6y1(a246u!-7 zK zffa23_PeUoDpQfUDUazgAo-QeT=_WQoO?^O-qFb+V?!AX0k?Fr3bu<{-;9gMnlz-m zfE!_L@p`!8f-urRdf;BK^@H4TcGY8ZvDFWL#-U}du6a01d%QPi5j4vk_Lxv%L(0y2 zPg(kO56|D)eoZ5F@G04QIgf3m18!{&oWj5R-CCF*orDnGbpg8TO3-BI=6^tI%g8@j@UDS%sOSN{td*~*rmg?* zvGquy{`l961cHE&ZxZ5b%KG#-LfAmDA^zPQlQdYrMxT)yCsX1y{DPGzqG3?SwP-+?8@#hnP8pEcLy9zJnL9bB)nEBg zjg}yt*1)av{*sd)9)Zj05e9 zAeJ5ST&@@D(sS2ONlx37x3RVs`+@dI64eV8_h-wF!$em#{J0nvpBYi@L!e9m@+_g( zC3ixW-#Ke?y+#aQSTR$u0Zj0TYZBOsTYLNDJTuI(E_E8V)2}%1OGxPBnK}N(2afPEJ(xmp=j@I?mA>o7K;_dICLn@5F2A;tN(aE2)}buHJg_h_hryYz}rxKFw1 zK>>xrs_kNQO#Xda=Mkh`oP+$!3*?!Uuo~lAi8k`N5HfzCS*<9+6vJ~;QtSaLOSu-c z%#``;&8&Pki zD0VWrzKMawi~SRkIo$mpA5ul-KarKNzi?UM4F6bCK>FZ?b(IN>a1xii+ghaQL)FV~ zHC}={N+gWjCg1-84?BNLKBt0F;*)e zy0!6FAv~%Jn)?^HWK*(Bd?0M^T$Lp?4&Ja5ITydWC?cIVTj&fTQtDyru&}3}Zi^>f z-;0JcM}XrXJbz$<7FZt2i~sPp8fo#lda{BiFFdv!BH9GM2MA+T_|&FC3Uc5hOQ0Y) zCo4Tsaj6>AULr7=Zepr_UAY$0e=8^1J)t1eug`;vha?JpG!NCtChwR#){HrPN7D6> z4ps<3D1T{bz|^PpFeA>HGzlDb6X1`5eleF-NBAo-yIgDx zWtMEkLXjgWUDDp|kPx|SyiOp7Hj=vtcD&i7}@y2gvK1k|zfVb%x~^vY zw`c;Ot^-~4&+sP%+O$s1_axgi2St=#(~#(Z2oX=v{fi~P2FXo!vNo-9QhvqiM5FV~ zc#CqgXnaTuEr)Rwe5PL9dbGC3mfoTX@$!6@C%=9f~%^w zS`!_z?6MT@PzLf;uDC4^ZB}$trMn9@KZ`x(>br1k2)W z0~E@Om_TrG773jGlifu;vgeBRx7(moebD9yxUOGZ?iAH$rTfp9@P3LcUYP?6gjAK% zzSj=9QiA-^0X$m*!cDcU+OVc4|I4RXxODc0=+MA>@Z^P;?@raN$&3i)%DAi;-*BfQ zn!r*E%T2B>p{as-LYNJK!*FaIE|#UN7Yz$Tvyxnk5j8*$kntZHX($79Z+XN!Q$-%h z+`u4PmHe5k2LN6s(+$#Ox=1X|vE;@e$9t3!k8qU6QO+|tlJ{{0tR ze)S0gF0bq0)dQ_6!^TA`Zgs^0G(Q)E&SpSH_ZKrF!fEn#=MAf+dKP17F?@lmmonCH;&YI1klKmXql9xo!u)>KxgiYwPpB2_ZP zIf~g^rn9MsYj3$XHK*u)pb{yQ4(u@ypJ-y8?byHp|5}+6D$&M{b(*Kn=^F{QM6Wj` zP5T%yrq~A~6pOz@u1%sQEK+?L3k(agS$u(+0-Haz>aC!5OtO>TFJ9By?HRQL28sAW z^fr^7YG6?J_33U6*+M;6i8Z~nGV36{U4r2T>o~f>Ve~6%eSwUd?I;U(yP7MSyJeEk zeUR!ZbTg3dn4j_gYwtRvnq1a3c7=_&g@ANXktW3k2$CowAXQ34YCr{%(0fZj1w0~x ziWCtDMS6)KC4>@+h)9i;2%$>73u!%swWVF#^^s1+9@7aqaxVBF?~?pzCg8YgN*0C7Zd`t!*< z@EpVN2RzB6NJZcy3WIU&XNlDC_K3=rysOW3{%pehXqB%~wKxe&9YOI`D$wU?^~xic`Fi10~XqpM>ZgFsA2Y_;|s z#Ld4!#~Gw+NuA{$+;%CskE4P zvxw;M{Mw72i!J7xOXdetKfb$_@83o*pAX^nhtXG0Zm)q#tmN6;m9q|Ya2f%Tf)G*| zMOFaRo#85sfz^37FZW>_&CePCfKs?eQ|XPugEKcu6=_Qy9+JmT>7JWtvqH?aSD|!9 z(iJTL_!#8(HUp!Ba^UwKM4=OC6(iw6W4T7OdxJ{87EcckJ(8Yxm;-@R#cym0jiSim z*}AsAn+P>OSljZ7e+P>hKUd>VZLD2#yA&|0h;beu7E8fhth8wI{;P9A18Mw`Rhtk^UXi`RV1_u=B?;}5 z5|F{_MV8Es%%=}KU19K#*Op|Rz9#qgprYvgUB#RQHBrmlXkvw{dv*gsFkg6+2&O>VxiO(M3*Uxn`^v{l?xiK#D*M#-b zzYMvvAB4z501$I7I513kcOxRDobyga4S;m@rMA2V(Y$`kT}F3_%(op5@yS01+ zL=AQY;ffH{b)hiZH$WeXi4j+Im88xK7u-z#F7V{{4%ak^?8$ZobF}fZpsPig%<}aN z@m{YkgjK$6BT3fq<2ZZZ6sa@LI&g}9Zz_@>(&QqXvPgRnk@C`wUyt6}QE{yc+m9?mocr~%Kq zF5^Q4$4$KwKbOACX=m$Tnb_%7#t#68=004%1N(VW%O*bBw8s8^8p5)H@0RF?LX<@s zYjCS7h2D!Rp^&Y@gj5^0m@pKumTJrajZe)rL` z*DJqjT7$p}xyLHpKmUs6aresh)_`4m(nBlGL)aLLuYGjg!_`54Defb|Be%#&XLiLd zmko+`=8S1`iFbImGhVc!lJB`mvDVov#sPfY9S_zQ0Mk_Miv1dX!#qd%wjTg%Q*%aX zZ62^RhtvROeHBeG?m-#=K=ZP_mMJr-^!2wY^m|qbp!N`RS$*?EE!Ijt*nUwA&pE}z zo954&iOAF{)Vl#j>djCA~Kzojx$lkVMtidC74Ka-7ra?2hrOI%?( z{jB?*YyYXN-7;|@wa3==FKqU@)dtNUiaZQaBO*9Mc5$@ga<8+%s?e3On`61+`|7wV zhT#yNw5T~@AAIP#*2t64B(OrSU#HY_Avg>~kHhP2@jgL;n%SI|7s8cy4U>|A`JiTO zm`QHWsI-d(5f5+JnFhTZzRN*p9_VZwy=29Suu8i3S|1 zc{H|SL8HjXe(G!5{Fv6^YFmEg_bN3nG9$#9X&`IRrGv8F_l`}VgTJ$W6hXe^Bd8B! z%|Y8)pE9Y%W_Hmk=>yMJzDzS%q??~(Q=>H@FyaE>5Pn)>>Al<CH7#JH3TUx>gf1 z8m(t|mMi?(XlS^a3&*CSK(~(#kk4!d%oN4kJ;Ae;SZy-!7hYsA?bDs z9J`pTd^?Ik)VC0@K2#mVoaY{8%d-Ank$g+>yLagI7$lP_ znsu7AI3oU@owY_Z{`YZS6NyIL3vS;KN{oO0;nX11@k>nX`RvRifFvyb8x>)l>2XU_ zn)*^}9&Lp%B8<+vQ`*a}Fx;y;eU1+vEpf|sL(9X`Sr&trqjI9h02q6t?3h#K@+~cr zJZog%xo*JdenB8afX}ln_YoWuicwy>Dgx{pGKL& z9*I3M%KN^@yHV&uzd`WK+fN`*v_Vnj?D$ohOlhN$8bPma<$6mDh^t*NG@S$}JQ&U* zhse1_i)vMijdDz>V@>W_*#v6GDArGqpB+z~XIlQ)f50&M_GzZnzllmRUHs z5v}#=aqqOChP=pRtU=T5GEV*(q17xObNAtWhbA74PEC1}oYyms`?%_fURok4Ig1jR zn&C$INF|-Rta{#GWax%r)v9q6U;pp=S8ck|8%X=!=#;Q?58S2OA6Tv{<2*A9sJ9AOR@3@0j1t``V8{^1-pB|JY3^an1Uy*yQMFtv1)tu5PP2LbDjrJp07AV>SV1K z?)~8W0&Z;rhhWoYBydr*J5wy|;27G>g zDP4{3C~N(NgM2Si8?deLB@F`QZ*y|#K8*!^<^4Pa{hF)(0EOjWH6U z8NRjZBjEa3XysdMK}m;>Vts?l@G$^`c2H)Dkq)WPWeZP+%YSW!PS}@^zS112d%f~$ z-?ctjTEm8Wfrk2ugX))39Q~*TGj!Vg{ z%@nXP4!mf=!g*yz;j$}t7L;uUVSfe)a$w+m|fq|5tDvg`~pv?b2I zM%Fjv$)heNRFeUof!!Y}|G`SV^p^kM{*+Zzsh~ zq7S_u+od!f8?^R-j1N^L1AiEXOLTh&DicAw=N4rm>(^>V_8LU7`_9C=K4f*sPU`4U#+K3I|yQpM^-k*(@|IIro9A(WH0igmv zMAxkOzLy{v`&l)9<8Q@izrFZ@+V6L2iBynx*X%lJPu}3d81`+q?nDfL#MR{yPf(TM zf>scvZB+{kO`gE7uD6DI`Mv#=et-b6Xq^q$26#ugr9KdIKeHKr^k5$;p~__ zI6>#-+CMjeO|BDIY4BM1%?zo4h7r%Ed3d`F_>%!i>eYco46xKfCMcRa^?JEGlGZ4| zmE}F)N+yWJ#d|~pKnga7>+x*vT75p&lz07^rh!1m8ehbki6_1)wJg+x5O+YpJ85vg zlJ80=))PvKbbem7Ttc2*Xfpkj5k=$eA2IW}F5#7jYI2&1qkiiL(3L%)rjI|0+#!N~ zd;jDKSx=20g1MePA`D1Itp(HqvGLl(tz%e9_yfs0;HKNM?~c~S3#znK#oUP*AS;<4 zYkv!@tiL5a+=D80rp>jM)4ok$P&O@Z5qF#_)na6|B+&0FieJK0sP7y{i zK|k$_=jY@ntII@GNd814-MA-F(;&|X?+B_x!4Jknc$DWI1ata1akMhKL4k--=G%t@vZ6O{s9r%8Li zGMV;wHzL`0i->VemxlN3wcOEB#UkPL2c+|7z7auTDn{l8JYH#I_KaUYyh6+}rLdz_ z(G&yRg|-4Qti;6vrJ(*P=+Wc_ZB0vBE1wQ`rH@_Sx4o|K6_l*MoV2TJY5x^eG@wN z+JKTSWv-u3R?IKV(Z%?+Fus!eu=9EK)-h$rRY{{a?r-L-T zC>e=f>Gc7n>CcHSB~4~mt|rUC)kWjo3t9Av?0du&Y&TKR5+RNkx=gC)J@dqShJ+qd zp0&Z~kRUeb(u>mP(uN^&CKljysj_Z1`$nWDsvenLW8TCkYuA}79BvKo6mXj@@Qlgf zBNKz~ywddX9_0-rZuKUiQG#D@9uqFZH6*RxHMAnsYg&8&&TtoeUKC;AFW0IWbh1%? zt;uz(i~OYu-Eb?Q&_I}gy0LbX(pK~7Fu{q4OWLrY#_7&HB*}u@Z4`&Z`D>;#qqNT( zFsYJB#l4n*G8N$1F~=M&)|ui~Uh79Z+E3b8nnJQEEhULvdB?08W$xKiZ}@x0du`)q zep;c+(>-+@-g@m#2%5$qsyk|g6lzDsx zDk_ux1*Cv}-A@KDgs!j$AA+oghCJ@V7X1hXyRoGMzRw7^#Ezt(a!dH5QA|!ILU` zWbS@~Is$U+;;zXZIbMWcTP14N%u8DLS9ysD$V*se%=X9_YZW#>&OCRw7iR!)QP}~-QjWG&`e6rw)31+cZcE#F<6Ko(n7>h2;2F3QLItEc&+3&ls4e)|QO(M=t=;~s#jT!vjR7{g%`LYHi zTK%FEnAVf2%#HTrFYS0tbl^j1nm9K+D>L*$uw|j7$^PJ~&O&W`=qtkx@n;U%Q&HX8 zRlQuD3c6Bb;fi<=Mh)_u2GO3~J@@bP!6hd$qoM=@R*5^9<753E$Czcx%Zd|rkW9p2 z71TMyS=Cjq$uJvdC?RUcDvU{qet~v|Oxt;!ib0(r`%K9Lnlq(u{smc9;8<`v6VqY* z4V9~gt)A;^hcgzVO}h2QDqCq&wb#IQcWBT=QNNnfp$l_KPL|Y4=14GLHg@0KsxNZ@ z;x|4U(NX^*3V|`sOQ1lMMco^_<;iQ~ZkNZASxm_#PU(vo(IPQ3H%eySP@I`5(@<-J zQq1g#$&;@h1!r~^u#$NZ%w|vVqlJJmTZJcAgaWRqnQT+S#lHE)vF^$QgL z+a;^f(FPd*a|0*L7ub%y+9PAft=+I#&t*P&tsU zcWjr1weFVr74<`?zrSIw$S%fdMNA$VFlXv60YHXV%NK;f?iFMrAr~qjoBU|3`s*1Jtq5}nQdgt z&4&}b3SK2U2z^BM(5sTC%I)I5K{*188QuKXZa@O{2%y|%JcG=im%JcurdSi~dKkL; zLWT$X3q4f$PA66Ow}X{9_vqtMF)*ifaj;3-O5f!oAbE3%n0hm2I=5PRc4t>Cw>$`P ziy7yB4>2QbhM!sM=#9u7dW3(Itk{8+yKjI3?Df-#mp~i$(3Rb`Yr%C#e&~dn+mSDw z%;vX35-es+Bz+oz?v^q^E*M$f(lZ<@IkGR_Sr*hP0#h0s?D)Hwbw!z9PrCRdD0meD z8D?-R=pui>Qx^a!$b7P|zaBoNS|jrGbBY@&MXxBTOrXEKhr^2oHzA%3=Xn2=QxY7s zg0jc^6~&t@>FEVtk1(7b7r;dG>1%KW620%5A?19vqC!oA;xG7w2AoQ!RsX_q>!#yR zId^Zs7O#Zd>&c)U**dR(gCkL=VtWtpDO%g(w0ZfKIpos)cyt^bYcb+QVh$6SY0ot_ z*!GSyZi5=7=!-g=6SLC-_I{bY#GYoJkS!FBLasYX_HsKB1MKD^HD z5Pt-ih&C-e^i^@U4ygRd-Q0zQ10%nX0b}m=JIuf zY=)^iV*!DRCHcnz{j-F~UblwM0TX8L=SclFv2xxOx8Gh$hA8C6!gJGC2uH!Dk} z5J)xwpA#NO{qXerL!E!>3R4K^6_ug2jN1o_qnz@1^|((=CKTO6(9QZ zxaar{)8ElzD@w6rKTL}M-QGi2AkQ(Ner*0li(f?F*X+0af*T0?abD+73j*NMp0-0U zNIv%4pJUX|X2i9Cvp_KM{N2C5=|Aq~XQX?m40NVqK_@!?^3C73e(~GL!+*a^ss)qZ@R-v1KX?CMe)mUHqCucXlts_6 z{$FpInH_Y!)l&1169fKe=GPsNbOeMp=H$;8etivp{_{T%;lK9O!+##ae;uy>%!L0w zIsXYqe-1r=H}U=nM}OBVfBNj7aP*7i{y#?7|05h#Zy&G`zI8ea!tTffUN^4msN^eK GKKdWOjGtEk literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/mqtt/throughput.png b/test/performance/result/aro-hpc/resource-usage/mqtt/throughput.png new file mode 100644 index 0000000000000000000000000000000000000000..1540bb99baf37ea8c2c11af809e9796f057c3bd9 GIT binary patch literal 216697 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℞SPhKI18(QRt>c|Y4V0hC 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

r5Ie1vN>vv9y(0M?n}BJ$vZVlS|tQ&!4*Mzh}vF z1Kbn@*jUHicR%UrMwz3PkF3q|)qXtt#e?UWSp2q`_j2{J_v`^*iocTOfH|(TLFY(HuG|I3l`Yp^KL#c9Lpone7BT@nz!G)AYySb{gYZ2>Shx?D9{|x z+&3Rxo8kY`;ddjHm4C#Qds%f0gW`odmEx80@S3&F98mVq z0Iqvl(UesE%PohK;FF`A*LNWU-A=4Z#jGt7)SXgh2^WcP>@*`}tRHOTwtz?M2CS;5 zT8^G5*ne3F=1>k&9r$KF5&wLUt21nB@5X&H&UXx7{)FU8NDTcU?>~ra0pTn5CIZ;kf0I~z*18ZUe6rK` zDYL3tEhdUgQBg6#(!VC|g8oa^_OGESD_`28%t=uhS7wRUU}%F9sjpHk8J(?hLLWYH zMATZFh75N6k?#GYk?k0nmm-Pgf^4uHVn^efbls0GeRFVrLxJ5Ny~5ME6P0Y!{Nc$_ z_fJG*M&=ihYN(oOJ*O<#q(t#zfsg$7pv*!mP{67t7P23OCh`t9WN^YL57#D!iqe$rn9upN)g!pXcVS@FVmcl!A%rlSwU7*$Qw>t05>CZP zGZ{5O!2P8oR`TBe(-cd2e|F%-hLtsr`Z_RE?GjcCORqp1!i_un5msstLf7pCp6fL%Mpo!Ox3~tK;R51>7`D zM&2Vm&7yA9gd=vl8`ts)H`1&E}bpNB#wEk-tw%dN2K`kl7lgaxgr`%EQWL42f-s_->QHUEnml7PRnFS$}qneA}Y4hQT%NW_N0~ZSsL@BNQ9)Wj`92 zr`Vut;@%-f6o_i*r&j#U{qtYzhCm*`LWwTO$jWy2I?Qzrs=N3MocX%GxV^n~+?}%j z@+Z?O;%R)17Cg|w<(%$bS0lnH6t=lJz(VTmIc zH5A*Bo`7M6kD2~wKyjt>n^0`cw`^X3Pz1_ci09{#zb2xuYn`5KYH{4AdL!NXv!eIH z0IXt`Il^LWS6UtBLfE$jP-?5!o@)&^I)1f*KoAKC1gLqm7#9azuS1bFAs8MIo&j4L z31MF)&MZ9=vvdJ2aOXMm{?8h0`GVeCR*Mb)aTEndi?FiTJVm`;OnURYrNE~QeqR!^ z>90VQgSc2N&kRulJyTI&_Cj$iw=on95*@Y=*tuF+-r4mix~574G8Bp+u1JSV5h(VD%KwOZL=LfV+X2X0axcY2@JyURNqzDxHu zTSg>H67%G&khaXqYJ*+t%VM+it_8HokG_+KUITw2N$ngik5(pz)J zh7gx`-Mc4%F=20Lb*JX&@Rx4eNC#;#^=(_HWDwP}>!ho*j&c2QhWo`7AxmWjgas%?1qgj8oekWD`qCCZmmX_%L@}aI72)Q~1(Mj@u>F23E z2>{v?uMAt$T-9tQ4vsP7f&PAqvmJJL=0#f_1QIkdhwJ+*tF^VY6t~7YK>>;hZ+vx~ zw95k|rY%RG?rPMAz4=R|1xM%Fhf*&uo2^lIctk|RQmq4tAHMOU>O6-u&t%gQA$ag( zxbG(m^47kANoTF0zKvM5l8y$!f~`xG{3-_8K;$Yla!%iM196q;aD9VSXxw>NDYS`G zyiVE)T6;r6mxjOq!-7kzv5N|3#N*9B4cgL=UY6NLTWbdlolFVTzgq;M);1D_sl)1o zp|2BhqU9n5``HS2`lxYI zlgzs&p0U^0Fr6~K%&Tk=L`0~7+i%G~6e8>OBLC740&8B^8m<@fIP5R762kG8ZWiy} zT+Cl|ri{Bv)k8Y1-|p9l{h{NYyXbb$=Cd?`vBh%Ww>!P(eh5&jZ95;t>`ub_YhYt={ zt&k}K}Gb;(meH%{eLZ%RW z)Zr)v1!dJTeAH4&zml`5DnX|d%znLPqHehOWs^l(YW}%eG=&gccJ%KzKtb*LmCP?( zN(e^l($f@Bum}pvJdZi4L>8k^cHQ~c0N){!PAj26@0H~^q!#dVZv{lpekn+=MpKd*`s|v{ZvI%^1@0MCWH?{j)1gI^Jzez#0}w- z&ozp~A;yA=&1BPyv`~O+`_z0JbE(u;(Kuao9x?h7TzuZ11$Zv#=zi@amdgM~2b^kv zcKfUk4{(J6TmpFAzJ6o`)`$FqW=FyzDGw#6zze$>5no?0ChwAP*vckWATsym*h!bT zGzv;8TblX>TXto-;)Tx`eQcE6{ znI5}H#4pjPRhQTM$t>Dgl;%qBlR`LVF<2lL&=FkWnR&6+mgu6`uV zk)ON5?W&n-W9F7(UwDZ<%<1NydgKfV7>S?(h-0WaNaOm2Mn7OKL__%4=x)mWI`Rtj zSOsLGvi%=*b#=A+YyM~p>Y!#xp=%QAg=H?Sw|HvO>fKP_89Sl`9hjuxY~SKk>--r( ziD7YL$dfN}k!kHKns+|?+Y=BUkMR@sAY{jWPGjx6`AglMif#$MS5~_A?gJIybfgfh>R#TBwd?t&{fiRFcc?PDl+q zI^Sq+XM@L(AM{Ul_+3sjPX%-BZ15zNq%`sNX1~TOaPPCm?yv&8c-|3YKMe@cM*5My z1-ed3jzvoX_?1Pj7O^D7z7Aaag@KVkJ}oC;pQ7KNz%lL4EQe zb|Qynf4HO6x|}A1{#Qr{b5}4rmAS-Ub@`(*5+{pqVi~9S{$a?|BGobczObuBH|Iwy z&{zl`dmxR_04JCT}lguB|59JAnnImBDRX@eCers&6+Yz+y-|6zml zROTo|#6WsS^em7A)NU>gf|r&arOs5LHLA>SLHeSa{f7yB`Lbx(u6FTW?`uYGi>!-A z{tsXXLVMib!fD+U)Ydf1@Z0X6h=pC&yfo>6W}nWY5?R|2?^LnxZX9M7>1q|&R%uQx zFrA<8)jAl0>S4eOhBcuLPLRN!q{p<5)GR7NKBOnA^82VSn{4^R*RpMTc(vVrN$ABFiitg0d`09PuH5jQZ?b4q?YEAd&#~6Cw4pe zGQ3AjR<+L#dRU`?C7t)1Drac_>3jfnkO{Ds()YM*Hg`s};CcwgF?>Q>VKS-{hl; z8!+1hrV=R`;7wO}V974|dpZLVztb{c#B8{CF}KxcAW{#of-4FBBImLLPLtFt6GPj7 zco=f_)6-+i$=?Y-_K#O5yE43yJY@Py7_mUBs21#j%pmg38`ZXUL`04BMO~QhP5`XI zql#J)UOEZ6;BaWQ9fFbVIodQL^3Rjcso%VdM*9a|fn5feW!Ry`Hmnwa7TthjZf0*; zsr+-b9wWATHbdW<;~M|fD2@5PwqW#TteEP@qM17X6{XyVzKC`e5s+Bq-?YG*Tb{Jw z`}O3=o(7#h9)`U94SZnDt%^HcjVB^8T_DiLr#%o(u3{RSAw=Y#Buxy+9JEL5_WP}O zKH^6^pQ%?ovo1AHWJ^#RdJ-qyPd-f)K2{8^>&^Wjb4b;3<`}tKZd+9&&y=x(eY$OX zYat)U%L|m&U}H?Y%E#hmMl$u&qd$_uhS=mA)2&jW=Af)fvBqz0G%_bEU8T+bD7cEu z$Vxq9L=%z}z|&0NFxcg2x5sL=){MX9W+v)+KGX#P+Kf5Sx^gMsOJYJ*Eq~nMfi`fh zjyp=)WBXpkp+?i8#qfGQr?LB=e05K7iF!GY>AR1$zby($fI^#|dA(2HoJ|Pi%EQfu z6O?(eNmfSpdRdf7@iwJYO!=Hud$T(9dkqf*BCRWM4b>7;4yo@Vww zQwbvX`>F@K`wDMY1$W9*JXYrMC@&d}U5^S_GBR=xg^fzsZ+BdGtmTz9e|2AOXk{7-m<>nTgJbmA2~HYRVo zzW~XYw-`KAc}QXR#=OuD+B`?L_NWnfwkJU-7DXM^i)Mm--8h{#`^gg_He@eN@@$>L za?>9&va9XQd%qBA9tVeySrVAg?(STML%e0r^9?(~lIIl)z;LZR#9yA#o>n2KF|-dw z7wiX-<4+NS3?G91+G;_A<#|c+#6TAh&O&!^T_dcC?HH$LmE}g9U)ceD^?-DX%Gu;I z(baOuW489!zc>#YNe5Sa*YanC>4aI?d6i2GDGr0NOaktgf7WvGcCI$@#w@a5#zd zx1$o7XmDx>3fUg~Rc){6(d@s-*ai!G+fdNZ<01CI1AW3>_jB{}GDT|0#^VK^6NM^m zlhJUWY+0U#-5!bW3XrdX%hlJ!-Io1%7z+6F4V|?$%V|-by8rEiyyc*;Gc3e~!+ws( ze$uiNbs=+`zS-F18n(uX!MV>i0SJcD@*GU>rV>5Q7t=r4bZLI>kU3pNh|g&vSv$@c zsHwnUcJ4Veb__C<5%;^RgD%DSHxCvI^r(dPy}PG$_l@UF^I5X>@hO)~oNXLFH#&X1 zARVx(Y(m4FC4gBcP!m3S-A?C&jxGC|b)XkP<@u+WWaV&F3`Sc>xKq$1+-fPNR^3$W zGH-eMWrP9zm*UCMrW5h)?hCt8B+4U&-}^^^k_~!U&=s#mYbvB=nA?WdAX3bPa9)1n zLtw??J8Em)SQ6EZzAE5`Is*7DO&2Fb)=#7)5S38xY}>~kmY9{PAW4peNcv1uj?Y)0p&(!(?Ix+ahH5u&yk~#J<^-gA) zgHD(w)KI3fjO1+-avGo;0(stv!_<2?5^->RnA|S!ks_XPP|dKNF$x>m?o{-wxs*B$ z{F7h?rMIIS%cmSTJm2<(wpXp~^RCIh4@oCq`Aow^1+Bq<>xPzQ0M}Z}R`&#)?jC7ejm!SF3Sm5WzigQ0nGc)Vk?2X0O*l4{y}!Dvol>Z8+MM38=$# zH**dfY5Df#@J7_ak5n{Y1(1N%C|>zWXhN1XwA3C}u-_NvO_Q7;Rl-BLwfg|nXEQ*0 ziCJC8An@O^&@{Go4Q|L^k38nwS;6 z+W%2ThjWx>;?FAPHAYt$k`NP#R8fQ+=mT+0jf%SVmlNCXcGpHQ>$5u8-t&$SO8^hB zz;%}JF+aJffJR%5f$n`7gEJtVXitf?a$6^iKtuz4#;| zvM6sgvYpBC5@(ac4Z`G2V*dGjm|k;kX-~i6$_e0|3BP1eL|ywqb)?iP9`P&ZGwJ=s zh1^Iu7~=0gDGi~P1n5t+hP~P9zcFjm#xKNDHeSg$VZuSeoX8tWjE+>77;6`+xSw$a zcqBTF$DQVpus!Yfm>Mo?Fuf5nNSqgYCt2#tSIknGMRlnzsMtl>ieEJL=6t2ER=d4h zZ)Q(a!X{z7!GDP@t>UD?NAIOFKjsS2`avnOuAMWh)mXDFKx5bo;r4Ljm>qIMGusSs zYuf3$UlY8khlAX{otLLYf}4@_nu{wxBHFGCLUvmwQ!^@LqV9SFa2@o>#TwYR0#J= zwYhpcQ@9se{K{JEOMdw!0-O-Pvt5J8!RWgt1wMbotS7>)?hmG9Zq2tA?#jTe(K~;R z)9t%g0Y8R%W^USXFdQ>Eq|K8bM6Nx_Ve3B`7b7NTNg>!00HZN9y1`mA}yiGaT4q@6NFC=FOeWDL$u*1y5R;Yxqq z-v)l+3;ZMdUvNx^GDR3D1ZBrpoa7&Z8V7eNy45RdLCb8$?`0v64~vtp>|?C z-wX>!rc`$YZP#4FPCC7LEQbGXftY4aSrfxgAmgOx86)Jt4>e1XF5V{>6`z%Z!@eD8 zb{pAJV4NwzP$+2?N%l56@df+<3jj|LUx8;;_%#79$$}I6HEd-IxY<$yw`1{llAa%Z zbxzFOe^+ovh{Ar6Um+B_- zMSQehBmr#UiPhrE?fe;YDngvN#7ftI=FhZl_*&U{RXiQ@KDJ60I<{9h>&z;X1t~hD zG%zAx^4UK)6KP(4o z&_RFNJJiNWozlOCl9s5}7$7z$&Qq{{k*5z>qfP7!EP2G7De2N~FO!^%^tp`d?Ozpe z;?=$(*yuzneS7#~3KLlqz1u9+y|GXJc=n>BHU6&U57&Vu3doFs>tF--Fo|?SkqWHS zB6&fhz&8pc+J>7WZe#BT!xvruHGzQc?%7y5N#Y*a47f~68Eg`PsNaeGU321>$A^n& zmtw_(47QJoMKLXR4EH3}&p7gXX0%*kh#=oo@ zyhMwHpw=^Ym1oQFJbCr=iXQp6cIS2a5tn$10tdL82@kw_!LV6$t}?zO!?7ZcA$o)2X=NAl1mB;tI@K zHB=UMspt0Ti-=ZhoGxHN5iHd{F7U38TdZ|KGm@SNBKs!OasXx96dy~f;^QzQGT>S? z#H60J_hdtCd=G~j65xfA%`awlSEz1>&o@s~dKoz&9igIAyet6hA?dWqt`p1SjbQ22 zjY@8zhn}SWmq<{brk)rh6 zgK55JC27>X$4Z9k=(yu%UKIm*WYg;SX7?;ht^+jX3)PzuDx~^o_vFF$wMnG&Q+dSg zN@0J7S^YqPWnKFIwm-y58AFN0vfFg8so=@j>-q2yg4nN0jv?>@lDf5ajq9Ok;M^~E zkNIkYbcJEaSkvv4>*bW&Qx%e|$UUM_WcNi>J|nw0Sz3#Dl{00X_il#MW6icH#}tHG z1faRwvfx>!{R76SW&~Odhn@pA=caL?Hq%&-)9g#OCsp zXL$b3jsG8^zVYvXez%oU!8CqC1l#>+&p{*_?R95$HQ!7_rq;$Cb>V?f;Zfpw8@cWa^u{dw@~d#%PO z#^<_R|A*x&UJPTR(Urzn;gtN3aBav3C`|Z0G=JKmm1o}V8s2PFejQ+aEHz@uzir2m z)>GKhp)lC}CnQf100N#2f%xF{At-`gYj-+@_!~$1_bX7^DAJ2X1Da5=(R$b8y>t*J zvySR|y5rVpqZ?XRpUlJE_)3X zpFCgK7jzUD0p2e>5brX1*+LEuen-ix@EO5xBWCa-XYik}EqOs-+;iI;_U|3+pC6PS z-@0=(g|oAtCc0Y0#BM%v90#cMy-hmf)nnE}C&)r!Ih6*byk=Cn{vD91?&sZGSh^jJ zl+1@)4z(06e(jZn41?ZBAP@tiL?H57>(W!m3UC_iA~)$U8uIOj$;=@!wu}DD-7l@_mQZiIbTbWGQ%!VP zC*bXo38mH?FESdPOZ{8JeLVK2x_l7ZC(2r?-;w(fk$T>3$Z7j$zv6~VRf)yZFGHcp z!(IP}eO)crm4LdByTlZ;b--Da;ar%J<5^W_P80X)R`k5FfgfCcjZEN8RV=Ho zxW3gkMXf7d@7V;>y3_E9kcW2=%a(}wVU&HQ-G{={!?}{_Z^)>z_&DT2D6xXjelY2V z|BlXsTMY{3@TU-$3l2E?8&FhAcuG**w}W3y>}^syD;_{lT_vJwPSwmw4XsIuvU9G@ zYRwrZiHxb(}#5RaJ*EmzicB8_A&@PMJDjebRiB= zJNGKXvD|u6R{k(R-{BM;5D7qR=wiK1C=I5c{8QLIsUd$(IeTOFr`zqo+Kcos!w$A| z<2Tz0ZTzU^ewV?4l-F-Y{=#!-Gn5+)9O?*>x}xy=Em!Kt-9HGHxYc&J4a4wNS{ub_QML=jq+G4ANQ(s)1y2K-B|1P5uIW_gEWUjoK=Dq8e{YTJD% ztKemrOnxX%7w~XHqE8|zTb%Axw_IwwNE0(Rp{+X8nV9BRcf;G)gksoNEWx7vKR$fR z(`LfBn{f0a*%g%G_*_mW`o^4aHg_{*^@hBQt6YMe9A?DxF`JpQKEh+WpZ3S;(a>xg zw&6xx*~y@FmMH{5J3lFSjZ$dZDIn~ygEP$_$B}0y=F*2Kq&*-G`Sq~aV+V= zMA|Tfb-8HZLqQW{^mbyP`|SEOt9m8n&j*(5x1JR_hoU%&rGvPkLC(n|Njk<%7;Y2o ze_e)NKP7k%9&-rzqu;8$F4)f>IfcrSrVO`3R1N_}wQOf%uC&RSd^G2Ylfz0exJs4s z0Or!+DsCiB?;kfyM?$LbjQJWahDm=W{ZV(Gp4p_i?qrvSq1};~!Ko-C@G~4X6`K&g zQK*>>#dGI4xSb{O&cHP)jA%2lm7JFs%?Sc~w8R5fi$b;}LQprO|K++NIeqKU#5mid zXwgB=N0y52!_R5tA!?KUX=@gfV9M$wBtBAF(SfXvRy|DJpZZRoM9o5@vF>A=sQVa> z!|dw?<^6Ec<|~L&*7={k)X_K6yu<$|fdXGJsKyb-OOcC5y%N_&y5`kI37b_VQqK{# zv2a9e=RjR56LQV^F?71Qg9dj@(qZOT31kCZ7T0e7X3w(qRAHm z#=$bwjvDXwPQhgGO&Ho{w6`ydpNM&;fMXXIlSY!&)E>?IK>0rXAS4hTPttgzM*#`8 zF*w8Bk^Xq{sH#DaD*o(M!+ojB1gdEIl`^6KM+~=c8r28~&5=LXpT;#&7)_6sgz+%j zZK1T2fn@iX@*`->m2NwOwdr$1TbV50L*PH5appe@|1Mf&PRGd3eJK(lq< z!3?M`bq5XG?pRa`FWYN656@aC8-(!LaHB<4xMLD_w#r(!FLEe@zLX4_s1^%hZKGX~ z^To-^{7r&E0fRuZ(WdN*TewP?9yG@JT#XOlaT{mVmLhYXi%>3qS?6mE2hF$`%~H>2 z-+kn*J}`5b7Ct2_2j1R7(Jof5wExJtCy|+S+ndGmL0YG)dtI? z)=EFhinBaQ+iA8nyW+Iuh9;)Em6wWNKp#ym>f?xX;Qp4DaJlbWc(`F)twGR)7g5^mm81Y@_Iam@E5f4(a3SWz;kiF;#F%JzS+%P!m$C5Vfj7$uRe1^6(s^v0df}ehG;P_*Kel zwBf$-oO_SEL{#l{#qs=Plqx*jsJ~~(yB=rLGd-}LC!^-cO&H2EbCYAnSShD-cCQ+) zVxRNU;Jk~bUZE4hWYF1R+PeJ`5Flehdv3ZcY0(ty`y~?k8ew{}x}&k?RC83zPNx*lpnxzpr#Yi2h=LM_!147E0VU z1dCsS_n&p9w7@Io@4UNr%!~#IE2ezbpKpF6ec0amEUgXoj1r!z_5W46ZyMLR9GP(# z3j-Idsc+^6k*Sx94I6)KV%yK1QZ?G0nQ{~^6zTgcpU`oB1b?&K=Wy}{B0;j%cxY#q= z^_MKMUDWd8?@-@cW(?1NSj3o4lePOL3aK&u8 zej@OKe2?$I!$tWqF12OpP%xzJBarUK+(6dWza_#cJs*Ahpq+39hS&NOwK<+_<ehnm}tM5>UY+P#Q7z1C#R*ZSlR zd!TU}=r~SvlVBa)9h%oBGJ+w;^M1~30uOV8WXM?-iiksQltB3wO!1T*EUHnsk@)9O zxxo1)J#A0&U4vP@Z-rj6%pT`+c*76ZZ~*& zl`9ahg$Yap$dKN~O@LpF4NEDcbk}g5x^#rPV{ItGhr@)py4#(70kSEAGWHz5nZ1-NI?qT|ovo>BhxHs4*JaVeuhw!|v?nXzXL9zZ zNk{zEIV69LHUdP%kcoa&#IrUS1_d}uc{hDEk(~|fr78CX|6Lw_o<%sp1^Ka>0%Wki z^%L8gJ~W)tx=!a13n)8m=g0-WbYxH?Nl|iP=Xd1SzCRQL1lDPD$-Wj3nnaW+sb(yE zPRRB+9UlT~T@rwdibqQlqz`FgU~SefE4;Ze|juKwA@zP|8?% zt~;EXN|bni?*KtFrzDQnJQ1JHYSQQyPMd%7WzWEPXRwgnIe(VOC-DC|%Q8yf@TTF* zV9%khB?-!H7LXN=h7`fS;;Vi)1U$pH0 z($DeSD}FiuW*e=)AYXbGNLHF*_QMKl3!1~077e+4WU~*K44M|#b)TzK zCb;D5YRWnMzo9~~e2E6LTkj&WskNm-mq{i|MMf)ri`S2dDRQkgY}Fpo9JF+VjL!P? zgTuR{?BSc=zn-J)sWN&NKmjHCvzQX(GXyVC)M~9Gt+N!A z%$}*utrp2No`sVe*w#I~r4M$SE{uYrtFX`|iZc^oAG0rfbq}lhTrvHSMMJ0|h3(i7v&ka^14;0r=Mc96PG`F?q zCP((5;LEx*n{$m3Ktjv+#Gyv9jG#-5Ibk2ro2?J&9LZ`l&JtOmjwq&&F898FLEcbG zNkGk_I868!^75Jcf!Zhvk7QyPOV=h*Hf#?}A^^_OD{5w9%~3TEU9b3v-~9qQvB{cU zhP;;W@P{*(a~v(aGQBPw%z*IHLb@(`GpX7%-dUa;Db4Q>o@78(op5DDLIV{p_w-eG z`7tRxlclX}tr4d`A%BObn;FC@)t|n@Vk>+*&YZi-TbUOt{8QYUWLUyLN)uId@-Xl6 zu~Fsb%k*R@nXh!T8)|Bknafs?b_wmebgX;eU3`S(`Av8T*emM!s0?H@p|_nI&n;I=8PFE(oSE$M69ulM2D2u1ii+cJ4T7EPRX26R%WJRf?FHDE9#Ju?cx>x#~{5ha@+A5%V zA0j5h#UvD=O+hL~mxe%j&lo55n6BTvJv0@V*W}*kGyyGn&wo4b{&7ELGLlwlt1#lv^78!OFT7_WC)5c@7M%2hQcXpabhQyOX)0& zjM!;BB{rl5`xyUwx<=mY3kKKNC=YjXE;Hnh5MeEf>RqWjQp3T1J#nR)DB8}#+-!m! z!mTz4C|WUR`Zaex+>R#Yo&Z1lwA5dDXcoaK!KZYIN@TeY^w36p3)_g)?87aGmg=n5 z#7Pr-eqqX6jbdr0J7}cwc^-Nh%(H#0mO=#ju8c z8n6Xb%lg$9`KM6Z2yJJizv`gdd|o__j5|*+amq`a9e|f6r?HJ|ixB_SD_treb@d08 zynQapN~JAR5X)z{EXu5H%jyEe!CqU-nI18%es0PHRIKCosupF{%-)IO257;Ff!UF> zV~`_NQE@C-sQpazz`gH~n~1~Va^?yGaD%~VBqZqIWdtqL1uXfIb9)`^>B`<`P~u=9|Bm$Rg%N8;y&-usR*Y;Afhojnq!>tNEnA#j{*?arMx0 z{}^qDXLP9eDvm>bi{1-{KKp6*iT~1q2EA)b)NJT0bPKv0OCi>%TfCz7&$`dh=Ow-Q z9UcL~Yu83&19ESj)FYN{l7-_UQ|N_JdH)^+vQDfkk_&e)K{Pwyp{G&ea(po3@jZt{q ze2MHQw4J%Js@`thj*iy1n6|jgg9S5kwoJVAi7f}*+D4;XjQLXgJJ&hK*;S6*sL?5S z2V2P4nRX&JR#oZCiT9*KaDTTXEp zC=35|Xtl5x=k|`5goHhgnS#cmX-=$3uvs^R5)$nrTV{exBpB@4g*Bcq*%VJw*U%NH z3w76}u66nOZ7Dn4Z^IEp#&DE+WLVpbR4iA@tkrNAs((!<53a>iUaDTWVtPIx4ZY_J zg_OQGo{;L<(I_$mP@bMofNH9MModb^U31Pm)EN4y&}AZ{~cJ&;wGnTW+H!c9TblnfYYBBmf}_;Qanemd-fM#L&g zEcH55Q#3ckRoa;EUf8tdM4rgarG8qON;LqTT*z#NLU|eR2Mczmv{vw#*@xl$l0%N* z2N*!}t2&2pHpgyDEp{D;gcT5eoVVAJ-t6|$W1R&{HspvYM^umUwt_!rRUpL&0C)lU z{V(8eK#N=Wj*!G8=k^MIy`+|ejeCgK+oKfxYW)zH>GbmRFHlYLZaQrlK7EA$aOAw< zVo%@#nXj+kdnlnYq7qXZhQurJdrroJb*b-*)%)0a)1V!_&*+oqW}QNV9AG2s@s-pb zj3kthc^^5&ev`agPeKl$2>O+PA=J8T+%j}T<#uMx+fCs*p{TgSO&O8Ykw=sq_U%uF zL6W$awb7T_%KP5%JOv&|@WB&CJKh>8n#OX{RVF?)I8cN&l1DX~S9rj~BM#sLm5(2N zo=K8fL_hJNFUc>Hw!{e3nJQ$L4jt+w{&ur&xbGnraMl=gZ^}8;bk9J&VH~E8Xr!*j*4X81-bia${WHsYnQIdV^ z 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 literal 0 HcmV?d00001 From d034b129d4b75b90050486772cd9fe58aca64f89 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Mon, 9 Sep 2024 15:47:06 +0800 Subject: [PATCH 25/67] update ocm (#190) Signed-off-by: Wei Liu --- .tekton/integration-test.yaml | 2 +- .tekton/unit-test.yaml | 2 +- go.mod | 96 ++++++------ go.sum | 244 ++++++++++++++++-------------- pr_check.sh | 2 +- test/e2e/pkg/serverside_test.go | 116 ++++++++++++++ test/e2e/pkg/suite_test.go | 4 + test/e2e/setup/e2e_setup.sh | 1 + test/integration/resource_test.go | 2 +- 9 files changed, 304 insertions(+), 165 deletions(-) diff --git a/.tekton/integration-test.yaml b/.tekton/integration-test.yaml index ddd61cd3..b4f0a8ec 100644 --- a/.tekton/integration-test.yaml +++ b/.tekton/integration-test.yaml @@ -48,7 +48,7 @@ spec: dnf -y install jq git make # Install golang with a given version - export GOVERSION=1.22.4 + export GOVERSION=1.22.5 curl -O -J https://dl.google.com/go/go$GOVERSION.linux-amd64.tar.gz rm -rf /usr/local/go && tar -C /usr/local -xzf go$GOVERSION.linux-amd64.tar.gz diff --git a/.tekton/unit-test.yaml b/.tekton/unit-test.yaml index 23236283..8b7c98ff 100644 --- a/.tekton/unit-test.yaml +++ b/.tekton/unit-test.yaml @@ -48,7 +48,7 @@ spec: dnf -y install jq git make # Install golang with a given version - export GOVERSION=1.22.4 + export GOVERSION=1.22.5 curl -O -J https://dl.google.com/go/go$GOVERSION.linux-amd64.tar.gz rm -rf /usr/local/go && tar -C /usr/local -xzf go$GOVERSION.linux-amd64.tar.gz diff --git a/go.mod b/go.mod index 1e6b776e..abc7377d 100755 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openshift-online/maestro -go 1.22.0 +go 1.22.5 require ( github.com/Masterminds/squirrel v1.5.3 @@ -17,45 +17,44 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/go-gormigrate/gormigrate/v2 v2.0.0 github.com/golang-jwt/jwt/v4 v4.5.0 - github.com/golang/glog v1.2.0 + github.com/golang/glog v1.2.1 github.com/google/uuid v1.6.0 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/jinzhu/inflection v1.0.0 github.com/lib/pq v1.10.7 github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 - github.com/onsi/ginkgo/v2 v2.17.1 - github.com/onsi/gomega v1.32.0 + github.com/onsi/ginkgo/v2 v2.20.0 + github.com/onsi/gomega v1.34.1 github.com/openshift-online/ocm-common v0.0.0-20240620110211-2ecfa6ec5707 github.com/openshift-online/ocm-sdk-go v0.1.421 github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81 github.com/prometheus/client_golang v1.18.0 github.com/segmentio/ksuid v1.0.2 - github.com/spf13/cobra v1.8.0 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/yaacov/tree-search-language v0.0.0-20190923184055-1c2dad2e354b - golang.org/x/oauth2 v0.16.0 - google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.33.0 + golang.org/x/oauth2 v0.20.0 + google.golang.org/grpc v1.65.0 + google.golang.org/protobuf v1.34.2 gopkg.in/resty.v1 v1.12.0 gorm.io/datatypes v1.2.0 gorm.io/driver/postgres v1.5.0 gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11 - k8s.io/api v0.30.2 - k8s.io/apimachinery v0.30.2 - k8s.io/apiserver v0.30.1 - k8s.io/client-go v0.30.2 - k8s.io/component-base v0.30.2 - k8s.io/klog/v2 v2.120.1 + k8s.io/api v0.30.3 + k8s.io/apimachinery v0.30.3 + k8s.io/apiserver v0.30.3 + k8s.io/client-go v0.30.3 + k8s.io/component-base v0.30.3 + k8s.io/klog/v2 v2.130.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c - open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 + open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8 sigs.k8s.io/yaml v1.4.0 ) require ( - cloud.google.com/go/compute v1.23.3 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr/antlr4 v0.0.0-20200712162734-eb1adaa8a7a6 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect @@ -63,8 +62,8 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991 // indirect github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20231030012137-0836a524e995 // indirect github.com/confluentinc/confluent-kafka-go/v2 v2.3.0 // indirect @@ -75,15 +74,15 @@ require ( github.com/docker/distribution v2.8.1+incompatible // indirect github.com/eclipse/paho.golang v0.11.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -91,10 +90,10 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect + github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -119,7 +118,6 @@ require ( github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/robfig/cron v1.2.0 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/smartystreets/goconvey v1.8.1 // indirect @@ -127,42 +125,42 @@ require ( go.etcd.io/etcd/api/v3 v3.5.10 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect go.etcd.io/etcd/client/v3 v3.5.10 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/sdk v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.18.0 // indirect - google.golang.org/appengine v1.6.8 // indirect + golang.org/x/tools v0.24.0 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/mysql v1.4.7 // indirect - k8s.io/apiextensions-apiserver v0.30.1 // indirect - k8s.io/kms v0.30.1 // indirect - k8s.io/kube-aggregator v0.30.1 // indirect + k8s.io/apiextensions-apiserver v0.30.3 // indirect + k8s.io/kms v0.30.3 // indirect + k8s.io/kube-aggregator v0.30.3 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 // indirect - sigs.k8s.io/controller-runtime v0.18.4 // indirect + sigs.k8s.io/controller-runtime v0.18.5 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/go.sum b/go.sum index 1ab30f89..26273bb9 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -50,15 +48,13 @@ github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgIS github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/bxcodec/faker/v3 v3.2.0 h1:L3cTa9Tptyk0jsF/R6RooDZwxwA8dDi6IWdkIu8jwKo= github.com/bxcodec/faker/v3 v3.2.0/go.mod h1:gF31YgnMSMKgkvl+fyEo1xuSMbEuieyqfeslGYFjneM= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991 h1:3/pjormyqkSjF2GHQehTELZ9oqlER4GrJZiVUIk8Fy8= github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991/go.mod h1:xiar5+gk13WqyAUQ/cpcxcjD1IhLe/PeilSfCdPcfMU= @@ -66,8 +62,7 @@ github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20231030012137-0836a5 github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20231030012137-0836a524e995/go.mod h1:mz9oS2Yhh/S7cvrrsgGMMR+6Shy0ZyL2lDN1sHQO1wE= github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240329120647-e6a74efbacbf h1:91HOb+vxZZQ1rJTJtvhJPRl2qyQa5bqh7lrIYhQSDnQ= github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240329120647-e6a74efbacbf/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/confluentinc/confluent-kafka-go/v2 v2.3.0 h1:icCHutJouWlQREayFwCc7lxDAhws08td+W3/gdqgZts= github.com/confluentinc/confluent-kafka-go/v2 v2.3.0/go.mod h1:/VTy8iEpe6mD9pkCH5BhijlUl8ulUXymKv1Qig5Rgb8= @@ -81,7 +76,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -113,8 +108,10 @@ github.com/eclipse/paho.golang v0.11.0 h1:6Avu5dkkCfcB61/y1vx+XrPQ0oAl4TPYtY0uw3 github.com/eclipse/paho.golang v0.11.0/go.mod h1:rhrV37IEwauUyx8FHrvmXOKo+QRKng5ncoN1vJiJMcs= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -122,8 +119,8 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= @@ -138,8 +135,8 @@ github.com/go-gormigrate/gormigrate/v2 v2.0.0/go.mod h1:YuVJ+D/dNt4HWrThTBnjgZuR github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -155,8 +152,8 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -171,8 +168,9 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2V github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -180,8 +178,14 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -196,6 +200,10 @@ github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvR github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -206,9 +214,10 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -232,13 +241,12 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hokaccha/go-prettyjson v0.0.0-20180920040306-f579f869bbfe/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -397,12 +405,12 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= +github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= -github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= @@ -437,6 +445,7 @@ github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+ github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -451,8 +460,8 @@ github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -477,8 +486,8 @@ github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= @@ -492,7 +501,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -540,24 +548,24 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -585,13 +593,13 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -626,16 +634,17 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -646,8 +655,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -663,7 +672,6 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -674,22 +682,21 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= @@ -704,6 +711,7 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190601110225-0abef6e9ecb8/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -713,8 +721,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -726,30 +734,41 @@ google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEt google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -796,40 +815,41 @@ gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqw honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190531162725-42df64e2171a/go.mod h1:wtc9q0E9zm8PjdRMh29DPlTlCCHVzKDwnkT4GskQVzg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= -k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= -k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= -k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= -k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= -k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8= -k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo= -k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50= -k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs= -k8s.io/component-base v0.30.2 h1:pqGBczYoW1sno8q9ObExUqrYSKhtE5rW3y6gX88GZII= -k8s.io/component-base v0.30.2/go.mod h1:yQLkQDrkK8J6NtP+MGJOws+/PPeEXNpwFixsUI7h/OE= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.30.1 h1:gEIbEeCbFiaN2tNfp/EUhFdGr5/CSj8Eyq6Mkr7cCiY= -k8s.io/kms v0.30.1/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4= -k8s.io/kube-aggregator v0.30.1 h1:ymR2BsxDacTKwzKTuNhGZttuk009c+oZbSeD+IPX5q4= -k8s.io/kube-aggregator v0.30.1/go.mod h1:SFbqWsM6ea8dHd3mPLsZFzJHbjBOS5ykIgJh4znZ5iQ= +k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= +k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= +k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U= +k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4= +k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= +k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/apiserver v0.30.3 h1:QZJndA9k2MjFqpnyYv/PH+9PE0SHhx3hBho4X0vE65g= +k8s.io/apiserver v0.30.3/go.mod h1:6Oa88y1CZqnzetd2JdepO0UXzQX4ZnOekx2/PtEjrOg= +k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= +k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= +k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s= +k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kms v0.30.3 h1:NLg+oN45S2Y3U0WiLRzbS61AY/XrS5JBMZp531Z+Pho= +k8s.io/kms v0.30.3/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4= +k8s.io/kube-aggregator v0.30.3 h1:hy5zfQ7p6BuJgc/XtGp3GBh2MPfOj6b1n3raKKMHOQE= +k8s.io/kube-aggregator v0.30.3/go.mod h1:2SP0IckvQoOwwZN8lmtWUnTZTgIpwOWvidWtxyqLwuk= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c h1:gYfgkX/U6fv2d3Ly8D6N1GM9zokORupLSgCxx791zZw= open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= -open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33 h1:7uPjyn1x25QZIzfZqeSFfZdNrzc2hlHm6t/JKYKu9fI= -open-cluster-management.io/ocm v0.13.1-0.20240618054845-e2a7b9e78b33/go.mod h1:KzUwhPZAg6Wq+4xRu10fVVpqNADyz5CtRW4ziqIC2z4= +open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff h1:nGP34ECvH6G8ihcF0Q6ZzpYGjvRrJ/yOcj1Dc3z/H48= +open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff/go.mod h1:bt8jy8oaXSTTlv6RtRSz4Ea8II15SH1PZJZs34ZWOU4= open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8 h1:2dOKe8kj2niAZMlc75NSI/CIkosNNt/Kqyau7ZH4DwM= open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8/go.mod h1:mHGre2DnTfV5gLgCWr+byBqKqTuf5Yzx/EtSSJ2EiGE= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= -sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= -sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= +sigs.k8s.io/controller-runtime v0.18.5/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 h1:PFWFSkpArPNJxFX4ZKWAk9NSeRoZaXschn+ULa4xVek= diff --git a/pr_check.sh b/pr_check.sh index 7074fe72..98899c3f 100755 --- a/pr_check.sh +++ b/pr_check.sh @@ -18,7 +18,7 @@ function cleanUp { } trap cleanUp EXIT -test -f go1.22.4.linux-amd64.tar.gz || curl -O -J https://dl.google.com/go/go1.22.4.linux-amd64.tar.gz +test -f go1.22.5.linux-amd64.tar.gz || curl -O -J https://dl.google.com/go/go1.22.5.linux-amd64.tar.gz podman build -t "$IMAGE_NAME" -f Dockerfile.test . diff --git a/test/e2e/pkg/serverside_test.go b/test/e2e/pkg/serverside_test.go index ed07f6c6..d753bc2d 100644 --- a/test/e2e/pkg/serverside_test.go +++ b/test/e2e/pkg/serverside_test.go @@ -12,7 +12,10 @@ import ( "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/api/openapi" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/rand" workv1 "open-cluster-management.io/api/work/v1" @@ -111,4 +114,117 @@ var _ = Describe("Server Side Apply", Ordered, Label("e2e-tests-serverside-apply Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) }) + + It("Apply a nested work with SSA", func() { + workName := fmt.Sprintf("ssa-work-%s", rand.String(5)) + nestedWorkName := fmt.Sprintf("nested-work-%s", rand.String(5)) + nestedWorkNamespace := "default" + + work := NewNestedManifestWork(nestedWorkNamespace, workName, nestedWorkName) + _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + // make sure the nested work is created + Eventually(func() error { + _, err := kubeWorkClient.WorkV1().ManifestWorks(nestedWorkNamespace).Get(ctx, nestedWorkName, metav1.GetOptions{}) + if err != nil { + return err + } + + return nil + }, 30*time.Second, time.Second).ShouldNot(HaveOccurred()) + + // make sure the nested work is not updated + Consistently(func() error { + nestedWork, err := kubeWorkClient.WorkV1().ManifestWorks(nestedWorkNamespace).Get(ctx, nestedWorkName, metav1.GetOptions{}) + if err != nil { + return err + } + + if nestedWork.Generation != 1 { + return fmt.Errorf("nested work generation is changed to %d", nestedWork.Generation) + } + + return nil + }, 1*time.Minute, 1*time.Second).Should(BeNil()) + + err = workClient.ManifestWorks(consumer.Name).Delete(ctx, workName, metav1.DeleteOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + }) }) + +func NewNestedManifestWork(nestedWorkNamespace, name, nestedWorkName string) *workv1.ManifestWork { + nestedWork := &workv1.ManifestWork{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "work.open-cluster-management.io/v1", + Kind: "ManifestWork", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: nestedWorkName, + Namespace: nestedWorkNamespace, + }, + Spec: workv1.ManifestWorkSpec{ + Workload: workv1.ManifestsTemplate{ + Manifests: []workv1.Manifest{{ + RawExtension: runtime.RawExtension{ + Object: &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "cm-test", + Namespace: "default", + }, + Data: map[string]string{ + "some": "data", + }, + }, + }, + }}, + }, + }, + } + + manifest := workv1.Manifest{} + manifest.Object = nestedWork + + return &workv1.ManifestWork{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: workv1.ManifestWorkSpec{ + Workload: workv1.ManifestsTemplate{ + Manifests: []workv1.Manifest{manifest}, + }, + ManifestConfigs: []workv1.ManifestConfigOption{ + { + ResourceIdentifier: workv1.ResourceIdentifier{ + Group: "work.open-cluster-management.io", + Resource: "manifestworks", + Name: nestedWorkName, + Namespace: nestedWorkNamespace, + }, + UpdateStrategy: &workv1.UpdateStrategy{ + Type: workv1.UpdateStrategyTypeServerSideApply, + ServerSideApply: &workv1.ServerSideApplyConfig{ + Force: true, + FieldManager: "maestro-agent", + }, + }, + FeedbackRules: []workv1.FeedbackRule{ + { + Type: workv1.JSONPathsType, + JsonPaths: []workv1.JsonPath{ + { + Name: "status", + Path: ".status", + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/test/e2e/pkg/suite_test.go b/test/e2e/pkg/suite_test.go index 3792bbee..0af54542 100644 --- a/test/e2e/pkg/suite_test.go +++ b/test/e2e/pkg/suite_test.go @@ -20,6 +20,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" + workclientset "open-cluster-management.io/api/client/work/clientset/versioned" workv1client "open-cluster-management.io/api/client/work/clientset/versioned/typed/work/v1" grpcoptions "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc" @@ -45,6 +46,7 @@ var ( cancel context.CancelFunc ctx context.Context grpcCertDir string + kubeWorkClient workclientset.Interface ) func TestE2E(t *testing.T) { @@ -95,6 +97,8 @@ var _ = BeforeSuite(func() { Expect(err).To(Succeed()) consumer.ClientSet, err = kubernetes.NewForConfig(restConfig) Expect(err).To(Succeed()) + kubeWorkClient, err = workclientset.NewForConfig(restConfig) + Expect(err).To(Succeed()) Expect(consumer.Name).NotTo(BeEmpty(), "consumer name is not provided") grpcCertSrt, err := consumer.ClientSet.CoreV1().Secrets("maestro").Get(ctx, "maestro-grpc-cert", metav1.GetOptions{}) diff --git a/test/e2e/setup/e2e_setup.sh b/test/e2e/setup/e2e_setup.sh index bd966061..8ea67bd7 100755 --- a/test/e2e/setup/e2e_setup.sh +++ b/test/e2e/setup/e2e_setup.sh @@ -71,6 +71,7 @@ kubectl get pod -A kubectl apply -f ./test/e2e/setup/service-ca-crds kubectl $1 create ns openshift-config-managed kubectl $1 apply -f ./test/e2e/setup/service-ca/ +kubectl apply -f https://raw.githubusercontent.com/open-cluster-management-io/api/release-0.14/work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml # 4. deploy maestro into maestro namespace export ENABLE_JWT=false diff --git a/test/integration/resource_test.go b/test/integration/resource_test.go index 5e9d86ce..3a5cb24d 100755 --- a/test/integration/resource_test.go +++ b/test/integration/resource_test.go @@ -212,7 +212,7 @@ func TestResourcePostWithoutName(t *testing.T) { Expect(*resource.Name).To(Equal(*resource.Id)) Eventually(func() error { - newRes, err := resourceService.List(types.ListOptions{ClusterName: clusterName}) + newRes, err := resourceService.List(types.ListOptions{ClusterName: clusterName, CloudEventsDataType: payload.ManifestEventDataType}) if err != nil { return err } From 9dd7f8e5f18b7522d315826c2333b6ab250c03f7 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Wed, 11 Sep 2024 10:27:02 +0800 Subject: [PATCH 26/67] ensure deletion event have different id and time. (#188) Signed-off-by: morvencao --- pkg/client/cloudevents/bundle_codec.go | 7 +++++++ pkg/client/cloudevents/codec.go | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/pkg/client/cloudevents/bundle_codec.go b/pkg/client/cloudevents/bundle_codec.go index 4dddabc8..6450d3b8 100644 --- a/pkg/client/cloudevents/bundle_codec.go +++ b/pkg/client/cloudevents/bundle_codec.go @@ -2,9 +2,11 @@ package cloudevents import ( "fmt" + "time" cloudevents "github.com/cloudevents/sdk-go/v2" cloudeventstypes "github.com/cloudevents/sdk-go/v2/types" + "github.com/google/uuid" cegeneric "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" workpayload "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" @@ -36,6 +38,11 @@ func (codec *BundleCodec) Encode(source string, eventType cetypes.CloudEventsTyp evt.SetExtension(cetypes.ExtensionClusterName, res.ConsumerName) if !res.GetDeletionTimestamp().IsZero() { + // in the deletion case, the event ID and time remain unchanged in storage. + // set the event ID and time before publishing, so the agent can identify the deletion event. + evt.SetID(uuid.New().String()) + evt.SetTime(time.Now()) + // set deletion timestamp extension evt.SetExtension(cetypes.ExtensionDeletionTimestamp, res.GetDeletionTimestamp().Time) } diff --git a/pkg/client/cloudevents/codec.go b/pkg/client/cloudevents/codec.go index bb3ad50a..23e787e1 100644 --- a/pkg/client/cloudevents/codec.go +++ b/pkg/client/cloudevents/codec.go @@ -2,9 +2,11 @@ package cloudevents import ( "fmt" + "time" cloudevents "github.com/cloudevents/sdk-go/v2" cloudeventstypes "github.com/cloudevents/sdk-go/v2/types" + "github.com/google/uuid" cegeneric "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" workpayload "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" @@ -36,6 +38,11 @@ func (codec *Codec) Encode(source string, eventType cetypes.CloudEventsType, res evt.SetExtension(cetypes.ExtensionClusterName, res.ConsumerName) if !res.GetDeletionTimestamp().IsZero() { + // in the deletion case, the event ID and time remain unchanged in storage. + // set the event ID and time before publishing, so the agent can identify the deletion event. + evt.SetID(uuid.New().String()) + evt.SetTime(time.Now()) + // set deletion timestamp extension evt.SetExtension(cetypes.ExtensionDeletionTimestamp, res.GetDeletionTimestamp().Time) } From 5ccb4ea85d27b63a2962b49e9f6bfde067fd2f0e Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Wed, 11 Sep 2024 14:15:47 +0800 Subject: [PATCH 27/67] support configuration for consistent hash. (#192) Signed-off-by: morvencao --- cmd/maestro/server/pulse_server.go | 3 +- pkg/config/config.go | 2 +- pkg/config/pulse_server.go | 50 +++++++++++++++--- pkg/config/pulse_server_test.go | 83 ++++++++++++++++++++++++++++++ pkg/dispatcher/hash_dispatcher.go | 9 ++-- 5 files changed, 134 insertions(+), 13 deletions(-) create mode 100644 pkg/config/pulse_server_test.go diff --git a/cmd/maestro/server/pulse_server.go b/cmd/maestro/server/pulse_server.go index d606e2fa..24abde0b 100644 --- a/cmd/maestro/server/pulse_server.go +++ b/cmd/maestro/server/pulse_server.go @@ -70,7 +70,8 @@ func NewPulseServer(eventBroadcaster *event.EventBroadcaster) EventServer { case config.SharedSubscriptionType: statusDispatcher = dispatcher.NewNoopDispatcher(dao.NewConsumerDao(&env().Database.SessionFactory), env().Clients.CloudEventsSource) case config.BroadcastSubscriptionType: - statusDispatcher = dispatcher.NewHashDispatcher(env().Config.MessageBroker.ClientID, dao.NewInstanceDao(&env().Database.SessionFactory), dao.NewConsumerDao(&env().Database.SessionFactory), env().Clients.CloudEventsSource) + statusDispatcher = dispatcher.NewHashDispatcher(env().Config.MessageBroker.ClientID, dao.NewInstanceDao(&env().Database.SessionFactory), + dao.NewConsumerDao(&env().Database.SessionFactory), env().Clients.CloudEventsSource, env().Config.PulseServer.ConsistentHashConfig) default: glog.Fatalf("Unsupported subscription type: %s", env().Config.PulseServer.SubscriptionType) } diff --git a/pkg/config/config.go b/pkg/config/config.go index e705e1e6..fbcbd052 100755 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -30,7 +30,7 @@ func NewApplicationConfig() *ApplicationConfig { GRPCServer: NewGRPCServerConfig(), Metrics: NewMetricsConfig(), HealthCheck: NewHealthCheckConfig(), - PulseServer: MewPulseServerConfig(), + PulseServer: NewPulseServerConfig(), Database: NewDatabaseConfig(), MessageBroker: NewMessageBrokerConfig(), OCM: NewOCMConfig(), diff --git a/pkg/config/pulse_server.go b/pkg/config/pulse_server.go index e4d48e0f..3b29b80f 100644 --- a/pkg/config/pulse_server.go +++ b/pkg/config/pulse_server.go @@ -13,15 +13,36 @@ const ( // PulseServerConfig contains the configuration for the maestro pulse server. type PulseServerConfig struct { - PulseInterval int64 `json:"pulse_interval"` - SubscriptionType string `json:"subscription_type"` + PulseInterval int64 `json:"pulse_interval"` + SubscriptionType string `json:"subscription_type"` + ConsistentHashConfig *ConsistentHashConfig `json:"consistent_hash_config"` +} + +// ConsistentHashConfig contains the configuration for the consistent hashing algorithm. +type ConsistentHashConfig struct { + PartitionCount int `json:"partition_count"` + ReplicationFactor int `json:"replication_factor"` + Load float64 `json:"load"` } // NewPulseServerConfig creates a new PulseServerConfig with default 15 second pulse interval. -func MewPulseServerConfig() *PulseServerConfig { +func NewPulseServerConfig() *PulseServerConfig { return &PulseServerConfig{ - PulseInterval: 15, - SubscriptionType: "shared", + PulseInterval: 15, + SubscriptionType: "shared", + ConsistentHashConfig: NewConsistentHashConfig(), + } +} + +// NewConsistentHashConfig creates a new ConsistentHashConfig with default values. +// - PartitionCount: 7 +// - ReplicationFactor: 20 +// - Load: 1.25 +func NewConsistentHashConfig() *ConsistentHashConfig { + return &ConsistentHashConfig{ + PartitionCount: 7, + ReplicationFactor: 20, + Load: 1.25, } } @@ -31,11 +52,26 @@ func MewPulseServerConfig() *PulseServerConfig { // - "subscription-type" specifies the subscription type for resource status updates from message broker, either "shared" or "broadcast". // "shared" subscription type uses MQTT feature to ensure only one Maestro instance receives resource status messages. // "broadcast" subscription type will make all Maestro instances to receive resource status messages and hash the message to determine which instance should process it. +// If subscription type is "broadcast", ConsistentHashConfig settings can be configured for the hashing algorithm. func (c *PulseServerConfig) AddFlags(fs *pflag.FlagSet) { - fs.Int64Var(&c.PulseInterval, "pulse-interval", c.PulseInterval, "Sets the pulse interval for maestro instances (seconds) to indicate liveness (default: 10 seconds)") - fs.StringVar(&c.SubscriptionType, "subscription-type", c.SubscriptionType, "Sets the subscription type for resource status updates from message broker, Options: \"shared\" (only one instance receives resource status message, MQTT feature ensures exclusivity) or \"broadcast\" (all instances receive messages, hashed to determine processing instance) (default: \"shared\")") + fs.Int64Var(&c.PulseInterval, "pulse-interval", c.PulseInterval, "Sets the pulse interval for maestro instances (seconds) to indicate liveness") + fs.StringVar(&c.SubscriptionType, "subscription-type", c.SubscriptionType, "Sets the subscription type for resource status updates from message broker, Options: \"shared\" (only one instance receives resource status message, MQTT feature ensures exclusivity) or \"broadcast\" (all instances receive messages, hashed to determine processing instance)") + c.ConsistentHashConfig.AddFlags(fs) } func (c *PulseServerConfig) ReadFiles() error { + c.ConsistentHashConfig.ReadFiles() + return nil +} + +// AddFlags configures the ConsistentHashConfig with command line flags. Only take effect when subscription type is "broadcast". +// It allows users to customize the partition count, replication factor, and load for the consistent hashing algorithm. +func (c *ConsistentHashConfig) AddFlags(fs *pflag.FlagSet) { + fs.IntVar(&c.PartitionCount, "consistent-hash-partition-count", c.PartitionCount, "Sets the partition count for consistent hashing algorithm, select a big PartitionCount for more consumers. only take effect when subscription type is \"broadcast\"") + fs.IntVar(&c.ReplicationFactor, "consistent-hash-replication-factor", c.ReplicationFactor, "Sets the replication factor for maestro instances to be replicated on consistent hash ring. only take effect when subscription type is \"broadcast\"") + fs.Float64Var(&c.Load, "consistent-hash-load", c.Load, "Sets the load for consistent hashing algorithm, only take effect when subscription type is \"broadcast\"") +} + +func (c *ConsistentHashConfig) ReadFiles() error { return nil } diff --git a/pkg/config/pulse_server_test.go b/pkg/config/pulse_server_test.go new file mode 100644 index 00000000..803c5dc1 --- /dev/null +++ b/pkg/config/pulse_server_test.go @@ -0,0 +1,83 @@ +package config + +import ( + "reflect" + "testing" + + "github.com/spf13/pflag" +) + +func TestPulseServerConfig(t *testing.T) { + cases := []struct { + name string + input map[string]string + want *PulseServerConfig + }{ + { + name: "default subscription type", + input: map[string]string{}, + want: &PulseServerConfig{ + PulseInterval: 15, + SubscriptionType: "shared", + ConsistentHashConfig: &ConsistentHashConfig{ + PartitionCount: 7, + ReplicationFactor: 20, + Load: 1.25, + }, + }, + }, + { + name: "broadcast subscription type", + input: map[string]string{ + "subscription-type": "broadcast", + }, + want: &PulseServerConfig{ + PulseInterval: 15, + SubscriptionType: "broadcast", + ConsistentHashConfig: &ConsistentHashConfig{ + PartitionCount: 7, + ReplicationFactor: 20, + Load: 1.25, + }, + }, + }, + { + name: "custom consistent hash config", + input: map[string]string{ + "subscription-type": "broadcast", + "consistent-hash-partition-count": "10", + "consistent-hash-replication-factor": "30", + "consistent-hash-load": "1.5", + }, + want: &PulseServerConfig{ + PulseInterval: 15, + SubscriptionType: "broadcast", + ConsistentHashConfig: &ConsistentHashConfig{ + PartitionCount: 10, + ReplicationFactor: 30, + Load: 1.5, + }, + }, + }, + } + + config := NewPulseServerConfig() + pflag.NewFlagSet("test", pflag.ContinueOnError) + fs := pflag.CommandLine + config.AddFlags(fs) + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + // set flags + for key, value := range tc.input { + fs.Set(key, value) + } + if !reflect.DeepEqual(config, tc.want) { + t.Errorf("NewPulseServerConfig() = %v; want %v", config, tc.want) + } + // clear flags + fs.VisitAll(func(f *pflag.Flag) { + fs.Lookup(f.Name).Changed = false + }) + }) + } +} diff --git a/pkg/dispatcher/hash_dispatcher.go b/pkg/dispatcher/hash_dispatcher.go index d618dfcf..6a94c13b 100644 --- a/pkg/dispatcher/hash_dispatcher.go +++ b/pkg/dispatcher/hash_dispatcher.go @@ -11,6 +11,7 @@ import ( mapset "github.com/deckarep/golang-set/v2" "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/client/cloudevents" + "github.com/openshift-online/maestro/pkg/config" "github.com/openshift-online/maestro/pkg/dao" "github.com/openshift-online/maestro/pkg/logger" "k8s.io/apimachinery/pkg/util/wait" @@ -32,7 +33,7 @@ type HashDispatcher struct { consistent *consistent.Consistent } -func NewHashDispatcher(instanceID string, instanceDao dao.InstanceDao, consumerDao dao.ConsumerDao, sourceClient cloudevents.SourceClient) *HashDispatcher { +func NewHashDispatcher(instanceID string, instanceDao dao.InstanceDao, consumerDao dao.ConsumerDao, sourceClient cloudevents.SourceClient, consistentHashingConfig *config.ConsistentHashConfig) *HashDispatcher { return &HashDispatcher{ instanceID: instanceID, instanceDao: instanceDao, @@ -41,9 +42,9 @@ func NewHashDispatcher(instanceID string, instanceDao dao.InstanceDao, consumerD consumerSet: mapset.NewSet[string](), workQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "hash-dispatcher"), consistent: consistent.New(nil, consistent.Config{ - PartitionCount: 7, // consumer IDs are distributed among partitions, select a big PartitionCount for more consumers. - ReplicationFactor: 20, // the numbers for maestro instances to be replicated on consistent hash ring. - Load: 1.25, // Load is used to calculate average load, 1.25 is reasonable for most cases. + PartitionCount: consistentHashingConfig.PartitionCount, + ReplicationFactor: consistentHashingConfig.ReplicationFactor, + Load: consistentHashingConfig.Load, Hasher: hasher{}, }), } From 22436c2bde50241a5c96f6d7699f28b330341028 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Thu, 12 Sep 2024 11:07:08 +0800 Subject: [PATCH 28/67] add basic metrics. (#186) Signed-off-by: morvencao --- cmd/maestro/server/auth_interceptor.go | 14 +- cmd/maestro/server/grpc_server.go | 17 +- cmd/maestro/server/metrics_interceptor.go | 242 ++++++++++++++++++++++ cmd/maestro/server/metrics_middleware.go | 50 ++--- go.mod | 6 +- go.sum | 4 +- pkg/client/cloudevents/source_client.go | 3 + pkg/db/advisory_locks.go | 4 +- pkg/db/metrics_collector.go | 21 +- pkg/services/resource.go | 69 ++++++ test/integration/resource_test.go | 142 ++++++++++++- 11 files changed, 507 insertions(+), 65 deletions(-) create mode 100644 cmd/maestro/server/metrics_interceptor.go diff --git a/cmd/maestro/server/auth_interceptor.go b/cmd/maestro/server/auth_interceptor.go index 892f9e05..1faef6c5 100644 --- a/cmd/maestro/server/auth_interceptor.go +++ b/cmd/maestro/server/auth_interceptor.go @@ -119,20 +119,22 @@ func newAuthUnaryInterceptor(authNType string, authorizer grpcauthorizer.GRPCAut } } -// wrappedStream wraps a grpc.ServerStream associated with an incoming RPC, and +// wrappedAuthStream wraps a grpc.ServerStream associated with an incoming RPC, and // a custom context containing the user and groups derived from the client certificate // specified in the incoming RPC metadata -type wrappedStream struct { +type wrappedAuthStream struct { grpc.ServerStream ctx context.Context } -func (w *wrappedStream) Context() context.Context { +// Context returns the context associated with the stream +func (w *wrappedAuthStream) Context() context.Context { return w.ctx } -func newWrappedStream(ctx context.Context, s grpc.ServerStream) grpc.ServerStream { - return &wrappedStream{s, ctx} +// newWrappedAuthStream creates a new wrappedAuthStream +func newWrappedAuthStream(ctx context.Context, s grpc.ServerStream) grpc.ServerStream { + return &wrappedAuthStream{s, ctx} } // newAuthStreamInterceptor creates a stream interceptor that retrieves the user and groups @@ -167,6 +169,6 @@ func newAuthStreamInterceptor(authNType string, authorizer grpcauthorizer.GRPCAu return fmt.Errorf("unsupported authentication Type %s", authNType) } - return handler(srv, newWrappedStream(newContextWithIdentity(ss.Context(), user, groups), ss)) + return handler(srv, newWrappedAuthStream(newContextWithIdentity(ss.Context(), user, groups), ss)) } } diff --git a/cmd/maestro/server/grpc_server.go b/cmd/maestro/server/grpc_server.go index 6b1f7469..79c21134 100644 --- a/cmd/maestro/server/grpc_server.go +++ b/cmd/maestro/server/grpc_server.go @@ -80,6 +80,11 @@ func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *e MaxVersion: tls.VersionTLS13, } + // add metrics and auth interceptors + grpcServerOptions = append(grpcServerOptions, + grpc.ChainUnaryInterceptor(newMetricsUnaryInterceptor(), newAuthUnaryInterceptor(config.GRPCAuthNType, grpcAuthorizer)), + grpc.ChainStreamInterceptor(newMetricsStreamInterceptor(), newAuthStreamInterceptor(config.GRPCAuthNType, grpcAuthorizer))) + if config.GRPCAuthNType == "mtls" { if len(config.ClientCAFile) == 0 { check(fmt.Errorf("no client CA file specified when using mtls authorization type"), "Can't start gRPC server") @@ -102,17 +107,17 @@ func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *e tlsConfig.ClientCAs = certPool tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert - grpcServerOptions = append(grpcServerOptions, grpc.Creds(credentials.NewTLS(tlsConfig)), - grpc.UnaryInterceptor(newAuthUnaryInterceptor(config.GRPCAuthNType, grpcAuthorizer)), - grpc.StreamInterceptor(newAuthStreamInterceptor(config.GRPCAuthNType, grpcAuthorizer))) + grpcServerOptions = append(grpcServerOptions, grpc.Creds(credentials.NewTLS(tlsConfig))) glog.Infof("Serving gRPC service with mTLS at %s", config.ServerBindPort) } else { - grpcServerOptions = append(grpcServerOptions, grpc.Creds(credentials.NewTLS(tlsConfig)), - grpc.UnaryInterceptor(newAuthUnaryInterceptor(config.GRPCAuthNType, grpcAuthorizer)), - grpc.StreamInterceptor(newAuthStreamInterceptor(config.GRPCAuthNType, grpcAuthorizer))) + grpcServerOptions = append(grpcServerOptions, grpc.Creds(credentials.NewTLS(tlsConfig))) glog.Infof("Serving gRPC service with TLS at %s", config.ServerBindPort) } } else { + // append metrics interceptor + grpcServerOptions = append(grpcServerOptions, + grpc.UnaryInterceptor(newMetricsUnaryInterceptor()), + grpc.StreamInterceptor(newMetricsStreamInterceptor())) // Note: Do not use this in production. glog.Infof("Serving gRPC service without TLS at %s", config.ServerBindPort) } diff --git a/cmd/maestro/server/metrics_interceptor.go b/cmd/maestro/server/metrics_interceptor.go new file mode 100644 index 00000000..a8341578 --- /dev/null +++ b/cmd/maestro/server/metrics_interceptor.go @@ -0,0 +1,242 @@ +package server + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/cloudevents/sdk-go/v2/binding" + "github.com/prometheus/client_golang/prometheus" + "google.golang.org/grpc" + "google.golang.org/grpc/status" + pbv1 "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protobuf/v1" + grpcprotocol "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protocol" +) + +func init() { + // Register the metrics: + RegisterGRPCMetrics() +} + +// NewMetricsUnaryInterceptor creates a unary server interceptor for server metrics. +// Currently supports the Publish method with PublishRequest. +func newMetricsUnaryInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + // extract the type from the method name + methodInfo := strings.Split(info.FullMethod, "/") + if len(methodInfo) != 3 || methodInfo[2] != "Publish" { + return nil, fmt.Errorf("invalid method name: %s", info.FullMethod) + } + t := methodInfo[2] + pubReq, ok := req.(*pbv1.PublishRequest) + if !ok { + return nil, fmt.Errorf("invalid request type for Publish method") + } + // convert the request to cloudevent and extract the source + evt, err := binding.ToEvent(ctx, grpcprotocol.NewMessage(pubReq.Event)) + if err != nil { + return nil, fmt.Errorf("failed to convert to cloudevent: %v", err) + } + source := evt.Source() + grpcCalledCountMetric.WithLabelValues(t, source).Inc() + + grpcMessageReceivedCountMetric.WithLabelValues(t, source).Inc() + startTime := time.Now() + resp, err := handler(ctx, req) + duration := time.Since(startTime).Seconds() + grpcMessageSentCountMetric.WithLabelValues(t, source).Inc() + + // get status code from error + status := statusFromError(err) + code := status.Code() + grpcProcessedCountMetric.WithLabelValues(t, source, code.String()).Inc() + grpcProcessedDurationMetric.WithLabelValues(t, source).Observe(duration) + + return resp, err + } +} + +// wrappedMetricsStream wraps a grpc.ServerStream, capturing the request source +// emitting metrics for the stream interceptor. +type wrappedMetricsStream struct { + t string + source *string + grpc.ServerStream + ctx context.Context +} + +// RecvMsg wraps the RecvMsg method of the embedded grpc.ServerStream. +// It captures the source from the SubscriptionRequest and emits metrics. +func (w *wrappedMetricsStream) RecvMsg(m interface{}) error { + err := w.ServerStream.RecvMsg(m) + subReq, ok := m.(*pbv1.SubscriptionRequest) + if !ok { + return fmt.Errorf("invalid request type for Subscribe method") + } + *w.source = subReq.Source + grpcCalledCountMetric.WithLabelValues(w.t, subReq.Source).Inc() + grpcMessageReceivedCountMetric.WithLabelValues(w.t, subReq.Source).Inc() + + return err +} + +// SendMsg wraps the SendMsg method of the embedded grpc.ServerStream. +func (w *wrappedMetricsStream) SendMsg(m interface{}) error { + err := w.ServerStream.SendMsg(m) + grpcMessageSentCountMetric.WithLabelValues(w.t, *w.source).Inc() + return err +} + +// newWrappedMetricsStream creates a wrappedMetricsStream with the specified type and source reference. +func newWrappedMetricsStream(t string, source *string, ctx context.Context, ss grpc.ServerStream) grpc.ServerStream { + return &wrappedMetricsStream{t, source, ss, ctx} +} + +// newMetricsStreamInterceptor creates a stream server interceptor for server metrics. +// Currently supports the Subscribe method with SubscriptionRequest. +func newMetricsStreamInterceptor() grpc.StreamServerInterceptor { + return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + // extract the type from the method name + if !info.IsServerStream || info.IsClientStream { + return fmt.Errorf("invalid stream type for stream method: %s", info.FullMethod) + } + methodInfo := strings.Split(info.FullMethod, "/") + if len(methodInfo) != 3 || methodInfo[2] != "Subscribe" { + return fmt.Errorf("invalid method name for stream method: %s", info.FullMethod) + } + t := methodInfo[2] + source := "" + // create a wrapped stream to capture the source and emit metrics + wrappedMetricsStream := newWrappedMetricsStream(t, &source, stream.Context(), stream) + err := handler(srv, wrappedMetricsStream) + + // get status code from error + status := statusFromError(err) + code := status.Code() + grpcProcessedCountMetric.WithLabelValues(t, source, code.String()).Inc() + + return err + } +} + +// statusFromError returns a grpc status. If the error code is neither a valid grpc status +// nor a context error, codes.Unknown will be set. +func statusFromError(err error) *status.Status { + s, ok := status.FromError(err) + // Mirror what the grpc server itself does, i.e. also convert context errors to status + if !ok { + s = status.FromContextError(err) + } + return s +} + +// Subsystem used to define the metrics: +const grpcMetricsSubsystem = "grpc_server" + +// Names of the labels added to metrics: +const ( + grpcMetricsTypeLabel = "type" + grpcMetricsSourceLabel = "source" + grpcMetricsCodeLabel = "code" +) + +// grpcMetricsLabels - Array of labels added to metrics: +var grpcMetricsLabels = []string{ + grpcMetricsTypeLabel, + grpcMetricsSourceLabel, +} + +// grpcMetricsAllLabels - Array of all labels added to metrics: +var grpcMetricsAllLabels = []string{ + grpcMetricsTypeLabel, + grpcMetricsSourceLabel, + grpcMetricsCodeLabel, +} + +// Names of the metrics: +const ( + calledCountMetric = "called_total" + processedCountMetric = "processed_total" + processedDurationMetric = "processed_duration_seconds" + messageReceivedCountMetric = "message_received_total" + messageSentCountMetric = "message_sent_total" +) + +// Register the metrics: +func RegisterGRPCMetrics() { + prometheus.MustRegister(grpcCalledCountMetric) + prometheus.MustRegister(grpcProcessedCountMetric) + prometheus.MustRegister(grpcProcessedDurationMetric) + prometheus.MustRegister(grpcMessageReceivedCountMetric) + prometheus.MustRegister(grpcMessageSentCountMetric) +} + +// Unregister the metrics: +func UnregisterGRPCMetrics() { + prometheus.Unregister(grpcCalledCountMetric) + prometheus.Unregister(grpcProcessedCountMetric) + prometheus.Unregister(grpcProcessedDurationMetric) + prometheus.Unregister(grpcMessageReceivedCountMetric) + prometheus.Unregister(grpcMessageSentCountMetric) +} + +// Reset the metrics: +func ResetGRPCMetrics() { + grpcCalledCountMetric.Reset() + grpcProcessedCountMetric.Reset() + grpcProcessedDurationMetric.Reset() + grpcMessageReceivedCountMetric.Reset() + grpcMessageSentCountMetric.Reset() +} + +// Description of the gRPC called count metric: +var grpcCalledCountMetric = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: grpcMetricsSubsystem, + Name: calledCountMetric, + Help: "Total number of RPCs called on the server.", + }, + grpcMetricsLabels, +) + +// Description of the gRPC processed count metric: +var grpcProcessedCountMetric = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: grpcMetricsSubsystem, + Name: processedCountMetric, + Help: "Total number of RPCs processed on the server, regardless of success or failure.", + }, + grpcMetricsAllLabels, +) + +// Description of the gRPC processed duration metric: +var grpcProcessedDurationMetric = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Subsystem: grpcMetricsSubsystem, + Name: processedDurationMetric, + Help: "Histogram of the duration of RPCs processed on the server.", + Buckets: prometheus.DefBuckets, + }, + grpcMetricsLabels, +) + +// Description of the gRPC message received count metric: +var grpcMessageReceivedCountMetric = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: grpcMetricsSubsystem, + Name: messageReceivedCountMetric, + Help: "Total number of messages received on the server from agent and client.", + }, + grpcMetricsLabels, +) + +// Description of the gRPC message sent count metric: +var grpcMessageSentCountMetric = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: grpcMetricsSubsystem, + Name: messageSentCountMetric, + Help: "Total number of messages sent by the server to agent and client.", + }, + grpcMetricsLabels, +) diff --git a/cmd/maestro/server/metrics_middleware.go b/cmd/maestro/server/metrics_middleware.go index 448593f1..517a188a 100755 --- a/cmd/maestro/server/metrics_middleware.go +++ b/cmd/maestro/server/metrics_middleware.go @@ -58,6 +58,12 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +func init() { + // Register the metrics: + prometheus.MustRegister(requestCountMetric) + prometheus.MustRegister(requestDurationMetric) +} + // MetricsMiddleware creates a new handler that collects metrics for the requests processed by the // given handler. func MetricsMiddleware(handler http.Handler) http.Handler { @@ -86,9 +92,9 @@ func MetricsMiddleware(handler http.Handler) http.Handler { // Create the set of labels that we will add to all the requests: labels := prometheus.Labels{ - metricsMethodLabel: r.Method, - metricsPathLabel: path, - metricsCodeLabel: strconv.Itoa(wrapper.code), + restMetricsMethodLabel: r.Method, + restMetricsPathLabel: path, + restMetricsCodeLabel: strconv.Itoa(wrapper.code), } // Update the metric containing the number of requests: @@ -112,20 +118,20 @@ var metricsPathVarRE = regexp.MustCompile(`{[^}]*}`) var PathVarSub = "-" // Subsystem used to define the metrics: -const metricsSubsystem = "api_inbound" +const restMetricsSubsystem = "rest_api_inbound" // Names of the labels added to metrics: const ( - metricsMethodLabel = "method" - metricsPathLabel = "path" - metricsCodeLabel = "code" + restMetricsMethodLabel = "method" + restMetricsPathLabel = "path" + restMetricsCodeLabel = "code" ) -// MetricsLabels - Array of labels added to metrics: -var MetricsLabels = []string{ - metricsMethodLabel, - metricsPathLabel, - metricsCodeLabel, +// restMetricsLabels - Array of labels added to metrics: +var restMetricsLabels = []string{ + restMetricsMethodLabel, + restMetricsPathLabel, + restMetricsCodeLabel, } // Names of the metrics: @@ -134,26 +140,20 @@ const ( requestDuration = "request_duration" ) -// MetricsNames - Array of Names of the metrics: -var MetricsNames = []string{ - requestCount, - requestDuration, -} - // Description of the requests count metric: var requestCountMetric = prometheus.NewCounterVec( prometheus.CounterOpts{ - Subsystem: metricsSubsystem, + Subsystem: restMetricsSubsystem, Name: requestCount, Help: "Number of requests served.", }, - MetricsLabels, + restMetricsLabels, ) // Description of the request duration metric: var requestDurationMetric = prometheus.NewHistogramVec( prometheus.HistogramOpts{ - Subsystem: metricsSubsystem, + Subsystem: restMetricsSubsystem, Name: requestDuration, Help: "Request duration in seconds.", Buckets: []float64{ @@ -163,7 +163,7 @@ var requestDurationMetric = prometheus.NewHistogramVec( 30.0, }, }, - MetricsLabels, + restMetricsLabels, ) // metricsResponseWrapper is an extension of the HTTP response writer that remembers the status code, @@ -189,9 +189,3 @@ func (w *metricsResponseWrapper) WriteHeader(code int) { w.code = code w.wrapped.WriteHeader(code) } - -func init() { - // Register the metrics: - prometheus.MustRegister(requestCountMetric) - prometheus.MustRegister(requestDurationMetric) -} diff --git a/go.mod b/go.mod index abc7377d..d94b4a6c 100755 --- a/go.mod +++ b/go.mod @@ -30,6 +30,8 @@ require ( github.com/openshift-online/ocm-sdk-go v0.1.421 github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81 github.com/prometheus/client_golang v1.18.0 + github.com/prometheus/client_model v0.5.0 + github.com/prometheus/common v0.45.0 github.com/segmentio/ksuid v1.0.2 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 @@ -49,7 +51,7 @@ require ( k8s.io/klog/v2 v2.130.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff - open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8 + open-cluster-management.io/sdk-go v0.14.1-0.20240906071839-3e8465851efc sigs.k8s.io/yaml v1.4.0 ) @@ -114,8 +116,6 @@ require ( github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/profile v1.3.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/robfig/cron v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect diff --git a/go.sum b/go.sum index 26273bb9..10b4b829 100644 --- a/go.sum +++ b/go.sum @@ -844,8 +844,8 @@ open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c h1:gYfgkX/U open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff h1:nGP34ECvH6G8ihcF0Q6ZzpYGjvRrJ/yOcj1Dc3z/H48= open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff/go.mod h1:bt8jy8oaXSTTlv6RtRSz4Ea8II15SH1PZJZs34ZWOU4= -open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8 h1:2dOKe8kj2niAZMlc75NSI/CIkosNNt/Kqyau7ZH4DwM= -open-cluster-management.io/sdk-go v0.14.1-0.20240829071054-7bd852f2b2a8/go.mod h1:mHGre2DnTfV5gLgCWr+byBqKqTuf5Yzx/EtSSJ2EiGE= +open-cluster-management.io/sdk-go v0.14.1-0.20240906071839-3e8465851efc h1:m669Deo9FCIbekScJ1xt8jIglaJG3fH17BFrUhpK5ww= +open-cluster-management.io/sdk-go v0.14.1-0.20240906071839-3e8465851efc/go.mod h1:dSRrKrD3zV36l6Pex3pv/ey3xw6NcvyurC4TxbRhM8w= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= diff --git a/pkg/client/cloudevents/source_client.go b/pkg/client/cloudevents/source_client.go index 2245f4f3..0c0bff28 100644 --- a/pkg/client/cloudevents/source_client.go +++ b/pkg/client/cloudevents/source_client.go @@ -41,6 +41,9 @@ func NewSourceClient(sourceOptions *ceoptions.CloudEventsSourceOptions, resource return nil, err } + // register resource resync metrics for cloud event source client + cegeneric.RegisterResourceResyncMetrics() + return &SourceClientImpl{ Codec: codec, BundleCodec: bundleCodec, diff --git a/pkg/db/advisory_locks.go b/pkg/db/advisory_locks.go index 6872640c..5541c1a5 100755 --- a/pkg/db/advisory_locks.go +++ b/pkg/db/advisory_locks.go @@ -19,8 +19,8 @@ type ( const ( Migrations LockType = "migrations" - Resources LockType = "Resources" - ResourceStatus LockType = "ResourceStatus" + Resources LockType = "resources" + ResourceStatus LockType = "resource_status" Events LockType = "events" Instances LockType = "instances" ) diff --git a/pkg/db/metrics_collector.go b/pkg/db/metrics_collector.go index 9f46c64d..288e5049 100755 --- a/pkg/db/metrics_collector.go +++ b/pkg/db/metrics_collector.go @@ -6,6 +6,11 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +func init() { + // Register the metrics for advisory locks + RegisterAdvisoryLockMetrics() +} + type MetricsCollector interface { } @@ -18,8 +23,8 @@ const ( metricsStatusLabel = "status" ) -// MetricsLabels - Array of labels added to metrics: -var MetricsLabels = []string{ +// metricsLabels - Array of labels added to metrics: +var metricsLabels = []string{ metricsTypeLabel, metricsStatusLabel, } @@ -30,12 +35,6 @@ const ( durationMetric = "duration" ) -// MetricsNames - Array of Names of the metrics: -var MetricsNames = []string{ - countMetric, - durationMetric, -} - // Description of the requests count metric: var advisoryLockCountMetric = prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -43,7 +42,7 @@ var advisoryLockCountMetric = prometheus.NewCounterVec( Name: countMetric, Help: "Number of advisory lock requests.", }, - MetricsLabels, + metricsLabels, ) // Description of the request duration metric: @@ -61,7 +60,7 @@ var advisoryLockDurationMetric = prometheus.NewHistogramVec( 10.0, }, }, - MetricsLabels, + metricsLabels, ) // Register the metrics: @@ -76,7 +75,7 @@ func UnregisterAdvisoryLockMetrics() { prometheus.Unregister(advisoryLockDurationMetric) } -// ResetMetricCollectors resets all collectors +// ResetAdvisoryLockMetricsCollectors resets all collectors func ResetAdvisoryLockMetricsCollectors() { advisoryLockCountMetric.Reset() advisoryLockDurationMetric.Reset() diff --git a/pkg/services/resource.go b/pkg/services/resource.go index 68d3d6dc..d596c60e 100755 --- a/pkg/services/resource.go +++ b/pkg/services/resource.go @@ -10,6 +10,7 @@ import ( "github.com/openshift-online/maestro/pkg/dao" "github.com/openshift-online/maestro/pkg/db" logger "github.com/openshift-online/maestro/pkg/logger" + "github.com/prometheus/client_golang/prometheus" cegeneric "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" @@ -19,6 +20,11 @@ import ( "github.com/openshift-online/maestro/pkg/errors" ) +func init() { + // Register the metrics for resource service + RegisterResourceMetrics() +} + type ResourceService interface { Get(ctx context.Context, id string) (*api.Resource, *errors.ServiceError) Create(ctx context.Context, resource *api.Resource) (*api.Resource, *errors.ServiceError) @@ -142,6 +148,15 @@ func (s *sqlResourceService) Update(ctx context.Context, resource *api.Resource) return nil, handleUpdateError("Resource", err) } + // Create the set of labels that we will add to all the resource process: + labels := prometheus.Labels{ + metricsIDLabel: updated.ID, + metricsActionLabel: "update", + } + + // Update the metric containing the number of processed resources: + resourceProcessedCountMetric.With(labels).Inc() + return updated, nil } @@ -215,6 +230,15 @@ func (s *sqlResourceService) UpdateStatus(ctx context.Context, resource *api.Res return nil, false, handleUpdateError("Resource", err) } + // Create the set of labels that we will add to all the resource process: + labels := prometheus.Labels{ + metricsIDLabel: updated.ID, + metricsActionLabel: "update", + } + + // Update the metric containing the number of processed resources: + resourceProcessedCountMetric.With(labels).Inc() + return updated, true, nil } @@ -334,3 +358,48 @@ func (s *sqlResourceService) syncTimestampsFromResourceMeta(resource *api.Resour } } } + +// Subsystem used to define the metrics: +const metricsSubsystem = "resource" + +// Names of the labels added to metrics: +const ( + metricsIDLabel = "id" + metricsActionLabel = "action" +) + +// metricsLabels - Array of labels added to metrics: +var metricsLabels = []string{ + metricsIDLabel, + metricsActionLabel, +} + +// Names of the metrics: +const ( + processedCountMetric = "processed_total" +) + +// Register the metrics: +func RegisterResourceMetrics() { + prometheus.MustRegister(resourceProcessedCountMetric) +} + +// Unregister the metrics: +func UnregisterResourceMetrics() { + prometheus.Unregister(resourceProcessedCountMetric) +} + +// Reset the metrics: +func ResetResourceMetrics() { + resourceProcessedCountMetric.Reset() +} + +// Description of the resource process count metric: +var resourceProcessedCountMetric = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: metricsSubsystem, + Name: processedCountMetric, + Help: "Number of processed resources.", + }, + metricsLabels, +) diff --git a/test/integration/resource_test.go b/test/integration/resource_test.go index 3a5cb24d..08a9e613 100755 --- a/test/integration/resource_test.go +++ b/test/integration/resource_test.go @@ -4,13 +4,17 @@ import ( "context" "encoding/json" "fmt" + "io" "net/http" + "strings" "sync" "testing" "time" "github.com/google/uuid" . "github.com/onsi/gomega" + prommodel "github.com/prometheus/client_model/go" + "github.com/prometheus/common/expfmt" "gopkg.in/resty.v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -365,15 +369,14 @@ func TestResourcePatch(t *testing.T) { openapi.ResourcePatchRequest{Version: &res.Version, Manifest: newRes.Manifest}).Execute() Expect(err).To(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusConflict)) -} -func contains(et api.EventType, events api.EventList) bool { - for _, e := range events { - if e.EventType == et { - return true - } + // check the metrics + families := getServerMetrics(t, "http://localhost:8080/metrics") + labels := []*prommodel.LabelPair{ + {Name: strPtr("id"), Value: resource.Id}, + {Name: strPtr("action"), Value: strPtr("update")}, } - return false + checkServerCounterMetric(t, families, "resource_processed_total", labels, 1.0) } func TestResourcePaging(t *testing.T) { @@ -452,6 +455,15 @@ func TestResourceBundleGet(t *testing.T) { Expect(*resBundle.CreatedAt).To(BeTemporally("~", resourceBundle.CreatedAt)) Expect(*resBundle.UpdatedAt).To(BeTemporally("~", resourceBundle.UpdatedAt)) Expect(*resBundle.Version).To(Equal(resourceBundle.Version)) + + // check the metrics + families := getServerMetrics(t, "http://localhost:8080/metrics") + labels := []*prommodel.LabelPair{ + {Name: strPtr("method"), Value: strPtr("GET")}, + {Name: strPtr("path"), Value: strPtr("/api/maestro/v1/resource-bundles/-")}, + {Name: strPtr("code"), Value: strPtr("200")}, + } + checkServerCounterMetric(t, families, "rest_api_inbound_request_count", labels, 1.0) } func TestResourceBundleListSearch(t *testing.T) { @@ -479,6 +491,15 @@ func TestResourceBundleListSearch(t *testing.T) { Expect(err).NotTo(HaveOccurred(), "Error getting resource bundle list: %v", err) Expect(len(list.Items)).To(Equal(20)) Expect(list.Total).To(Equal(int32(20))) + + // check the metrics + families := getServerMetrics(t, "http://localhost:8080/metrics") + labels := []*prommodel.LabelPair{ + {Name: strPtr("method"), Value: strPtr("GET")}, + {Name: strPtr("path"), Value: strPtr("/api/maestro/v1/resource-bundles")}, + {Name: strPtr("code"), Value: strPtr("200")}, + } + checkServerCounterMetric(t, families, "rest_api_inbound_request_count", labels, 2.0) } func TestUpdateResourceWithRacingRequests(t *testing.T) { @@ -755,6 +776,37 @@ func TestResourceFromGRPC(t *testing.T) { return nil }, 10*time.Second, 1*time.Second).Should(Succeed()) + // check the metrics + families := getServerMetrics(t, "http://localhost:8080/metrics") + labels := []*prommodel.LabelPair{ + {Name: strPtr("type"), Value: strPtr("Publish")}, + {Name: strPtr("source"), Value: strPtr("maestro")}, + } + checkServerCounterMetric(t, families, "grpc_server_called_total", labels, 3.0) + checkServerCounterMetric(t, families, "grpc_server_message_received_total", labels, 3.0) + checkServerCounterMetric(t, families, "grpc_server_message_sent_total", labels, 3.0) + + labels = []*prommodel.LabelPair{ + {Name: strPtr("type"), Value: strPtr("Subscribe")}, + {Name: strPtr("source"), Value: strPtr("maestro")}, + } + checkServerCounterMetric(t, families, "grpc_server_called_total", labels, 1.0) + checkServerCounterMetric(t, families, "grpc_server_message_received_total", labels, 1.0) + //checkServerCounterMetric(t, families, "maestro_grpc_server_msg_sent_total", labels, 2.0) + + labels = []*prommodel.LabelPair{ + {Name: strPtr("type"), Value: strPtr("Publish")}, + {Name: strPtr("source"), Value: strPtr("maestro")}, + {Name: strPtr("code"), Value: strPtr("OK")}, + } + checkServerCounterMetric(t, families, "grpc_server_processed_total", labels, 3.0) + + labels = []*prommodel.LabelPair{ + {Name: strPtr("type"), Value: strPtr("Subscribe")}, + {Name: strPtr("source"), Value: strPtr("maestro")}, + {Name: strPtr("code"), Value: strPtr("OK")}, + } + checkServerCounterMetric(t, families, "grpc_server_processed_total", labels, 0.0) } func TestResourceBundleFromGRPC(t *testing.T) { @@ -921,3 +973,79 @@ func TestResourceBundleFromGRPC(t *testing.T) { Expect(len(list.Items)).To(Equal(1)) Expect(list.Total).To(Equal(int32(1))) } + +func contains(et api.EventType, events api.EventList) bool { + for _, e := range events { + if e.EventType == et { + return true + } + } + return false +} + +func getServerMetrics(t *testing.T, url string) map[string]*prommodel.MetricFamily { + // gather metrics from metrics server from url /metrics + resp, err := http.Get(url) + if err != nil { + t.Errorf("Error getting metrics: %v", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Errorf("Error getting metrics with status code: %v", resp.StatusCode) + } + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Errorf("Error reading metrics: %v", err) + } + parser := expfmt.TextParser{} + // Ensure EOL + reader := strings.NewReader(strings.ReplaceAll(string(body), "\r\n", "\n")) + families, err := parser.TextToMetricFamilies(reader) + if err != nil { + t.Errorf("Error parsing metrics: %v", err) + } + + return families +} + +func checkServerCounterMetric(t *testing.T, families map[string]*prommodel.MetricFamily, name string, labels []*prommodel.LabelPair, value float64) { + family, ok := families[name] + if !ok { + t.Errorf("Metric %s not found", name) + } + metricValue := 0.0 + metrics := family.GetMetric() + for _, metric := range metrics { + metricLabels := metric.GetLabel() + if !compareMetricLabels(labels, metricLabels) { + continue + } + metricValue += *metric.Counter.Value + } + if metricValue != value { + t.Errorf("Counter metric %s value is %f, expected %f", name, metricValue, value) + } +} + +func compareMetricLabels(labels []*prommodel.LabelPair, metricLabels []*prommodel.LabelPair) bool { + if len(labels) != len(metricLabels) { + return false + } + for _, label := range labels { + match := false + for _, metricLabel := range metricLabels { + if *label.Name == *metricLabel.Name && *label.Value == *metricLabel.Value { + match = true + break + } + } + if !match { + return false + } + } + return true +} + +func strPtr(s string) *string { + return &s +} From ea066c250a002f0cc458711945165591bc9f6d3f Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Thu, 12 Sep 2024 15:44:58 +0800 Subject: [PATCH 29/67] update cloudevent sdk (#194) * update cloudevent sdk Signed-off-by: Wei Liu * update cloudevent sdk Signed-off-by: Wei Liu --------- Signed-off-by: Wei Liu --- go.mod | 12 ++++++------ go.sum | 28 ++++++++++++---------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index d94b4a6c..7845ac49 100755 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/bwmarrin/snowflake v0.3.0 github.com/bxcodec/faker/v3 v3.2.0 github.com/cespare/xxhash v1.1.0 - github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240329120647-e6a74efbacbf + github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240911135016-682f3a9684e4 github.com/deckarep/golang-set/v2 v2.6.0 github.com/docker/go-healthcheck v0.1.0 github.com/evanphx/json-patch v5.9.0+incompatible @@ -51,7 +51,7 @@ require ( k8s.io/klog/v2 v2.130.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff - open-cluster-management.io/sdk-go v0.14.1-0.20240906071839-3e8465851efc + open-cluster-management.io/sdk-go v0.14.1-0.20240912064053-889250d1453e sigs.k8s.io/yaml v1.4.0 ) @@ -67,14 +67,14 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991 // indirect - github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20231030012137-0836a524e995 // indirect + github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20240911135016-682f3a9684e4 // indirect github.com/confluentinc/confluent-kafka-go/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/eclipse/paho.golang v0.11.0 // indirect + github.com/eclipse/paho.golang v0.12.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -96,7 +96,7 @@ require ( github.com/gorilla/css v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect - github.com/imdario/mergo v0.3.13 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect @@ -144,7 +144,7 @@ require ( golang.org/x/sys v0.23.0 // indirect golang.org/x/term v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.24.0 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect diff --git a/go.sum b/go.sum index 10b4b829..97fad408 100644 --- a/go.sum +++ b/go.sum @@ -58,10 +58,10 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991 h1:3/pjormyqkSjF2GHQehTELZ9oqlER4GrJZiVUIk8Fy8= github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991/go.mod h1:xiar5+gk13WqyAUQ/cpcxcjD1IhLe/PeilSfCdPcfMU= -github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20231030012137-0836a524e995 h1:pXyRKZ0T5WoB6X9QnHS5cEyW0Got39bNQIECxGUKVO4= -github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20231030012137-0836a524e995/go.mod h1:mz9oS2Yhh/S7cvrrsgGMMR+6Shy0ZyL2lDN1sHQO1wE= -github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240329120647-e6a74efbacbf h1:91HOb+vxZZQ1rJTJtvhJPRl2qyQa5bqh7lrIYhQSDnQ= -github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240329120647-e6a74efbacbf/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= +github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20240911135016-682f3a9684e4 h1:gOxnzX4wrfMMb1X3Y/gzxthyAKVAHopH5spSc/zpveQ= +github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20240911135016-682f3a9684e4/go.mod h1:s+KZsVZst0bVW6vuKYb8CH49CcSJDO09+ZiIeKzJmqE= +github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240911135016-682f3a9684e4 h1:Ov6mO9A4hHpuTWNeYJgQUI42rHr4AgJIc9BB/N9fzDs= +github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240911135016-682f3a9684e4/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/confluentinc/confluent-kafka-go/v2 v2.3.0 h1:icCHutJouWlQREayFwCc7lxDAhws08td+W3/gdqgZts= @@ -104,8 +104,8 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/eclipse/paho.golang v0.11.0 h1:6Avu5dkkCfcB61/y1vx+XrPQ0oAl4TPYtY0uw3HbQdM= -github.com/eclipse/paho.golang v0.11.0/go.mod h1:rhrV37IEwauUyx8FHrvmXOKo+QRKng5ncoN1vJiJMcs= +github.com/eclipse/paho.golang v0.12.0 h1:EXQFJbJklDnUqW6lyAknMWRhM2NgpHxwrrL8riUmp3Q= +github.com/eclipse/paho.golang v0.12.0/go.mod h1:TSDCUivu9JnoR9Hl+H7sQMcHkejWH2/xKK1NJGtLbIE= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -204,7 +204,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -231,7 +230,6 @@ github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/graphql-go/graphql v0.7.8/go.mod h1:k6yrAYQaSP59DC5UVxbgxESlmVyojThKdORUqGDGmrI= @@ -247,8 +245,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hokaccha/go-prettyjson v0.0.0-20180920040306-f579f869bbfe/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/itchyny/gojq v0.12.7 h1:hYPTpeWfrJ1OT+2j6cvBScbhl0TkdwGM4bc66onUSOQ= @@ -652,7 +650,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= @@ -699,8 +696,8 @@ golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -790,7 +787,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco= @@ -844,8 +840,8 @@ open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c h1:gYfgkX/U open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff h1:nGP34ECvH6G8ihcF0Q6ZzpYGjvRrJ/yOcj1Dc3z/H48= open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff/go.mod h1:bt8jy8oaXSTTlv6RtRSz4Ea8II15SH1PZJZs34ZWOU4= -open-cluster-management.io/sdk-go v0.14.1-0.20240906071839-3e8465851efc h1:m669Deo9FCIbekScJ1xt8jIglaJG3fH17BFrUhpK5ww= -open-cluster-management.io/sdk-go v0.14.1-0.20240906071839-3e8465851efc/go.mod h1:dSRrKrD3zV36l6Pex3pv/ey3xw6NcvyurC4TxbRhM8w= +open-cluster-management.io/sdk-go v0.14.1-0.20240912064053-889250d1453e h1:VZ/zCMMzEulH90BDrlOysS5HBr90J2jXhdXiJk+Ys2c= +open-cluster-management.io/sdk-go v0.14.1-0.20240912064053-889250d1453e/go.mod h1:jCyXPY900UK1n4xwUBWSz27s7lcXN/fhIDF6xu3jIHw= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= From 2ce94611b015306a6651a8c796acba87baf7714e Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Wed, 18 Sep 2024 10:20:15 +0800 Subject: [PATCH 30/67] default orphan delete option for read only update strategy. (#189) * default orphan delete option for read only update strategy. Signed-off-by: morvencao * force deletion option to orphan if update strategy is readonly. Signed-off-by: morvencao --------- Signed-off-by: morvencao --- pkg/api/resource_types.go | 41 ++++++++++++++++++++-------------- pkg/handlers/resource.go | 1 + pkg/handlers/validation.go | 22 ++++++++++++++++++ test/e2e/pkg/resources_test.go | 18 ++++++++++++++- test/factories.go | 6 ++--- 5 files changed, 67 insertions(+), 21 deletions(-) diff --git a/pkg/api/resource_types.go b/pkg/api/resource_types.go index 4b1d8e83..e2c06387 100755 --- a/pkg/api/resource_types.go +++ b/pkg/api/resource_types.go @@ -165,26 +165,11 @@ func EncodeManifest(manifest, deleteOption, updateStrategy map[string]interface{ return nil, nil } - delOption := &workv1.DeleteOption{ - PropagationPolicy: workv1.DeletePropagationPolicyTypeForeground, - } - if len(deleteOption) != 0 { - delOption = &workv1.DeleteOption{} - deleteOptionBytes, err := json.Marshal(deleteOption) - if err != nil { - return nil, fmt.Errorf("failed to marshal deleteOption to json: %v", err) - } - err = json.Unmarshal(deleteOptionBytes, delOption) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal json to deleteOption: %v", err) - } - } - + // default update strategy is ServerSideApply upStrategy := &workv1.UpdateStrategy{ Type: workv1.UpdateStrategyTypeServerSideApply, } if len(updateStrategy) != 0 { - upStrategy = &workv1.UpdateStrategy{} updateStrategyBytes, err := json.Marshal(updateStrategy) if err != nil { return nil, fmt.Errorf("failed to marshal updateStrategy to json: %v", err) @@ -193,7 +178,29 @@ func EncodeManifest(manifest, deleteOption, updateStrategy map[string]interface{ if err != nil { return nil, fmt.Errorf("failed to unmarshal json to updateStrategy: %v", err) } - fmt.Println("upStrategy", upStrategy) + } + + // default delete option is Foreground + delOption := &workv1.DeleteOption{ + PropagationPolicy: workv1.DeletePropagationPolicyTypeForeground, + } + + // set delete option to Orphan if update strategy is ReadOnly + if upStrategy.Type == workv1.UpdateStrategyTypeReadOnly { + delOption = &workv1.DeleteOption{ + PropagationPolicy: workv1.DeletePropagationPolicyTypeOrphan, + } + } else { + if len(deleteOption) != 0 { + deleteOptionBytes, err := json.Marshal(deleteOption) + if err != nil { + return nil, fmt.Errorf("failed to marshal deleteOption to json: %v", err) + } + err = json.Unmarshal(deleteOptionBytes, delOption) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal json to deleteOption: %v", err) + } + } } // create a cloud event with the manifest as the data diff --git a/pkg/handlers/resource.go b/pkg/handlers/resource.go index 501ddc60..555462c9 100755 --- a/pkg/handlers/resource.go +++ b/pkg/handlers/resource.go @@ -35,6 +35,7 @@ func (h resourceHandler) Create(w http.ResponseWriter, r *http.Request) { validateEmpty(&rs, "Id", "id"), validateNotEmpty(&rs, "ConsumerName", "consumer_name"), validateNotEmpty(&rs, "Manifest", "manifest"), + validateDeleteOptionAndUpdateStrategy(&rs), }, func() (interface{}, *errors.ServiceError) { ctx := r.Context() diff --git a/pkg/handlers/validation.go b/pkg/handlers/validation.go index 48f6c6d6..4367c525 100755 --- a/pkg/handlers/validation.go +++ b/pkg/handlers/validation.go @@ -3,6 +3,7 @@ package handlers import ( "reflect" + "github.com/openshift-online/maestro/pkg/api/openapi" "github.com/openshift-online/maestro/pkg/errors" ) @@ -37,3 +38,24 @@ func validateEmpty(i interface{}, fieldName string, field string) validate { return nil } } + +// validateDeleteOptionAndUpdateStrategy validates the delete option and update strategy +// for a resource, to ensure that update strategy ReadOnly is only allowed with delete option Orphan. +func validateDeleteOptionAndUpdateStrategy(rs *openapi.Resource) validate { + return func() *errors.ServiceError { + if rs.DeleteOption != nil && rs.UpdateStrategy != nil { + deleteType, ok := rs.DeleteOption["propagationPolicy"].(string) + if !ok { + return errors.Validation("invalid delete option") + } + updateStrategy, ok := rs.UpdateStrategy["type"].(string) + if !ok { + return errors.Validation("invalid update strategy") + } + if deleteType != "Orphan" && updateStrategy == "ReadOnly" { + return errors.Validation("update strategy ReadOnly is only allowed with delete option Orphan") + } + } + return nil + } +} diff --git a/test/e2e/pkg/resources_test.go b/test/e2e/pkg/resources_test.go index 2ca7aef8..fb190b7c 100644 --- a/test/e2e/pkg/resources_test.go +++ b/test/e2e/pkg/resources_test.go @@ -227,9 +227,16 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("post the resource to the maestro api with readonly updateStrategy", func() { - res := helper.NewReadOnlyAPIResource(consumer.Name, deployName) var resp *http.Response var err error + // post the resource with readonly updateStrategy and foreground delete option should fail + invalidRes := helper.NewReadOnlyAPIResource(consumer.Name, deployName) + invalidRes.DeleteOption = map[string]interface{}{"propagationPolicy": "Foreground"} + resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(invalidRes).Execute() + Expect(err).Should(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusBadRequest)) + + res := helper.NewReadOnlyAPIResource(consumer.Name, deployName) resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) @@ -243,6 +250,15 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { return err } + // ensure the delete option is set to Orphan + deleteType, ok := res.DeleteOption["propagationPolicy"] + if !ok { + return fmt.Errorf("delete option is not set") + } + if deleteType != "Orphan" { + return fmt.Errorf("delete option is not Orphan") + } + statusJSON, err := json.Marshal(res.Status) if err != nil { return err diff --git a/test/factories.go b/test/factories.go index b1ba8678..85a6f97e 100755 --- a/test/factories.go +++ b/test/factories.go @@ -73,9 +73,6 @@ var testReadOnlyManifestJSON = ` "metadata": { "name": "%s", "namespace": "%s" - }, - "update_strategy": { - "type": "ReadOnly" } } ` @@ -125,6 +122,9 @@ func (helper *Helper) NewReadOnlyAPIResource(consumerName, deployName string) op return openapi.Resource{ Manifest: testManifest, ConsumerName: &consumerName, + UpdateStrategy: map[string]interface{}{ + "type": "ReadOnly", + }, } } From 25831ec41a9f3e76ec98ee002eb936c0deb985c1 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Mon, 23 Sep 2024 14:46:40 +0800 Subject: [PATCH 31/67] update go-sdk (#196) Signed-off-by: Wei Liu --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7845ac49..2d0ce953 100755 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( k8s.io/klog/v2 v2.130.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff - open-cluster-management.io/sdk-go v0.14.1-0.20240912064053-889250d1453e + open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index 97fad408..93cc4573 100644 --- a/go.sum +++ b/go.sum @@ -840,8 +840,8 @@ open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c h1:gYfgkX/U open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff h1:nGP34ECvH6G8ihcF0Q6ZzpYGjvRrJ/yOcj1Dc3z/H48= open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff/go.mod h1:bt8jy8oaXSTTlv6RtRSz4Ea8II15SH1PZJZs34ZWOU4= -open-cluster-management.io/sdk-go v0.14.1-0.20240912064053-889250d1453e h1:VZ/zCMMzEulH90BDrlOysS5HBr90J2jXhdXiJk+Ys2c= -open-cluster-management.io/sdk-go v0.14.1-0.20240912064053-889250d1453e/go.mod h1:jCyXPY900UK1n4xwUBWSz27s7lcXN/fhIDF6xu3jIHw= +open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866 h1:nxYrSsYwl9Mq8DuaJ0K98PCpuGsai+AvXbggMfZDCGI= +open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866/go.mod h1:jCyXPY900UK1n4xwUBWSz27s7lcXN/fhIDF6xu3jIHw= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= From 350adc0b070b9de983d5387937f4bd69f35cbe95 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Wed, 9 Oct 2024 11:13:40 +0800 Subject: [PATCH 32/67] enhance log format using zapr logger. (#195) Signed-off-by: morvencao --- Makefile | 4 +- cmd/maestro/agent/cmd.go | 21 +++----- cmd/maestro/environments/framework.go | 50 +++++++++---------- cmd/maestro/main.go | 51 +++++++++++++++----- cmd/maestro/migrate/cmd.go | 8 ++- cmd/maestro/servecmd/cmd.go | 16 +++--- cmd/maestro/server/api_server.go | 9 ++-- cmd/maestro/server/auth_interceptor.go | 10 ++-- cmd/maestro/server/grpc_broker.go | 15 +++--- cmd/maestro/server/grpc_server.go | 19 ++++---- cmd/maestro/server/healthcheck_server.go | 8 +-- cmd/maestro/server/logging/formatter_json.go | 6 +-- cmd/maestro/server/pulse_server.go | 4 +- cmd/maestro/server/server.go | 4 +- go.mod | 3 +- pkg/api/error.go | 10 ++-- pkg/api/metadata.go | 6 +-- pkg/auth/authz_middleware_mock.go | 4 +- pkg/client/grpcauthorizer/kube_authorizer.go | 6 +-- pkg/db/db_session/test.go | 7 ++- pkg/db/migrations.go | 4 +- pkg/errors/errors.go | 5 +- pkg/event/event.go | 6 +-- pkg/logger/logger.go | 16 +++--- templates/service-template-aro-hcp.yml | 8 +-- templates/service-template.yml | 8 +-- test/helper.go | 44 ++++++++--------- test/integration/integration_test.go | 5 +- 28 files changed, 184 insertions(+), 173 deletions(-) diff --git a/Makefile b/Makefile index 4b9a1705..bf261dd8 100755 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ mqtt_password_file=${PWD}/secrets/mqtt.password mqtt_config_file=${PWD}/secrets/mqtt.config # Log verbosity level -glog_v:=10 +klog_v:=10 # Location of the JSON web key set used to verify tokens: jwks_url:=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs @@ -269,7 +269,7 @@ cmds: --local="true" \ --ignore-unknown-parameters="true" \ --param="ENVIRONMENT=$(OCM_ENV)" \ - --param="GLOG_V=$(glog_v)" \ + --param="KLOG_V=$(klog_v)" \ --param="SERVER_REPLICAS=$(SERVER_REPLICAS)" \ --param="DATABASE_HOST=$(db_host)" \ --param="DATABASE_NAME=$(db_name)" \ diff --git a/cmd/maestro/agent/cmd.go b/cmd/maestro/agent/cmd.go index f204449a..bde78ba6 100644 --- a/cmd/maestro/agent/cmd.go +++ b/cmd/maestro/agent/cmd.go @@ -2,16 +2,13 @@ package agent import ( "context" - "flag" "fmt" - "os" "github.com/spf13/cobra" "github.com/spf13/pflag" utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilflag "k8s.io/component-base/cli/flag" "k8s.io/component-base/version" - "k8s.io/klog/v2" ocmfeature "open-cluster-management.io/api/feature" commonoptions "open-cluster-management.io/ocm/pkg/common/options" "open-cluster-management.io/ocm/pkg/features" @@ -38,17 +35,8 @@ func NewAgentCommand() *cobra.Command { cmd.Short = "Start the Maestro Agent" cmd.Long = "Start the Maestro Agent" - // check if the flag is already registered to avoid duplicate flag define error - if flag.CommandLine.Lookup("alsologtostderr") != nil { - flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) - } - - // add klog flags - klog.InitFlags(nil) - - flags := cmd.Flags() + flags := cmd.PersistentFlags() flags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) - flags.AddGoFlagSet(flag.CommandLine) // add common flags // commonOptions.AddFlags(flags) @@ -58,8 +46,11 @@ func NewAgentCommand() *cobra.Command { // add alias flags addFlags(flags) - utilruntime.Must(features.SpokeMutableFeatureGate.Add(ocmfeature.DefaultSpokeWorkFeatureGates)) - utilruntime.Must(features.SpokeMutableFeatureGate.Set(fmt.Sprintf("%s=true", ocmfeature.RawFeedbackJsonString))) + // add pre-run to set feature gates + cmd.PreRun = func(cmd *cobra.Command, args []string) { + utilruntime.Must(features.SpokeMutableFeatureGate.Add(ocmfeature.DefaultSpokeWorkFeatureGates)) + utilruntime.Must(features.SpokeMutableFeatureGate.Set(fmt.Sprintf("%s=true", ocmfeature.RawFeedbackJsonString))) + } return cmd } diff --git a/cmd/maestro/environments/framework.go b/cmd/maestro/environments/framework.go index 110c2d6d..317095f3 100755 --- a/cmd/maestro/environments/framework.go +++ b/cmd/maestro/environments/framework.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/getsentry/sentry-go" - "github.com/golang/glog" "github.com/openshift-online/maestro/pkg/client/cloudevents" "github.com/openshift-online/maestro/pkg/client/grpcauthorizer" "github.com/openshift-online/maestro/pkg/client/ocm" @@ -16,6 +15,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog/v2" "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" ) @@ -76,36 +76,36 @@ func (e *Env) AddFlags(flags *pflag.FlagSet) error { // This should be called after the e.Config has been set appropriately though AddFlags and pasing, done elsewhere // The environment does NOT handle flag parsing func (e *Env) Initialize() error { - glog.Infof("Initializing %s environment", e.Name) + klog.Infof("Initializing %s environment", e.Name) envImpl, found := environments[e.Name] if !found { - glog.Fatalf("Unknown runtime environment: %s", e.Name) + klog.Fatalf("Unknown runtime environment: %s", e.Name) } if err := envImpl.VisitConfig(&e.ApplicationConfig); err != nil { - glog.Fatalf("Failed to visit ApplicationConfig: %s", err) + klog.Fatalf("Failed to visit ApplicationConfig: %s", err) } messages := environment.Config.ReadFiles() if len(messages) != 0 { err := fmt.Errorf("unable to read configuration files:\n%s", strings.Join(messages, "\n")) sentry.CaptureException(err) - glog.Fatalf("Unable to read configuration files:\n%s", strings.Join(messages, "\n")) + klog.Fatalf("Unable to read configuration files:\n%s", strings.Join(messages, "\n")) } // each env will set db explicitly because the DB impl has a `once` init section if err := envImpl.VisitDatabase(&e.Database); err != nil { - glog.Fatalf("Failed to visit Database: %s", err) + klog.Fatalf("Failed to visit Database: %s", err) } if err := envImpl.VisitMessageBroker(&e.MessageBroker); err != nil { - glog.Fatalf("Failed to visit MessageBroker: %s", err) + klog.Fatalf("Failed to visit MessageBroker: %s", err) } e.LoadServices() if err := envImpl.VisitServices(&e.Services); err != nil { - glog.Fatalf("Failed to visit Services: %s", err) + klog.Fatalf("Failed to visit Services: %s", err) } // Load clients after services so that clients can use services @@ -114,7 +114,7 @@ func (e *Env) Initialize() error { return err } if err := envImpl.VisitClients(&e.Clients); err != nil { - glog.Fatalf("Failed to visit Clients: %s", err) + klog.Fatalf("Failed to visit Clients: %s", err) } err = e.InitializeSentry() @@ -129,7 +129,7 @@ func (e *Env) Initialize() error { if _, ok := envImpl.(HandlerVisitor); ok { if err := (envImpl.(HandlerVisitor)).VisitHandlers(&e.Handlers); err != nil { - glog.Fatalf("Failed to visit Handlers: %s", err) + klog.Fatalf("Failed to visit Handlers: %s", err) } } @@ -162,19 +162,19 @@ func (e *Env) LoadClients() error { // Create OCM Authz client if e.Config.OCM.EnableMock { - glog.Infof("Using Mock OCM Authz Client") + klog.Infof("Using Mock OCM Authz Client") e.Clients.OCM, err = ocm.NewClientMock(ocmConfig) } else { e.Clients.OCM, err = ocm.NewClient(ocmConfig) } if err != nil { - glog.Errorf("Unable to create OCM Authz client: %s", err.Error()) + klog.Errorf("Unable to create OCM Authz client: %s", err.Error()) return err } // Create CloudEvents Source client if e.Config.MessageBroker.EnableMock { - glog.Infof("Using Mock CloudEvents Source Client") + klog.Infof("Using Mock CloudEvents Source Client") e.Clients.CloudEventsSource = cloudevents.NewSourceClientMock(e.Services.Resources()) } else { // For gRPC message broker type, Maestro server does not require the source client to publish resources or subscribe to resource status. @@ -182,19 +182,19 @@ func (e *Env) LoadClients() error { _, config, err := generic.NewConfigLoader(e.Config.MessageBroker.MessageBrokerType, e.Config.MessageBroker.MessageBrokerConfig). LoadConfig() if err != nil { - glog.Errorf("Unable to load configuration: %s", err.Error()) + klog.Errorf("Unable to load configuration: %s", err.Error()) return err } cloudEventsSourceOptions, err := generic.BuildCloudEventsSourceOptions(config, e.Config.MessageBroker.ClientID, e.Config.MessageBroker.SourceID) if err != nil { - glog.Errorf("Unable to build cloudevent source options: %s", err.Error()) + klog.Errorf("Unable to build cloudevent source options: %s", err.Error()) return err } e.Clients.CloudEventsSource, err = cloudevents.NewSourceClient(cloudEventsSourceOptions, e.Services.Resources()) if err != nil { - glog.Errorf("Unable to create CloudEvents Source client: %s", err.Error()) + klog.Errorf("Unable to create CloudEvents Source client: %s", err.Error()) return err } } @@ -203,22 +203,22 @@ func (e *Env) LoadClients() error { // Create GRPC authorizer based on configuration if e.Config.GRPCServer.EnableGRPCServer { if e.Config.GRPCServer.GRPCAuthNType == "mock" { - glog.Infof("Using Mock GRPC Authorizer") + klog.Infof("Using Mock GRPC Authorizer") e.Clients.GRPCAuthorizer = grpcauthorizer.NewMockGRPCAuthorizer() } else { kubeConfig, err := clientcmd.BuildConfigFromFlags("", e.Config.GRPCServer.GRPCAuthorizerConfig) if err != nil { - glog.Warningf("Unable to create kube client config: %s", err.Error()) + klog.Warningf("Unable to create kube client config: %s", err.Error()) // fallback to in-cluster config kubeConfig, err = rest.InClusterConfig() if err != nil { - glog.Errorf("Unable to create kube client config: %s", err.Error()) + klog.Errorf("Unable to create kube client config: %s", err.Error()) return err } } kubeClient, err := kubernetes.NewForConfig(kubeConfig) if err != nil { - glog.Errorf("Unable to create kube client: %s", err.Error()) + klog.Errorf("Unable to create kube client: %s", err.Error()) return err } e.Clients.GRPCAuthorizer = grpcauthorizer.NewKubeGRPCAuthorizer(kubeClient) @@ -235,12 +235,12 @@ func (e *Env) InitializeSentry() error { key := e.Config.Sentry.Key url := e.Config.Sentry.URL project := e.Config.Sentry.Project - glog.Infof("Sentry error reporting enabled to %s on project %s", url, project) + klog.Infof("Sentry error reporting enabled to %s on project %s", url, project) options.Dsn = fmt.Sprintf("https://%s@%s/%s", key, url, project) } else { // Setting the DSN to an empty string effectively disables sentry // See https://godoc.org/github.com/getsentry/sentry-go#ClientOptions Dsn - glog.Infof("Disabling Sentry error reporting") + klog.Infof("Disabling Sentry error reporting") options.Dsn = "" } @@ -264,7 +264,7 @@ func (e *Env) InitializeSentry() error { err = sentry.Init(options) if err != nil { - glog.Errorf("Unable to initialize sentry integration: %s", err.Error()) + klog.Errorf("Unable to initialize sentry integration: %s", err.Error()) return err } return nil @@ -273,7 +273,7 @@ func (e *Env) InitializeSentry() error { func (e *Env) Teardown() { if e.Name != TestingEnv { if err := e.Database.SessionFactory.Close(); err != nil { - glog.Fatalf("Unable to close db connection: %s", err.Error()) + klog.Fatalf("Unable to close db connection: %s", err.Error()) } e.Clients.OCM.Close() } @@ -282,7 +282,7 @@ func (e *Env) Teardown() { func setConfigDefaults(flags *pflag.FlagSet, defaults map[string]string) error { for name, value := range defaults { if err := flags.Set(name, value); err != nil { - glog.Errorf("Error setting flag %s: %v", name, err) + klog.Errorf("Error setting flag %s: %v", name, err) return err } } diff --git a/cmd/maestro/main.go b/cmd/maestro/main.go index 15122e6c..5cecb502 100755 --- a/cmd/maestro/main.go +++ b/cmd/maestro/main.go @@ -2,13 +2,17 @@ package main import ( "flag" + "os" + "strconv" - "github.com/golang/glog" - "github.com/spf13/cobra" - + "github.com/go-logr/zapr" "github.com/openshift-online/maestro/cmd/maestro/agent" "github.com/openshift-online/maestro/cmd/maestro/migrate" "github.com/openshift-online/maestro/cmd/maestro/servecmd" + "github.com/spf13/cobra" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "k8s.io/klog/v2" ) // nolint @@ -16,23 +20,44 @@ import ( //go:generate go-bindata -o ../../data/generated/openapi/openapi.go -pkg openapi -prefix ../../openapi/ ../../openapi func main() { - // This is needed to make `glog` believe that the flags have already been parsed, otherwise - // every log messages is prefixed by an error message stating the the flags haven't been - // parsed. - _ = flag.CommandLine.Parse([]string{}) + // check if the glog flag is already registered to avoid duplicate flag define error + if flag.CommandLine.Lookup("alsologtostderr") != nil { + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + } - //pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + // add klog flags + klog.InitFlags(nil) - // Always log to stderr by default - if err := flag.Set("logtostderr", "true"); err != nil { - glog.Infof("Unable to set logtostderr to true") - } + // Set up klog backing logger + cobra.OnInitialize(func() { + // Retrieve log level from klog flags + logLevel, err := strconv.ParseInt(flag.CommandLine.Lookup("v").Value.String(), 10, 8) + if err != nil { + klog.Fatalf("can't parse log level: %v", err) + } + + // Initialize zap logger + zc := zap.NewDevelopmentConfig() + // zap log level is the inverse of klog log level, for more details refer to: + // https://github.com/go-logr/zapr?tab=readme-ov-file#increasing-verbosity + zc.Level = zap.NewAtomicLevelAt(zapcore.Level(0 - logLevel)) + zapLog, err := zc.Build() + if err != nil { + klog.Fatalf("can't initialize zap logger: %v", err) + } + // Set backing logger for klog + klog.SetLogger(zapr.NewLogger(zapLog)) + }) + // Initialize root command rootCmd := &cobra.Command{ Use: "maestro", Long: "maestro is a multi-cluster resources orchestrator for Kubernetes", } + // Add klog flags to root command + rootCmd.PersistentFlags().AddGoFlagSet(flag.CommandLine) + // All subcommands under root migrateCmd := migrate.NewMigrationCommand() serveCmd := servecmd.NewServerCommand() @@ -42,6 +67,6 @@ func main() { rootCmd.AddCommand(migrateCmd, serveCmd, agentCmd) if err := rootCmd.Execute(); err != nil { - glog.Fatalf("error running command: %v", err) + klog.Fatalf("error running command: %v", err) } } diff --git a/cmd/maestro/migrate/cmd.go b/cmd/maestro/migrate/cmd.go index 5ba4fc04..f8cc8e37 100755 --- a/cmd/maestro/migrate/cmd.go +++ b/cmd/maestro/migrate/cmd.go @@ -2,11 +2,10 @@ package migrate import ( "context" - "flag" - "github.com/golang/glog" "github.com/openshift-online/maestro/pkg/db/db_session" "github.com/spf13/cobra" + "k8s.io/klog/v2" "github.com/openshift-online/maestro/pkg/config" "github.com/openshift-online/maestro/pkg/db" @@ -24,18 +23,17 @@ func NewMigrationCommand() *cobra.Command { } dbConfig.AddFlags(cmd.PersistentFlags()) - cmd.PersistentFlags().AddGoFlagSet(flag.CommandLine) return cmd } func runMigration(_ *cobra.Command, _ []string) { err := dbConfig.ReadFiles() if err != nil { - glog.Fatal(err) + klog.Fatal(err) } connection := db_session.NewProdFactory(dbConfig) if err := db.Migrate(connection.New(context.Background())); err != nil { - glog.Fatal(err) + klog.Fatal(err) } } diff --git a/cmd/maestro/servecmd/cmd.go b/cmd/maestro/servecmd/cmd.go index e73c5728..c0f41c30 100755 --- a/cmd/maestro/servecmd/cmd.go +++ b/cmd/maestro/servecmd/cmd.go @@ -6,8 +6,8 @@ import ( "os/signal" "syscall" - "github.com/golang/glog" "github.com/spf13/cobra" + "k8s.io/klog/v2" "github.com/openshift-online/maestro/cmd/maestro/environments" "github.com/openshift-online/maestro/cmd/maestro/server" @@ -23,7 +23,7 @@ func NewServerCommand() *cobra.Command { } err := environments.Environment().AddFlags(cmd.PersistentFlags()) if err != nil { - glog.Fatalf("Unable to add environment flags to serve command: %s", err.Error()) + klog.Fatalf("Unable to add environment flags to serve command: %s", err.Error()) } return cmd @@ -32,7 +32,7 @@ func NewServerCommand() *cobra.Command { func runServer(cmd *cobra.Command, args []string) { err := environments.Environment().Initialize() if err != nil { - glog.Fatalf("Unable to initialize environment: %s", err.Error()) + klog.Fatalf("Unable to initialize environment: %s", err.Error()) } // Create event broadcaster to broadcast resource status update events to subscribers @@ -43,10 +43,10 @@ func runServer(cmd *cobra.Command, args []string) { // For MQTT, create a Pulse server to handle resource spec and status events. var eventServer server.EventServer if environments.Environment().Config.MessageBroker.MessageBrokerType == "grpc" { - glog.Info("Setting up grpc broker") + klog.Info("Setting up grpc broker") eventServer = server.NewGRPCBroker(eventBroadcaster) } else { - glog.Info("Setting up pulse server") + klog.Info("Setting up pulse server") eventServer = server.NewPulseServer(eventBroadcaster) } // Create the servers @@ -64,15 +64,15 @@ func runServer(cmd *cobra.Command, args []string) { <-stopCh // Received SIGTERM or SIGINT signal, shutting down servers gracefully. if err := apiserver.Stop(); err != nil { - glog.Errorf("Failed to stop api server, %v", err) + klog.Errorf("Failed to stop api server, %v", err) } if err := metricsServer.Stop(); err != nil { - glog.Errorf("Failed to stop metrics server, %v", err) + klog.Errorf("Failed to stop metrics server, %v", err) } if err := healthcheckServer.Stop(); err != nil { - glog.Errorf("Failed to stop healthcheck server, %v", err) + klog.Errorf("Failed to stop healthcheck server, %v", err) } }() diff --git a/cmd/maestro/server/api_server.go b/cmd/maestro/server/api_server.go index ddc43044..39a2f108 100755 --- a/cmd/maestro/server/api_server.go +++ b/cmd/maestro/server/api_server.go @@ -15,6 +15,7 @@ import ( gorillahandlers "github.com/gorilla/handlers" sdk "github.com/openshift-online/ocm-sdk-go" "github.com/openshift-online/ocm-sdk-go/authentication" + "k8s.io/klog/v2" "github.com/openshift-online/maestro/cmd/maestro/environments" "github.com/openshift-online/maestro/data/generated/openapi" @@ -144,16 +145,16 @@ func (s apiServer) Serve(listener net.Listener) { } // Serve with TLS - glog.Infof("Serving with TLS at %s", env().Config.HTTPServer.BindPort) + klog.Infof("Serving with TLS at %s", env().Config.HTTPServer.BindPort) err = s.httpServer.ServeTLS(listener, env().Config.HTTPServer.HTTPSCertFile, env().Config.HTTPServer.HTTPSKeyFile) } else { - glog.Infof("Serving without TLS at %s", env().Config.HTTPServer.BindPort) + klog.Infof("Serving without TLS at %s", env().Config.HTTPServer.BindPort) err = s.httpServer.Serve(listener) } // Web server terminated. check(err, "Web server terminated with errors") - glog.Info("Web server terminated") + klog.Info("Web server terminated") } // Listen only start the listener, not the server. @@ -173,7 +174,7 @@ func (s apiServer) Start() { listener, err := s.Listen() if err != nil { - glog.Fatalf("Unable to start API server: %s", err) + klog.Fatalf("Unable to start API server: %s", err) } s.Serve(listener) diff --git a/cmd/maestro/server/auth_interceptor.go b/cmd/maestro/server/auth_interceptor.go index 1faef6c5..c8d042b3 100644 --- a/cmd/maestro/server/auth_interceptor.go +++ b/cmd/maestro/server/auth_interceptor.go @@ -5,7 +5,6 @@ import ( "fmt" "strings" - "github.com/golang/glog" "github.com/openshift-online/maestro/pkg/client/grpcauthorizer" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -13,6 +12,7 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" "google.golang.org/grpc/status" + "k8s.io/klog/v2" ) // Context key type defined to avoid collisions in other pkgs using context @@ -101,13 +101,13 @@ func newAuthUnaryInterceptor(authNType string, authorizer grpcauthorizer.GRPCAut case "token": user, groups, err = identityFromToken(ctx, authorizer) if err != nil { - glog.Errorf("unable to get user and groups from token: %v", err) + klog.Errorf("unable to get user and groups from token: %v", err) return nil, err } case "mtls": user, groups, err = identityFromCertificate(ctx) if err != nil { - glog.Errorf("unable to get user and groups from certificate: %v", err) + klog.Errorf("unable to get user and groups from certificate: %v", err) return nil, err } default: @@ -156,13 +156,13 @@ func newAuthStreamInterceptor(authNType string, authorizer grpcauthorizer.GRPCAu case "token": user, groups, err = identityFromToken(ss.Context(), authorizer) if err != nil { - glog.Errorf("unable to get user and groups from token: %v", err) + klog.Errorf("unable to get user and groups from token: %v", err) return err } case "mtls": user, groups, err = identityFromCertificate(ss.Context()) if err != nil { - glog.Errorf("unable to get user and groups from certificate: %v", err) + klog.Errorf("unable to get user and groups from certificate: %v", err) return err } default: diff --git a/cmd/maestro/server/grpc_broker.go b/cmd/maestro/server/grpc_broker.go index 2275691d..450adc70 100644 --- a/cmd/maestro/server/grpc_broker.go +++ b/cmd/maestro/server/grpc_broker.go @@ -11,7 +11,6 @@ import ( ce "github.com/cloudevents/sdk-go/v2" "github.com/cloudevents/sdk-go/v2/binding" cetypes "github.com/cloudevents/sdk-go/v2/types" - "github.com/golang/glog" "github.com/google/uuid" "google.golang.org/grpc" "google.golang.org/grpc/keepalive" @@ -73,7 +72,7 @@ func NewGRPCBroker(eventBroadcaster *event.EventBroadcaster) EventServer { MaxConnectionAge: config.MaxConnectionAge, })) - glog.Infof("Serving gRPC broker without TLS at %s", config.BrokerBindPort) + klog.Infof("Serving gRPC broker without TLS at %s", config.BrokerBindPort) sessionFactory := env().Database.SessionFactory return &GRPCBroker{ grpcServer: grpc.NewServer(grpcServerOptions...), @@ -89,7 +88,7 @@ func NewGRPCBroker(eventBroadcaster *event.EventBroadcaster) EventServer { // Start starts the gRPC broker func (bkr *GRPCBroker) Start(ctx context.Context) { - glog.Info("Starting gRPC broker") + klog.Info("Starting gRPC broker") lis, err := net.Listen("tcp", bkr.bindAddress) if err != nil { check(fmt.Errorf("failed to listen: %v", err), "Can't start gRPC broker") @@ -119,7 +118,7 @@ func (bkr *GRPCBroker) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return nil, fmt.Errorf("failed to parse cloud event type %s, %v", evt.Type(), err) } - glog.V(4).Infof("receive the event with grpc broker, %s", evt) + klog.V(4).Infof("receive the event with grpc broker, %s", evt) // handler resync request if eventType.Action == types.ResyncRequestAction { @@ -157,7 +156,7 @@ func (bkr *GRPCBroker) register(clusterName string, handler resourceHandler) (st errChan: errChan, } - glog.V(4).Infof("register a subscriber %s (cluster name = %s)", id, clusterName) + klog.V(4).Infof("register a subscriber %s (cluster name = %s)", id, clusterName) return id, errChan } @@ -167,7 +166,7 @@ func (bkr *GRPCBroker) unregister(id string) { bkr.mu.Lock() defer bkr.mu.Unlock() - glog.V(10).Infof("unregister subscriber %s", id) + klog.V(10).Infof("unregister subscriber %s", id) close(bkr.subscribers[id].errChan) delete(bkr.subscribers, id) } @@ -187,7 +186,7 @@ func (bkr *GRPCBroker) Subscribe(subReq *pbv1.SubscriptionRequest, subServer pbv return fmt.Errorf("failed to encode resource %s to cloudevent: %v", res.ID, err) } - glog.V(4).Infof("send the event to spec subscribers, %s", evt) + klog.V(4).Infof("send the event to spec subscribers, %s", evt) // WARNING: don't use "pbEvt, err := pb.ToProto(evt)" to convert cloudevent to protobuf pbEvt := &pbv1.CloudEvent{} @@ -206,7 +205,7 @@ func (bkr *GRPCBroker) Subscribe(subReq *pbv1.SubscriptionRequest, subServer pbv select { case err := <-errChan: - glog.Errorf("unregister subscriber %s, error= %v", subscriberID, err) + klog.Errorf("unregister subscriber %s, error= %v", subscriberID, err) bkr.unregister(subscriberID) return err case <-subServer.Context().Done(): diff --git a/cmd/maestro/server/grpc_server.go b/cmd/maestro/server/grpc_server.go index 79c21134..bde8bdbc 100644 --- a/cmd/maestro/server/grpc_server.go +++ b/cmd/maestro/server/grpc_server.go @@ -12,7 +12,6 @@ import ( ce "github.com/cloudevents/sdk-go/v2" "github.com/cloudevents/sdk-go/v2/binding" cetypes "github.com/cloudevents/sdk-go/v2/types" - "github.com/golang/glog" "github.com/google/uuid" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -108,10 +107,10 @@ func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *e tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert grpcServerOptions = append(grpcServerOptions, grpc.Creds(credentials.NewTLS(tlsConfig))) - glog.Infof("Serving gRPC service with mTLS at %s", config.ServerBindPort) + klog.Infof("Serving gRPC service with mTLS at %s", config.ServerBindPort) } else { grpcServerOptions = append(grpcServerOptions, grpc.Creds(credentials.NewTLS(tlsConfig))) - glog.Infof("Serving gRPC service with TLS at %s", config.ServerBindPort) + klog.Infof("Serving gRPC service with TLS at %s", config.ServerBindPort) } } else { // append metrics interceptor @@ -119,7 +118,7 @@ func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *e grpc.UnaryInterceptor(newMetricsUnaryInterceptor()), grpc.StreamInterceptor(newMetricsStreamInterceptor())) // Note: Do not use this in production. - glog.Infof("Serving gRPC service without TLS at %s", config.ServerBindPort) + klog.Infof("Serving gRPC service without TLS at %s", config.ServerBindPort) } return &GRPCServer{ @@ -134,10 +133,10 @@ func NewGRPCServer(resourceService services.ResourceService, eventBroadcaster *e // Start starts the gRPC server func (svr *GRPCServer) Start() error { - glog.Info("Starting gRPC server") + klog.Info("Starting gRPC server") lis, err := net.Listen("tcp", svr.bindAddress) if err != nil { - glog.Errorf("failed to listen: %v", err) + klog.Errorf("failed to listen: %v", err) return err } pbv1.RegisterCloudEventServiceServer(svr.grpcServer, svr) @@ -175,7 +174,7 @@ func (svr *GRPCServer) Publish(ctx context.Context, pubReq *pbv1.PublishRequest) return nil, fmt.Errorf("failed to parse cloud event type %s, %v", evt.Type(), err) } - glog.V(4).Infof("receive the event with grpc server, %s", evt) + klog.V(4).Infof("receive the event with grpc server, %s", evt) // handler resync request if eventType.Action == types.ResyncRequestAction { @@ -248,7 +247,7 @@ func (svr *GRPCServer) Subscribe(subReq *pbv1.SubscriptionRequest, subServer pbv return fmt.Errorf("failed to encode resource %s to cloudevent: %v", res.ID, err) } - glog.V(4).Infof("send the event to status subscribers, %s", evt) + klog.V(4).Infof("send the event to status subscribers, %s", evt) // WARNING: don't use "pbEvt, err := pb.ToProto(evt)" to convert cloudevent to protobuf pbEvt := &pbv1.CloudEvent{} @@ -267,11 +266,11 @@ func (svr *GRPCServer) Subscribe(subReq *pbv1.SubscriptionRequest, subServer pbv select { case err := <-errChan: - glog.Errorf("unregister client %s, error= %v", clientID, err) + klog.Errorf("unregister client %s, error= %v", clientID, err) svr.eventBroadcaster.Unregister(clientID) return err case <-subServer.Context().Done(): - glog.V(10).Infof("unregister client %s", clientID) + klog.V(10).Infof("unregister client %s", clientID) svr.eventBroadcaster.Unregister(clientID) return nil } diff --git a/cmd/maestro/server/healthcheck_server.go b/cmd/maestro/server/healthcheck_server.go index 601e995a..ed099c1a 100755 --- a/cmd/maestro/server/healthcheck_server.go +++ b/cmd/maestro/server/healthcheck_server.go @@ -7,8 +7,8 @@ import ( "net/http" health "github.com/docker/go-healthcheck" - "github.com/golang/glog" "github.com/gorilla/mux" + "k8s.io/klog/v2" ) var ( @@ -50,14 +50,14 @@ func (s healthCheckServer) Start() { } // Serve with TLS - glog.Infof("Serving HealthCheck with TLS at %s", env().Config.HealthCheck.BindPort) + klog.Infof("Serving HealthCheck with TLS at %s", env().Config.HealthCheck.BindPort) err = s.httpServer.ListenAndServeTLS(env().Config.HTTPServer.HTTPSCertFile, env().Config.HTTPServer.HTTPSKeyFile) } else { - glog.Infof("Serving HealthCheck without TLS at %s", env().Config.HealthCheck.BindPort) + klog.Infof("Serving HealthCheck without TLS at %s", env().Config.HealthCheck.BindPort) err = s.httpServer.ListenAndServe() } check(err, "HealthCheck server terminated with errors") - glog.Infof("HealthCheck server terminated") + klog.Infof("HealthCheck server terminated") } func (s healthCheckServer) Stop() error { diff --git a/cmd/maestro/server/logging/formatter_json.go b/cmd/maestro/server/logging/formatter_json.go index 9d0062cf..4346749a 100755 --- a/cmd/maestro/server/logging/formatter_json.go +++ b/cmd/maestro/server/logging/formatter_json.go @@ -5,7 +5,7 @@ import ( "io" "net/http" - "github.com/golang/glog" + "k8s.io/klog/v2" ) func NewJSONLogFormatter() *jsonLogFormatter { @@ -22,7 +22,7 @@ func (f *jsonLogFormatter) FormatRequestLog(r *http.Request) (string, error) { RequestURI: r.RequestURI, RemoteAddr: r.RemoteAddr, } - if glog.V(10) { + if klog.V(10).Enabled() { jsonlog.Header = r.Header jsonlog.Body = r.Body } @@ -36,7 +36,7 @@ func (f *jsonLogFormatter) FormatRequestLog(r *http.Request) (string, error) { func (f *jsonLogFormatter) FormatResponseLog(info *ResponseInfo) (string, error) { jsonlog := jsonResponseLog{Header: nil, Status: info.Status, Elapsed: info.Elapsed} - if glog.V(10) { + if klog.V(10).Enabled() { jsonlog.Body = string(info.Body[:]) } log, err := json.Marshal(jsonlog) diff --git a/cmd/maestro/server/pulse_server.go b/cmd/maestro/server/pulse_server.go index 24abde0b..97ae42b0 100644 --- a/cmd/maestro/server/pulse_server.go +++ b/cmd/maestro/server/pulse_server.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "github.com/golang/glog" "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/client/cloudevents" "github.com/openshift-online/maestro/pkg/config" @@ -17,6 +16,7 @@ import ( "github.com/openshift-online/maestro/pkg/services" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" "open-cluster-management.io/sdk-go/pkg/cloudevents/work/common" workpayload "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" @@ -73,7 +73,7 @@ func NewPulseServer(eventBroadcaster *event.EventBroadcaster) EventServer { statusDispatcher = dispatcher.NewHashDispatcher(env().Config.MessageBroker.ClientID, dao.NewInstanceDao(&env().Database.SessionFactory), dao.NewConsumerDao(&env().Database.SessionFactory), env().Clients.CloudEventsSource, env().Config.PulseServer.ConsistentHashConfig) default: - glog.Fatalf("Unsupported subscription type: %s", env().Config.PulseServer.SubscriptionType) + klog.Fatalf("Unsupported subscription type: %s", env().Config.PulseServer.SubscriptionType) } sessionFactory := env().Database.SessionFactory return &PulseServer{ diff --git a/cmd/maestro/server/server.go b/cmd/maestro/server/server.go index 44976ca9..5df7dcb9 100755 --- a/cmd/maestro/server/server.go +++ b/cmd/maestro/server/server.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/getsentry/sentry-go" - "github.com/golang/glog" + "k8s.io/klog/v2" "github.com/openshift-online/maestro/cmd/maestro/environments" ) @@ -29,7 +29,7 @@ func removeTrailingSlash(next http.Handler) http.Handler { // Exit on error func check(err error, msg string) { if err != nil && err != http.ErrServerClosed { - glog.Errorf("%s: %s", msg, err) + klog.Errorf("%s: %s", msg, err) sentry.CaptureException(err) sentry.Flush(environments.Environment().Config.Sentry.Timeout) os.Exit(1) diff --git a/go.mod b/go.mod index 2d0ce953..45329a24 100755 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/getsentry/sentry-go v0.20.0 github.com/ghodss/yaml v1.0.0 github.com/go-gormigrate/gormigrate/v2 v2.0.0 + github.com/go-logr/zapr v1.3.0 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/glog v1.2.1 github.com/google/uuid v1.6.0 @@ -36,6 +37,7 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/yaacov/tree-search-language v0.0.0-20190923184055-1c2dad2e354b + go.uber.org/zap v1.27.0 golang.org/x/oauth2 v0.20.0 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 @@ -136,7 +138,6 @@ require ( go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.26.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.28.0 // indirect diff --git a/pkg/api/error.go b/pkg/api/error.go index fcb62a38..7aebc1ef 100755 --- a/pkg/api/error.go +++ b/pkg/api/error.go @@ -7,8 +7,8 @@ import ( "os" "github.com/getsentry/sentry-go" - "github.com/golang/glog" "github.com/openshift-online/maestro/pkg/errors" + "k8s.io/klog/v2" ) // SendNotFound sends a 404 response with some details about the non existing resource. @@ -40,7 +40,7 @@ func SendNotFound(w http.ResponseWriter, r *http.Request) { _, err = w.Write(data) if err != nil { err = fmt.Errorf("cannot send response body for request '%s'", r.URL.Path) - glog.Error(err) + klog.Error(err) sentry.CaptureException(err) return } @@ -62,7 +62,7 @@ func SendUnauthorized(w http.ResponseWriter, r *http.Request, message string) { _, err = w.Write(data) if err != nil { err = fmt.Errorf("cannot send response body for request '%s'", r.URL.Path) - glog.Error(err) + klog.Error(err) sentry.CaptureException(err) return } @@ -78,7 +78,7 @@ func SendPanic(w http.ResponseWriter, r *http.Request) { r.URL.Path, err.Error(), ) - glog.Error(err) + klog.Error(err) sentry.CaptureException(err) } } @@ -109,7 +109,7 @@ func init() { "cannot create the panic error body: %s", err.Error(), ) - glog.Error(err) + klog.Error(err) sentry.CaptureException(err) os.Exit(1) } diff --git a/pkg/api/metadata.go b/pkg/api/metadata.go index 09f026bd..a725008f 100755 --- a/pkg/api/metadata.go +++ b/pkg/api/metadata.go @@ -24,7 +24,7 @@ import ( "net/http" "github.com/getsentry/sentry-go" - "github.com/golang/glog" + "k8s.io/klog/v2" ) // SendAPI sends API documentation response. @@ -55,7 +55,7 @@ func SendAPI(w http.ResponseWriter, r *http.Request) { _, err = w.Write(data) if err != nil { err = fmt.Errorf("cannot send response body for request '%s'", r.URL.Path) - glog.Error(err) + klog.Error(err) sentry.CaptureException(err) return } @@ -90,7 +90,7 @@ func SendAPIV1(w http.ResponseWriter, r *http.Request) { // Send the response: _, err = w.Write(data) if err != nil { - glog.Errorf("Can't send response body for request '%s'", r.URL.Path) + klog.Errorf("Can't send response body for request '%s'", r.URL.Path) return } } diff --git a/pkg/auth/authz_middleware_mock.go b/pkg/auth/authz_middleware_mock.go index 5e88ecba..ee9e3797 100755 --- a/pkg/auth/authz_middleware_mock.go +++ b/pkg/auth/authz_middleware_mock.go @@ -3,7 +3,7 @@ package auth import ( "net/http" - "github.com/golang/glog" + "k8s.io/klog/v2" ) type authzMiddlewareMock struct{} @@ -16,7 +16,7 @@ func NewAuthzMiddlewareMock() AuthorizationMiddleware { func (a authzMiddlewareMock) AuthorizeApi(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - glog.V(10).Infof("Mock authz allows / for %q/%q", r.Method, r.URL) + klog.V(10).Infof("Mock authz allows / for %q/%q", r.Method, r.URL) next.ServeHTTP(w, r) }) } diff --git a/pkg/client/grpcauthorizer/kube_authorizer.go b/pkg/client/grpcauthorizer/kube_authorizer.go index 74441ddb..87da1040 100644 --- a/pkg/client/grpcauthorizer/kube_authorizer.go +++ b/pkg/client/grpcauthorizer/kube_authorizer.go @@ -4,11 +4,11 @@ import ( "context" "fmt" - "github.com/golang/glog" authenticationv1 "k8s.io/api/authentication/v1" authorizationv1 "k8s.io/api/authorization/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" ) // KubeGRPCAuthorizer is a gRPC authorizer that uses the Kubernetes RBAC API to authorize requests. @@ -26,7 +26,7 @@ var _ GRPCAuthorizer = &KubeGRPCAuthorizer{} // TokenReview validates the given token and returns the user and groups associated with it. func (k *KubeGRPCAuthorizer) TokenReview(ctx context.Context, token string) (user string, groups []string, err error) { - glog.V(4).Infof("TokenReview: token=%s", token) + klog.V(4).Infof("TokenReview: token=%s", token) tr, err := k.kubeClient.AuthenticationV1().TokenReviews().Create(ctx, &authenticationv1.TokenReview{ Spec: authenticationv1.TokenReviewSpec{ @@ -46,7 +46,7 @@ func (k *KubeGRPCAuthorizer) TokenReview(ctx context.Context, token string) (use // AccessReview checks if the given user or group is allowed to perform the given action on the given resource by making a SubjectAccessReview request. func (k *KubeGRPCAuthorizer) AccessReview(ctx context.Context, action, resourceType, resource, user string, groups []string) (allowed bool, err error) { - glog.V(4).Infof("AccessReview: action=%s, resourceType=%s, resource=%s, user=%s, groups=%s", action, resourceType, resource, user, groups) + klog.V(4).Infof("AccessReview: action=%s, resourceType=%s, resource=%s, user=%s, groups=%s", action, resourceType, resource, user, groups) if user != "" && len(groups) == 0 { return false, fmt.Errorf("both user and groups cannot be specified") } diff --git a/pkg/db/db_session/test.go b/pkg/db/db_session/test.go index 9e24c494..672afe94 100755 --- a/pkg/db/db_session/test.go +++ b/pkg/db/db_session/test.go @@ -6,11 +6,10 @@ import ( "fmt" "time" - "github.com/golang/glog" - "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" + "k8s.io/klog/v2" "github.com/openshift-online/maestro/pkg/config" "github.com/openshift-online/maestro/pkg/db" @@ -50,12 +49,12 @@ func (f *Test) Init(config *config.DatabaseConfig) { // Only the first time once.Do(func() { if err := initDatabase(config, db.Migrate); err != nil { - glog.Errorf("error initializing test database: %s", err) + klog.Errorf("error initializing test database: %s", err) return } if err := resetDB(config); err != nil { - glog.Errorf("error resetting test database: %s", err) + klog.Errorf("error resetting test database: %s", err) return } }) diff --git a/pkg/db/migrations.go b/pkg/db/migrations.go index 77bdbc2e..9f3edfc9 100755 --- a/pkg/db/migrations.go +++ b/pkg/db/migrations.go @@ -4,8 +4,8 @@ import ( "context" "github.com/go-gormigrate/gormigrate/v2" - "github.com/golang/glog" "github.com/openshift-online/maestro/pkg/db/migrations" + "k8s.io/klog/v2" "gorm.io/gorm" ) @@ -30,7 +30,7 @@ func MigrateTo(sessionFactory SessionFactory, migrationID string) { m := newGormigrate(g2) if err := m.MigrateTo(migrationID); err != nil { - glog.Fatalf("Could not migrate: %v", err) + klog.Fatalf("Could not migrate: %v", err) } } diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 35f2101a..5188ca4c 100755 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -5,9 +5,8 @@ import ( "net/http" "strconv" - "github.com/golang/glog" - "github.com/openshift-online/maestro/pkg/api/openapi" + "k8s.io/klog/v2" ) const ( @@ -106,7 +105,7 @@ func New(code ServiceErrorCode, reason string, values ...interface{}) *ServiceEr var err *ServiceError exists, err := Find(code) if !exists { - glog.Errorf("Undefined error code used: %d", code) + klog.Errorf("Undefined error code used: %d", code) err = &ServiceError{ErrorGeneral, "Unspecified error", 500} } diff --git a/pkg/event/event.go b/pkg/event/event.go index 5ac7a56d..f9b24990 100644 --- a/pkg/event/event.go +++ b/pkg/event/event.go @@ -4,9 +4,9 @@ import ( "context" "sync" - "github.com/golang/glog" "github.com/google/uuid" "github.com/openshift-online/maestro/pkg/api" + "k8s.io/klog/v2" ) // resourceHandler is a function that can handle resource status change events. @@ -51,7 +51,7 @@ func (h *EventBroadcaster) Register(source string, handler resourceHandler) (str errChan: errChan, } - glog.V(4).Infof("register a broadcaster client %s (source=%s)", id, source) + klog.V(4).Infof("register a broadcaster client %s (source=%s)", id, source) return id, errChan } @@ -72,7 +72,7 @@ func (h *EventBroadcaster) Broadcast(res *api.Resource) { // Start starts the event broadcaster and waits for events to broadcast. func (h *EventBroadcaster) Start(ctx context.Context) { - glog.Infof("Starting event broadcaster") + klog.Infof("Starting event broadcaster") for { select { diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 19d9c082..32b142b0 100755 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -6,8 +6,8 @@ import ( "strings" "github.com/getsentry/sentry-go" - "github.com/golang/glog" "github.com/openshift-online/maestro/pkg/util" + "k8s.io/klog/v2" ) type OCMLogger interface { @@ -100,7 +100,7 @@ func (l *logger) V(level int32) OCMLogger { // Infof doesn't trigger Sentry error func (l *logger) Infof(format string, args ...interface{}) { prefixed := l.prepareLogPrefixf(format, args...) - glog.V(glog.Level(l.level)).Infof("%s", prefixed) + klog.V(klog.Level(l.level)).Infof("%s", prefixed) } func (l *logger) Extra(key string, value interface{}) OCMLogger { @@ -109,24 +109,24 @@ func (l *logger) Extra(key string, value interface{}) OCMLogger { } func (l *logger) Info(message string) { - l.log(message, sentry.LevelInfo, glog.V(glog.Level(l.level)).Infoln) + l.log(message, sentry.LevelInfo, klog.V(klog.Level(l.level)).Infoln) } func (l *logger) Warning(message string) { - l.log(message, sentry.LevelWarning, glog.Warningln) + l.log(message, sentry.LevelWarning, klog.Warningln) } func (l *logger) Error(message string) { - l.log(message, sentry.LevelError, glog.Errorln) + l.log(message, sentry.LevelError, klog.Errorln) } func (l *logger) Fatal(message string) { - l.log(message, sentry.LevelFatal, glog.Fatalln) + l.log(message, sentry.LevelFatal, klog.Fatalln) } -func (l *logger) log(message string, level sentry.Level, glogFunc func(args ...interface{})) { +func (l *logger) log(message string, level sentry.Level, logFunc func(args ...interface{})) { prefixed := l.prepareLogPrefix(message, l.extra) - glogFunc(prefixed) + logFunc(prefixed) if level != sentry.LevelInfo && level != sentry.LevelWarning { l.captureSentryEvent(level, message) } diff --git a/templates/service-template-aro-hcp.yml b/templates/service-template-aro-hcp.yml index 6a4ec2aa..9859d16f 100755 --- a/templates/service-template-aro-hcp.yml +++ b/templates/service-template-aro-hcp.yml @@ -35,8 +35,8 @@ parameters: displayName: Image tag value: latest -- name: GLOG_V - displayName: GLOG V Level +- name: KLOG_V + displayName: KLOG V Level description: Log verbosity level value: "10" @@ -216,7 +216,7 @@ objects: - --db-name-file=/secrets/db/db.name - --db-sslmode=${DB_SSLMODE} - --alsologtostderr - - -v=${GLOG_V} + - -v=${KLOG_V} containers: - name: service image: ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}:${IMAGE_TAG} @@ -269,7 +269,7 @@ objects: - --http-write-timeout=${HTTP_WRITE_TIMEOUT} - --label-metrics-inclusion-duration=${LABEL_METRICS_INCLUSION_DURATION} - --alsologtostderr - - -v=${GLOG_V} + - -v=${KLOG_V} resources: requests: cpu: ${CPU_REQUEST} diff --git a/templates/service-template.yml b/templates/service-template.yml index 2ae608ca..c116dd27 100755 --- a/templates/service-template.yml +++ b/templates/service-template.yml @@ -44,8 +44,8 @@ parameters: displayName: Image tag value: "7" -- name: GLOG_V - displayName: GLOG V Level +- name: KLOG_V + displayName: KLOG V Level description: Log verbosity level value: "10" @@ -297,7 +297,7 @@ objects: - --db-rootcert=/secrets/rds/db.ca_cert - --db-sslmode=${DB_SSLMODE} - --alsologtostderr - - -v=${GLOG_V} + - -v=${KLOG_V} containers: - name: service image: ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}:${IMAGE_TAG} @@ -369,7 +369,7 @@ objects: - --http-write-timeout=${HTTP_WRITE_TIMEOUT} - --label-metrics-inclusion-duration=${LABEL_METRICS_INCLUSION_DURATION} - --alsologtostderr - - -v=${GLOG_V} + - -v=${KLOG_V} resources: requests: cpu: ${CPU_REQUEST} diff --git a/test/helper.go b/test/helper.go index 8b3e8281..25c9423a 100755 --- a/test/helper.go +++ b/test/helper.go @@ -15,6 +15,7 @@ import ( "github.com/openshift-online/maestro/pkg/controllers" "github.com/openshift-online/maestro/pkg/event" "github.com/openshift-online/maestro/pkg/logger" + "k8s.io/klog/v2" workinformers "open-cluster-management.io/api/client/work/informers/externalversions" workv1informers "open-cluster-management.io/api/client/work/informers/externalversions/work/v1" @@ -30,7 +31,6 @@ import ( "github.com/bxcodec/faker/v3" "github.com/golang-jwt/jwt/v4" - "github.com/golang/glog" "github.com/google/uuid" "github.com/segmentio/ksuid" "github.com/spf13/pflag" @@ -100,17 +100,17 @@ func NewHelper(t *testing.T) *Helper { env.Name = environments.TestingEnv err = env.AddFlags(pflag.CommandLine) if err != nil { - glog.Fatalf("Unable to add environment flags: %s", err.Error()) + klog.Fatalf("Unable to add environment flags: %s", err.Error()) } if logLevel := os.Getenv("LOGLEVEL"); logLevel != "" { - glog.Infof("Using custom loglevel: %s", logLevel) + klog.Infof("Using custom loglevel: %s", logLevel) pflag.CommandLine.Set("-v", logLevel) } pflag.Parse() err = env.Initialize() if err != nil { - glog.Fatalf("Unable to initialize testing environment: %s", err.Error()) + klog.Fatalf("Unable to initialize testing environment: %s", err.Error()) } ctx, cancel := context.WithCancel(context.Background()) @@ -163,9 +163,9 @@ func (helper *Helper) startAPIServer() { helper.Env().Config.GRPCServer.DisableTLS = true helper.APIServer = server.NewAPIServer(helper.EventBroadcaster) go func() { - glog.V(10).Info("Test API server started") + klog.V(10).Info("Test API server started") helper.APIServer.Start() - glog.V(10).Info("Test API server stopped") + klog.V(10).Info("Test API server stopped") }() } @@ -179,9 +179,9 @@ func (helper *Helper) stopAPIServer() error { func (helper *Helper) startMetricsServer() { helper.MetricsServer = server.NewMetricsServer() go func() { - glog.V(10).Info("Test Metrics server started") + klog.V(10).Info("Test Metrics server started") helper.MetricsServer.Start() - glog.V(10).Info("Test Metrics server stopped") + klog.V(10).Info("Test Metrics server stopped") }() } @@ -195,9 +195,9 @@ func (helper *Helper) stopMetricsServer() error { func (helper *Helper) startHealthCheckServer() { helper.HealthCheckServer = server.NewHealthCheckServer() go func() { - glog.V(10).Info("Test health check server started") + klog.V(10).Info("Test health check server started") helper.HealthCheckServer.Start() - glog.V(10).Info("Test health check server stopped") + klog.V(10).Info("Test health check server stopped") }() } @@ -218,17 +218,17 @@ func (helper *Helper) startEventServer(ctx context.Context) { helper.Env().Config.PulseServer.SubscriptionType = "broadcast" helper.EventServer = server.NewPulseServer(helper.EventBroadcaster) go func() { - glog.V(10).Info("Test event server started") + klog.V(10).Info("Test event server started") helper.EventServer.Start(ctx) - glog.V(10).Info("Test event server stopped") + klog.V(10).Info("Test event server stopped") }() } func (helper *Helper) startEventBroadcaster() { go func() { - glog.V(10).Info("Test event broadcaster started") + klog.V(10).Info("Test event broadcaster started") helper.EventBroadcaster.Start(helper.Ctx) - glog.V(10).Info("Test event broadcaster stopped") + klog.V(10).Info("Test event broadcaster stopped") }() } @@ -264,7 +264,7 @@ func (helper *Helper) StartWorkAgent(ctx context.Context, clusterName string, bu // initilize the mqtt options mqttOptions, err := mqtt.BuildMQTTOptionsFromFlags(helper.Env().Config.MessageBroker.MessageBrokerConfig) if err != nil { - glog.Fatalf("Unable to build MQTT options: %s", err.Error()) + klog.Fatalf("Unable to build MQTT options: %s", err.Error()) } var workCodec generic.Codec[*workv1.ManifestWork] @@ -283,7 +283,7 @@ func (helper *Helper) StartWorkAgent(ctx context.Context, clusterName string, bu WithWorkClientWatcherStore(watcherStore). NewAgentClientHolder(ctx) if err != nil { - glog.Fatalf("Unable to create work agent holder: %s", err) + klog.Fatalf("Unable to create work agent holder: %s", err) } factory := workinformers.NewSharedInformerFactoryWithOptions( @@ -314,7 +314,7 @@ func (helper *Helper) StartGRPCResourceSourceClient() { ) if err != nil { - glog.Fatalf("Unable to create grpc cloudevents source client: %s", err.Error()) + klog.Fatalf("Unable to create grpc cloudevents source client: %s", err.Error()) } sourceClient.Subscribe(helper.Ctx, func(action types.ResourceAction, resource *api.Resource) error { @@ -328,31 +328,31 @@ func (helper *Helper) StartGRPCResourceSourceClient() { func (helper *Helper) RestartServer() { helper.stopAPIServer() helper.startAPIServer() - glog.V(10).Info("Test API server restarted") + klog.V(10).Info("Test API server restarted") } func (helper *Helper) RestartMetricsServer() { helper.stopMetricsServer() helper.startMetricsServer() - glog.V(10).Info("Test metrics server restarted") + klog.V(10).Info("Test metrics server restarted") } func (helper *Helper) Reset() { - glog.Infof("Reseting testing environment") + klog.Infof("Reseting testing environment") env := environments.Environment() // Reset the configuration env.Config = config.NewApplicationConfig() // Re-read command-line configuration into a NEW flagset // This new flag set ensures we don't hit conflicts defining the same flag twice - // Also on reset, we don't care to be re-defining 'v' and other glog flags + // Also on reset, we don't care to be re-defining 'v' and other klog flags flagset := pflag.NewFlagSet(helper.NewID(), pflag.ContinueOnError) env.AddFlags(flagset) pflag.Parse() err := env.Initialize() if err != nil { - glog.Fatalf("Unable to reset testing environment: %s", err.Error()) + klog.Fatalf("Unable to reset testing environment: %s", err.Error()) } helper.AppConfig = env.Config helper.RestartServer() diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go index 47c7c2d8..edf399d5 100755 --- a/test/integration/integration_test.go +++ b/test/integration/integration_test.go @@ -6,14 +6,13 @@ import ( "runtime" "testing" - "github.com/golang/glog" - "github.com/openshift-online/maestro/test" + "k8s.io/klog/v2" ) func TestMain(m *testing.M) { flag.Parse() - glog.Infof("Starting integration test using go version %s", runtime.Version()) + klog.Infof("Starting integration test using go version %s", runtime.Version()) helper := test.NewHelper(&testing.T{}) exitCode := m.Run() helper.Teardown() From 715e01d36204e138f65635a8b002015decdc693b Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Wed, 9 Oct 2024 21:14:02 +0800 Subject: [PATCH 33/67] upgrate sdk-go lib (#200) Signed-off-by: Wei Liu --- cmd/maestro/server/pulse_server.go | 2 +- go.mod | 6 +++--- go.sum | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd/maestro/server/pulse_server.go b/cmd/maestro/server/pulse_server.go index 97ae42b0..35214cb0 100644 --- a/cmd/maestro/server/pulse_server.go +++ b/cmd/maestro/server/pulse_server.go @@ -139,7 +139,7 @@ func (s *PulseServer) checkInstances(ctx context.Context) { } // skip if the lock is not acquired if !acquired { - log.Error("failed to acquire the lock as another maestro instance is checking instances") + log.V(4).Infof("failed to acquire the lock as another maestro instance is checking instances, skip") return } diff --git a/go.mod b/go.mod index 45329a24..58f7c82e 100755 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( k8s.io/klog/v2 v2.130.1 open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff - open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866 + open-cluster-management.io/sdk-go v0.14.1-0.20241009075853-0c5ba39fd113 sigs.k8s.io/yaml v1.4.0 ) @@ -69,14 +69,14 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991 // indirect - github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20240911135016-682f3a9684e4 // indirect + github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20241008145627-6bcc075b5b6c // indirect github.com/confluentinc/confluent-kafka-go/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/eclipse/paho.golang v0.12.0 // indirect + github.com/eclipse/paho.golang v0.21.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect diff --git a/go.sum b/go.sum index 93cc4573..3e4a6035 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991 h1:3/pjormyqkSjF2GHQehTELZ9oqlER4GrJZiVUIk8Fy8= github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991/go.mod h1:xiar5+gk13WqyAUQ/cpcxcjD1IhLe/PeilSfCdPcfMU= -github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20240911135016-682f3a9684e4 h1:gOxnzX4wrfMMb1X3Y/gzxthyAKVAHopH5spSc/zpveQ= -github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20240911135016-682f3a9684e4/go.mod h1:s+KZsVZst0bVW6vuKYb8CH49CcSJDO09+ZiIeKzJmqE= +github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20241008145627-6bcc075b5b6c h1:CU7OKO6vJQLp8ghHkyhnkcPw37wdhfK1LzV7L2pNm4w= +github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.0.0-20241008145627-6bcc075b5b6c/go.mod h1:FwZuQ17vf240KYoiIuz0ffRssLYR36Wvq2KJFYWVn88= github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240911135016-682f3a9684e4 h1:Ov6mO9A4hHpuTWNeYJgQUI42rHr4AgJIc9BB/N9fzDs= github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240911135016-682f3a9684e4/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -104,8 +104,8 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/eclipse/paho.golang v0.12.0 h1:EXQFJbJklDnUqW6lyAknMWRhM2NgpHxwrrL8riUmp3Q= -github.com/eclipse/paho.golang v0.12.0/go.mod h1:TSDCUivu9JnoR9Hl+H7sQMcHkejWH2/xKK1NJGtLbIE= +github.com/eclipse/paho.golang v0.21.0 h1:cxxEReu+iFbA5RrHfRGxJOh8tXZKDywuehneoeBeyn8= +github.com/eclipse/paho.golang v0.21.0/go.mod h1:GHF6vy7SvDbDHBguaUpfuBkEB5G6j0zKxMG4gbh6QRQ= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -840,8 +840,8 @@ open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c h1:gYfgkX/U open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff h1:nGP34ECvH6G8ihcF0Q6ZzpYGjvRrJ/yOcj1Dc3z/H48= open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff/go.mod h1:bt8jy8oaXSTTlv6RtRSz4Ea8II15SH1PZJZs34ZWOU4= -open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866 h1:nxYrSsYwl9Mq8DuaJ0K98PCpuGsai+AvXbggMfZDCGI= -open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866/go.mod h1:jCyXPY900UK1n4xwUBWSz27s7lcXN/fhIDF6xu3jIHw= +open-cluster-management.io/sdk-go v0.14.1-0.20241009075853-0c5ba39fd113 h1:VSIxKaQyL1AaT+3TmOYnUlAkEX3lKG40zPuGPjXBP6M= +open-cluster-management.io/sdk-go v0.14.1-0.20241009075853-0c5ba39fd113/go.mod h1:VUykb6x2KAljQHql6vnPcE40MQvA4JQNKvwT7JIbrkM= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= From 7dbc0c648ff679dc01606fbc5787d26289f70b1e Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Tue, 15 Oct 2024 14:20:59 +0800 Subject: [PATCH 34/67] fix template api version. (#202) Signed-off-by: morvencao --- templates/agent-template-aro-hcp.yml | 2 +- templates/agent-template.yml | 2 +- templates/db-template.yml | 2 +- templates/mqtt-template.yml | 2 +- templates/route-template.yml | 2 +- templates/secrets-template.yml | 2 +- templates/service-template-aro-hcp.yml | 2 +- templates/service-template.yml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/templates/agent-template-aro-hcp.yml b/templates/agent-template-aro-hcp.yml index e60c5ee7..7e3d462a 100644 --- a/templates/agent-template-aro-hcp.yml +++ b/templates/agent-template-aro-hcp.yml @@ -1,6 +1,6 @@ --- +apiVersion: template.openshift.io/v1 kind: Template -apiVersion: v1 metadata: name: maestro-agent annotations: diff --git a/templates/agent-template.yml b/templates/agent-template.yml index d4f79a5b..7350c8f5 100644 --- a/templates/agent-template.yml +++ b/templates/agent-template.yml @@ -1,6 +1,6 @@ --- +apiVersion: template.openshift.io/v1 kind: Template -apiVersion: v1 metadata: name: maestro-agent annotations: diff --git a/templates/db-template.yml b/templates/db-template.yml index 23c2efd7..18c07221 100755 --- a/templates/db-template.yml +++ b/templates/db-template.yml @@ -1,5 +1,5 @@ --- -apiVersion: v1 +apiVersion: template.openshift.io/v1 kind: Template metadata: annotations: diff --git a/templates/mqtt-template.yml b/templates/mqtt-template.yml index b6fdeaeb..1075b689 100644 --- a/templates/mqtt-template.yml +++ b/templates/mqtt-template.yml @@ -1,5 +1,5 @@ --- -apiVersion: v1 +apiVersion: template.openshift.io/v1 kind: Template metadata: annotations: diff --git a/templates/route-template.yml b/templates/route-template.yml index a4296147..a782ca84 100755 --- a/templates/route-template.yml +++ b/templates/route-template.yml @@ -1,5 +1,5 @@ --- -apiVersion: v1 +apiVersion: template.openshift.io/v1 kind: Template name: uhc-acct-mangr-routes metadata: diff --git a/templates/secrets-template.yml b/templates/secrets-template.yml index 407a9649..efbe1914 100755 --- a/templates/secrets-template.yml +++ b/templates/secrets-template.yml @@ -1,5 +1,5 @@ --- -apiVersion: v1 +apiVersion: template.openshift.io/v1 kind: Template metadata: name: maestro-secrets diff --git a/templates/service-template-aro-hcp.yml b/templates/service-template-aro-hcp.yml index 9859d16f..90b5df81 100755 --- a/templates/service-template-aro-hcp.yml +++ b/templates/service-template-aro-hcp.yml @@ -1,6 +1,6 @@ --- +apiVersion: template.openshift.io/v1 kind: Template -apiVersion: v1 metadata: name: maestro-service annotations: diff --git a/templates/service-template.yml b/templates/service-template.yml index c116dd27..296235da 100755 --- a/templates/service-template.yml +++ b/templates/service-template.yml @@ -1,6 +1,6 @@ --- +apiVersion: template.openshift.io/v1 kind: Template -apiVersion: v1 metadata: name: maestro-service annotations: From 7b9534d67ac52615ff207f431686e33d004815d2 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:08:26 +0800 Subject: [PATCH 35/67] chore(deps): update openapitools/openapi-generator-cli docker tag to v7.9.0 (#199) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- Dockerfile.openapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.openapi b/Dockerfile.openapi index 6e07a7fa..0ef5c504 100755 --- a/Dockerfile.openapi +++ b/Dockerfile.openapi @@ -1,4 +1,4 @@ -FROM openapitools/openapi-generator-cli:v7.8.0 +FROM openapitools/openapi-generator-cli:v7.9.0 RUN apt-get update RUN apt-get install -y make sudo git From d94d00ef9d20348a3ac8583bfb63d0efaf3509d4 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:09:34 +0800 Subject: [PATCH 36/67] chore(deps): update docker.io/library/postgres docker tag to v17 (#197) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/integration-test.yaml | 2 +- .tekton/unit-test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.tekton/integration-test.yaml b/.tekton/integration-test.yaml index b4f0a8ec..80b5215b 100644 --- a/.tekton/integration-test.yaml +++ b/.tekton/integration-test.yaml @@ -110,7 +110,7 @@ spec: ) echo -n "$TEST_OUTPUT" | tee $(results.TEST_OUTPUT.path) sidecars: - - image: docker.io/library/postgres:16.4 + - image: docker.io/library/postgres:17.0 name: database-test env: - name: PGDATA diff --git a/.tekton/unit-test.yaml b/.tekton/unit-test.yaml index 8b7c98ff..a55686e8 100644 --- a/.tekton/unit-test.yaml +++ b/.tekton/unit-test.yaml @@ -110,7 +110,7 @@ spec: ) echo -n "$TEST_OUTPUT" | tee $(results.TEST_OUTPUT.path) sidecars: - - image: docker.io/library/postgres:16.4 + - image: docker.io/library/postgres:17.0 name: database-test env: - name: PGDATA From 8ed6055685a6f13a0ffe7118bb0483091135fa16 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Thu, 24 Oct 2024 16:25:51 +0800 Subject: [PATCH 37/67] refine e2e testings. (#205) Signed-off-by: morvencao --- Makefile | 3 +- test/e2e/pkg/grpc_test.go | 24 +- test/e2e/pkg/resources_test.go | 52 +- test/e2e/pkg/serverside_test.go | 10 +- test/e2e/pkg/sourceclient_test.go | 84 ++-- test/e2e/pkg/spec_resync_test.go | 762 ++++++++++++++--------------- test/e2e/pkg/status_resync_test.go | 399 ++++++++------- test/e2e/pkg/suite_test.go | 115 +++-- test/factories.go | 57 ++- 9 files changed, 767 insertions(+), 739 deletions(-) diff --git a/Makefile b/Makefile index bf261dd8..87326eb1 100755 --- a/Makefile +++ b/Makefile @@ -422,6 +422,7 @@ e2e-test: e2e-test/teardown e2e-test/setup ${PWD}/test/e2e/pkg -- \ -api-server=https://$(shell cat ${PWD}/test/e2e/.external_host_ip):30080 \ -grpc-server=$(shell cat ${PWD}/test/e2e/.external_host_ip):30090 \ + -server-kubeconfig=${PWD}/test/e2e/.kubeconfig \ -consumer-name=$(shell cat ${PWD}/test/e2e/.consumer_name) \ - -consumer-kubeconfig=${PWD}/test/e2e/.kubeconfig + -agent-kubeconfig=${PWD}/test/e2e/.kubeconfig .PHONY: e2e-test diff --git a/test/e2e/pkg/grpc_test.go b/test/e2e/pkg/grpc_test.go index 5670c3a4..34c1ea95 100644 --- a/test/e2e/pkg/grpc_test.go +++ b/test/e2e/pkg/grpc_test.go @@ -95,7 +95,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec using grpc client", func() { - evt := helper.NewEvent(sourceID, "create_request", consumer.Name, resourceID, deployName, 1, 1) + evt := helper.NewEvent(sourceID, "create_request", agentTestOpts.consumerName, resourceID, deployName, 1, 1) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -132,7 +132,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -152,7 +152,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec with update request using grpc client", func() { - evt := helper.NewEvent(sourceID, "update_request", consumer.Name, resourceID, deployName, 1, 2) + evt := helper.NewEvent(sourceID, "update_request", agentTestOpts.consumerName, resourceID, deployName, 1, 2) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -189,7 +189,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -209,7 +209,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource spec with delete request using grpc client", func() { - evt := helper.NewEvent(sourceID, "delete_request", consumer.Name, resourceID, deployName, 2, 2) + evt := helper.NewEvent(sourceID, "delete_request", agentTestOpts.consumerName, resourceID, deployName, 2, 2) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -233,7 +233,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -302,7 +302,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec using grpc client", func() { - evt := helper.NewBundleEvent(sourceID, "create_request", consumer.Name, resourceID, deployName, 1, 1) + evt := helper.NewBundleEvent(sourceID, "create_request", agentTestOpts.consumerName, resourceID, deployName, 1, 1) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -354,7 +354,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -374,7 +374,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec with update request using grpc client", func() { - evt := helper.NewBundleEvent(sourceID, "update_request", consumer.Name, resourceID, deployName, 1, 2) + evt := helper.NewBundleEvent(sourceID, "update_request", agentTestOpts.consumerName, resourceID, deployName, 1, 2) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -426,7 +426,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -446,7 +446,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { }) It("publish a resource bundle spec with delete request using grpc client", func() { - evt := helper.NewBundleEvent(sourceID, "delete_request", consumer.Name, resourceID, deployName, 2, 2) + evt := helper.NewBundleEvent(sourceID, "delete_request", agentTestOpts.consumerName, resourceID, deployName, 2, 2) pbEvt := &pbv1.CloudEvent{} err := grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt) Expect(err).To(BeNil(), "failed to convert spec from cloudevent to protobuf") @@ -470,7 +470,7 @@ var _ = Describe("GRPC", Ordered, Label("e2e-tests-grpc"), func() { It("get the nginx deployment from cluster", func() { Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil diff --git a/test/e2e/pkg/resources_test.go b/test/e2e/pkg/resources_test.go index fb190b7c..9fca6f7f 100644 --- a/test/e2e/pkg/resources_test.go +++ b/test/e2e/pkg/resources_test.go @@ -25,7 +25,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { deployName := fmt.Sprintf("nginx-%s", rand.String(5)) var resource *openapi.Resource It("post the nginx resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, deployName, 1) + res := helper.NewAPIResource(agentTestOpts.consumerName, deployName, 1) var resp *http.Response var err error resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -35,7 +35,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(*resource.Version).To(Equal(int32(1))) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -55,7 +55,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("patch the nginx resource with the maestro api", func() { - newRes := helper.NewAPIResource(consumer.Name, deployName, 2) + newRes := helper.NewAPIResource(agentTestOpts.consumerName, deployName, 2) patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resource.Id). ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resource.Version, Manifest: newRes.Manifest}).Execute() Expect(err).ShouldNot(HaveOccurred()) @@ -63,7 +63,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(*patchedResource.Version).To(Equal(*resource.Version + 1)) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -80,7 +80,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -96,7 +96,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { deployName := fmt.Sprintf("nginx-%s", rand.String(5)) var resource *openapi.Resource It("post the nginx resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, deployName, 1) + res := helper.NewAPIResource(agentTestOpts.consumerName, deployName, 1) res.DeleteOption = map[string]interface{}{"propagationPolicy": "Orphan"} var resp *http.Response var err error @@ -106,7 +106,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(*resource.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -124,7 +124,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { // ensure the "nginx" deployment in the "default" namespace is not deleted Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return fmt.Errorf("nginx deployment is deleted") @@ -135,11 +135,11 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("delete the nginx deployment", func() { - err := consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, deployName, metav1.DeleteOptions{}) + err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Delete(ctx, deployName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -155,7 +155,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { deployName := fmt.Sprintf("nginx-%s", rand.String(5)) var resource *openapi.Resource It("post the nginx resource to the maestro api with createOnly updateStrategy", func() { - res := helper.NewAPIResource(consumer.Name, deployName, 1) + res := helper.NewAPIResource(agentTestOpts.consumerName, deployName, 1) res.UpdateStrategy = map[string]interface{}{"type": "CreateOnly"} var resp *http.Response var err error @@ -165,7 +165,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(*resource.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return err } @@ -177,7 +177,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("patch the nginx resource", func() { - newRes := helper.NewAPIResource(consumer.Name, deployName, 2) + newRes := helper.NewAPIResource(agentTestOpts.consumerName, deployName, 2) patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resource.Id). ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resource.Version, Manifest: newRes.Manifest}).Execute() Expect(err).ShouldNot(HaveOccurred()) @@ -186,7 +186,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { // ensure the "nginx" deployment in the "default" namespace is not updated Consistently(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { return nil } @@ -203,7 +203,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -222,7 +222,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { nginxDeploy := &appsv1.Deployment{} err := json.Unmarshal([]byte(helper.NewResourceManifestJSON(deployName, 1)), nginxDeploy) Expect(err).ShouldNot(HaveOccurred()) - _, err = consumer.ClientSet.AppsV1().Deployments("default").Create(ctx, nginxDeploy, metav1.CreateOptions{}) + _, err = agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Create(ctx, nginxDeploy, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) @@ -230,13 +230,13 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { var resp *http.Response var err error // post the resource with readonly updateStrategy and foreground delete option should fail - invalidRes := helper.NewReadOnlyAPIResource(consumer.Name, deployName) + invalidRes := helper.NewReadOnlyAPIResource(agentTestOpts.consumerName, deployName) invalidRes.DeleteOption = map[string]interface{}{"propagationPolicy": "Foreground"} resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(invalidRes).Execute() Expect(err).Should(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusBadRequest)) - res := helper.NewReadOnlyAPIResource(consumer.Name, deployName) + res := helper.NewReadOnlyAPIResource(agentTestOpts.consumerName, deployName) resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) @@ -286,11 +286,11 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { Expect(err).ShouldNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, deployName, metav1.DeleteOptions{}) + err = agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Delete(ctx, deployName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -307,7 +307,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { secretName := "auth-" + rand.String(5) manifest := fmt.Sprintf("{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"name\":\"%s\",\"namespace\":\"default\"}}", secretName) It("create a secret in the target cluster", func() { - _, err := consumer.ClientSet.CoreV1().Secrets("default").Create(ctx, &corev1.Secret{ + _, err := agentTestOpts.kubeClientSet.CoreV1().Secrets("default").Create(ctx, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: secretName, Namespace: "default", @@ -360,7 +360,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }, } Eventually(func() error { - _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) return err }, 5*time.Minute, 5*time.Second).ShouldNot(HaveOccurred()) }) @@ -380,7 +380,7 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { It("get the resource status back", func() { Eventually(func() error { - work, err := workClient.ManifestWorks(consumer.Name).Get(ctx, workName, metav1.GetOptions{}) + work, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Get(ctx, workName, metav1.GetOptions{}) if err != nil { return err } @@ -402,14 +402,14 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { }) It("delete the readonly resource", func() { - err := workClient.ManifestWorks(consumer.Name).Delete(ctx, workName, metav1.DeleteOptions{}) + err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = consumer.ClientSet.CoreV1().Secrets("default").Delete(ctx, secretName, metav1.DeleteOptions{}) + err = agentTestOpts.kubeClientSet.CoreV1().Secrets("default").Delete(ctx, secretName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { - _, err := consumer.ClientSet.CoreV1().Secrets("default").Get(ctx, secretName, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.CoreV1().Secrets("default").Get(ctx, secretName, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil diff --git a/test/e2e/pkg/serverside_test.go b/test/e2e/pkg/serverside_test.go index d753bc2d..e4859a5d 100644 --- a/test/e2e/pkg/serverside_test.go +++ b/test/e2e/pkg/serverside_test.go @@ -64,7 +64,7 @@ var _ = Describe("Server Side Apply", Ordered, Label("e2e-tests-serverside-apply res := openapi.Resource{ Manifest: manifest, - ConsumerName: &consumer.Name, + ConsumerName: &agentTestOpts.consumerName, } created, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -121,12 +121,12 @@ var _ = Describe("Server Side Apply", Ordered, Label("e2e-tests-serverside-apply nestedWorkNamespace := "default" work := NewNestedManifestWork(nestedWorkNamespace, workName, nestedWorkName) - _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) // make sure the nested work is created Eventually(func() error { - _, err := kubeWorkClient.WorkV1().ManifestWorks(nestedWorkNamespace).Get(ctx, nestedWorkName, metav1.GetOptions{}) + _, err := agentTestOpts.workClientSet.WorkV1().ManifestWorks(nestedWorkNamespace).Get(ctx, nestedWorkName, metav1.GetOptions{}) if err != nil { return err } @@ -136,7 +136,7 @@ var _ = Describe("Server Side Apply", Ordered, Label("e2e-tests-serverside-apply // make sure the nested work is not updated Consistently(func() error { - nestedWork, err := kubeWorkClient.WorkV1().ManifestWorks(nestedWorkNamespace).Get(ctx, nestedWorkName, metav1.GetOptions{}) + nestedWork, err := agentTestOpts.workClientSet.WorkV1().ManifestWorks(nestedWorkNamespace).Get(ctx, nestedWorkName, metav1.GetOptions{}) if err != nil { return err } @@ -148,7 +148,7 @@ var _ = Describe("Server Side Apply", Ordered, Label("e2e-tests-serverside-apply return nil }, 1*time.Minute, 1*time.Second).Should(BeNil()) - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, workName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) }) diff --git a/test/e2e/pkg/sourceclient_test.go b/test/e2e/pkg/sourceclient_test.go index ec6a0d20..3a1c9086 100644 --- a/test/e2e/pkg/sourceclient_test.go +++ b/test/e2e/pkg/sourceclient_test.go @@ -33,7 +33,7 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- workName = "work-" + rand.String(5) work := NewManifestWork(workName) Eventually(func() error { - _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) return err }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) @@ -42,7 +42,7 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- }) AfterEach(func() { - err := workClient.ManifestWorks(consumer.Name).Delete(ctx, workName, metav1.DeleteOptions{}) + err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { @@ -53,7 +53,7 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- It("Should return an error when updating an obsolete work", func() { By("update a work by work client") - work, err := workClient.ManifestWorks(consumer.Name).Get(ctx, workName, metav1.GetOptions{}) + work, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Get(ctx, workName, metav1.GetOptions{}) Expect(err).ShouldNot(HaveOccurred()) newWork := work.DeepCopy() @@ -61,7 +61,7 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- patchData, err := grpcsource.ToWorkPatch(work, newWork) Expect(err).ShouldNot(HaveOccurred()) - _, err = workClient.ManifestWorks(consumer.Name).Patch(ctx, workName, types.MergePatchType, patchData, metav1.PatchOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Patch(ctx, workName, types.MergePatchType, patchData, metav1.PatchOptions{}) Expect(err).ShouldNot(HaveOccurred()) By("update the work by work client again") @@ -70,7 +70,7 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- patchData, err = grpcsource.ToWorkPatch(work, obsoleteWork) Expect(err).ShouldNot(HaveOccurred()) - _, err = workClient.ManifestWorks(consumer.Name).Patch(ctx, workName, types.MergePatchType, patchData, metav1.PatchOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Patch(ctx, workName, types.MergePatchType, patchData, metav1.PatchOptions{}) Expect(err).Should(HaveOccurred()) Expect(strings.Contains(err.Error(), "the resource version is not the latest")).Should(BeTrue()) @@ -93,20 +93,20 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- initWorkAName = "init-work-a-" + rand.String(5) work := NewManifestWorkWithLabels(initWorkAName, map[string]string{"app": "test"}) - _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) initWorkBName = "init-work-b-" + rand.String(5) work = NewManifestWorkWithLabels(initWorkBName, map[string]string{"app": "test"}) - _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) AfterEach(func() { - err := workClient.ManifestWorks(consumer.Name).Delete(ctx, initWorkAName, metav1.DeleteOptions{}) + err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, initWorkAName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, initWorkBName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, initWorkBName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { @@ -131,20 +131,20 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- Expect(err).ShouldNot(HaveOccurred()) By("start watching") - watcher, err := watcherClient.ManifestWorks(consumer.Name).Watch(watcherCtx, metav1.ListOptions{}) + watcher, err := watcherClient.ManifestWorks(agentTestOpts.consumerName).Watch(watcherCtx, metav1.ListOptions{}) Expect(err).ShouldNot(HaveOccurred()) result := StartWatch(watcherCtx, watcher) By("create a work by work client") workName := "work-" + rand.String(5) - _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, NewManifestWork(workName), metav1.CreateOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, NewManifestWork(workName), metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) // wait for few seconds to ensure the creation is finished <-time.After(5 * time.Second) By("update a work by work client") - work, err := workClient.ManifestWorks(consumer.Name).Get(ctx, workName, metav1.GetOptions{}) + work, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Get(ctx, workName, metav1.GetOptions{}) Expect(err).ShouldNot(HaveOccurred()) newWork := work.DeepCopy() @@ -152,14 +152,14 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- patchData, err := grpcsource.ToWorkPatch(work, newWork) Expect(err).ShouldNot(HaveOccurred()) - _, err = workClient.ManifestWorks(consumer.Name).Patch(ctx, workName, types.MergePatchType, patchData, metav1.PatchOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Patch(ctx, workName, types.MergePatchType, patchData, metav1.PatchOptions{}) Expect(err).ShouldNot(HaveOccurred()) // wait for few seconds to ensure the work status is updated by agent <-time.After(5 * time.Second) By("delete the work by work client") - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, workName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { @@ -181,8 +181,8 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- Expect(err).ShouldNot(HaveOccurred()) allConsumerWatcherResult := StartWatch(watcherCtx, allConsumerWatcher) - By("start watching works from consumer" + consumer.Name) - consumerWatcher, err := watcherClient.ManifestWorks(consumer.Name).Watch(watcherCtx, metav1.ListOptions{}) + By("start watching works from consumer" + agentTestOpts.consumerName) + consumerWatcher, err := watcherClient.ManifestWorks(agentTestOpts.consumerName).Watch(watcherCtx, metav1.ListOptions{}) Expect(err).ShouldNot(HaveOccurred()) consumerWatcherResult := StartWatch(watcherCtx, consumerWatcher) @@ -193,14 +193,14 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- By("create a work by work client") workName := "work-" + rand.String(5) - _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, NewManifestWork(workName), metav1.CreateOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, NewManifestWork(workName), metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) // wait for few seconds to ensure the creation is finished <-time.After(5 * time.Second) By("delete the work by work client") - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, workName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { @@ -229,7 +229,7 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- Expect(err).ShouldNot(HaveOccurred()) By("start watching with label app=test") - watcher, err := watcherClient.ManifestWorks(consumer.Name).Watch(watcherCtx, metav1.ListOptions{ + watcher, err := watcherClient.ManifestWorks(agentTestOpts.consumerName).Watch(watcherCtx, metav1.ListOptions{ LabelSelector: "app=test", }) Expect(err).ShouldNot(HaveOccurred()) @@ -238,14 +238,14 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- By("create a work by work client") workName := "work-" + rand.String(5) work := NewManifestWorkWithLabels(workName, map[string]string{"app": "test"}) - _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) // wait for few seconds to ensure the creation is finished <-time.After(5 * time.Second) By("delete the work by work client") - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, workName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { @@ -265,27 +265,27 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- // prepare works firstly workName = "work-" + rand.String(5) work := NewManifestWork(workName) - _, err := workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) prodWorkName = "work-production" + rand.String(5) work = NewManifestWorkWithLabels(prodWorkName, map[string]string{"app": "test", "env": "production"}) - _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) testWorkAName = "work-integration-a-" + rand.String(5) work = NewManifestWorkWithLabels(testWorkAName, map[string]string{"app": "test", "env": "integration", "val": "a"}) - _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) testWorkBName = "work-integration-b-" + rand.String(5) work = NewManifestWorkWithLabels(testWorkBName, map[string]string{"app": "test", "env": "integration", "val": "b"}) - _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) testWorkCName = "work-integration-c-" + rand.String(5) work = NewManifestWorkWithLabels(testWorkCName, map[string]string{"app": "test", "env": "integration", "val": "c"}) - _, err = workClient.ManifestWorks(consumer.Name).Create(ctx, work, metav1.CreateOptions{}) + _, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) Expect(err).ShouldNot(HaveOccurred()) // wait for few seconds to ensure the creation is finished @@ -293,19 +293,19 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- }) AfterEach(func() { - err := workClient.ManifestWorks(consumer.Name).Delete(ctx, workName, metav1.DeleteOptions{}) + err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, prodWorkName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, prodWorkName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, testWorkAName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, testWorkAName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, testWorkBName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, testWorkBName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = workClient.ManifestWorks(consumer.Name).Delete(ctx, testWorkCName, metav1.DeleteOptions{}) + err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, testWorkCName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) Eventually(func() error { @@ -331,57 +331,57 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- It("List works with options", func() { By("list all works") - works, err := workClient.ManifestWorks(metav1.NamespaceAll).List(ctx, metav1.ListOptions{}) + works, err := sourceWorkClient.ManifestWorks(metav1.NamespaceAll).List(ctx, metav1.ListOptions{}) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, workName, prodWorkName, testWorkAName, testWorkBName, testWorkCName)).ShouldNot(HaveOccurred()) By("list works by consumer name") - works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{}) + works, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).List(ctx, metav1.ListOptions{}) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, workName, prodWorkName, testWorkAName, testWorkBName, testWorkCName)).ShouldNot(HaveOccurred()) By("list works by nonexistent consumer") - works, err = workClient.ManifestWorks("nonexistent").List(ctx, metav1.ListOptions{}) + works, err = sourceWorkClient.ManifestWorks("nonexistent").List(ctx, metav1.ListOptions{}) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items)).ShouldNot(HaveOccurred()) By("list works with nonexistent labels") - works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ + works, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).List(ctx, metav1.ListOptions{ LabelSelector: "nonexistent=true", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items)).ShouldNot(HaveOccurred()) By("list works with app label") - works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ + works, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).List(ctx, metav1.ListOptions{ LabelSelector: "app=test", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, prodWorkName, testWorkAName, testWorkBName, testWorkCName)).ShouldNot(HaveOccurred()) By("list works without test env") - works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ + works, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).List(ctx, metav1.ListOptions{ LabelSelector: "app=test,env!=integration", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, prodWorkName)).ShouldNot(HaveOccurred()) By("list works in prod and test env") - works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ + works, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).List(ctx, metav1.ListOptions{ LabelSelector: "env in (production, integration)", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, prodWorkName, testWorkAName, testWorkBName, testWorkCName)).ShouldNot(HaveOccurred()) By("list works in test env and val not in a and b") - works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ + works, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).List(ctx, metav1.ListOptions{ LabelSelector: "env=integration,val notin (a,b)", }) Expect(err).ShouldNot(HaveOccurred()) Expect(AssertWorks(works.Items, testWorkCName)).ShouldNot(HaveOccurred()) By("list works with val label") - works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ + works, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).List(ctx, metav1.ListOptions{ LabelSelector: "val", }) Expect(err).ShouldNot(HaveOccurred()) @@ -389,7 +389,7 @@ var _ = Describe("Source ManifestWork Client", Ordered, Label("e2e-tests-source- // TODO support does not exist // By("list works without val label") - // works, err = workClient.ManifestWorks(consumer.Name).List(ctx, metav1.ListOptions{ + // works, err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).List(ctx, metav1.ListOptions{ // LabelSelector: "!val", // }) // Expect(err).ShouldNot(HaveOccurred()) @@ -476,7 +476,7 @@ func AssertWatchResult(result *WatchedResult) error { } func AssertWorkNotFound(name string) error { - _, err := workClient.ManifestWorks(consumer.Name).Get(ctx, name, metav1.GetOptions{}) + _, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Get(ctx, name, metav1.GetOptions{}) if errors.IsNotFound(err) { return nil } diff --git a/test/e2e/pkg/spec_resync_test.go b/test/e2e/pkg/spec_resync_test.go index 5d374a43..a6a7aa6a 100644 --- a/test/e2e/pkg/spec_resync_test.go +++ b/test/e2e/pkg/spec_resync_test.go @@ -8,11 +8,9 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/openshift-online/maestro/pkg/api/openapi" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/rand" ) @@ -24,7 +22,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res deployB := fmt.Sprintf("nginx-%s", rand.String(5)) deployC := fmt.Sprintf("nginx-%s", rand.String(5)) It("post the nginx A resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, deployA, 1) + res := helper.NewAPIResource(agentTestOpts.consumerName, deployA, 1) var resp *http.Response var err error resourceA, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -33,7 +31,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res Expect(*resourceA.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return err } @@ -45,7 +43,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res }) It("post the nginx B resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, deployB, 1) + res := helper.NewAPIResource(agentTestOpts.consumerName, deployB, 1) var resp *http.Response var err error resourceB, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -54,7 +52,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res Expect(*resourceB.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { return err } @@ -66,20 +64,20 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res }) It("shut down maestro agent", func() { - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro-agent").Get(ctx, "maestro-agent", metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments(agentTestOpts.agentNamespace).Get(ctx, "maestro-agent", metav1.GetOptions{}) Expect(err).ShouldNot(HaveOccurred()) maestroAgentReplicas = int(*deploy.Spec.Replicas) // patch maestro agent replicas to 0 - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro-agent").Patch(ctx, "maestro-agent", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ - FieldManager: "testconsumer.ClientSet", + deploy, err = agentTestOpts.kubeClientSet.AppsV1().Deployments(agentTestOpts.agentNamespace).Patch(ctx, "maestro-agent", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ + FieldManager: "testagentTestOpts.kubeClientSet", }) Expect(err).ShouldNot(HaveOccurred()) Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) // ensure no running maestro agent pods Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro-agent").List(ctx, metav1.ListOptions{ + pods, err := agentTestOpts.kubeClientSet.CoreV1().Pods(agentTestOpts.agentNamespace).List(ctx, metav1.ListOptions{ LabelSelector: "app=maestro-agent", }) if err != nil { @@ -93,7 +91,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res }) It("patch the nginx A resource", func() { - newRes := helper.NewAPIResource(consumer.Name, deployA, 2) + newRes := helper.NewAPIResource(agentTestOpts.consumerName, deployA, 2) patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resourceA.Id). ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resourceA.Version, Manifest: newRes.Manifest}).Execute() Expect(err).ShouldNot(HaveOccurred()) @@ -103,7 +101,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res It("ensure the nginx A resource is not updated", func() { Consistently(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return nil } @@ -122,7 +120,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res It("ensure the nginx B resource is not deleted", func() { Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return fmt.Errorf("nginx B deployment %s is deleted", deployB) @@ -133,7 +131,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res }) It("post the nginx C resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, deployC, 1) + res := helper.NewAPIResource(agentTestOpts.consumerName, deployC, 1) var resp *http.Response var err error resourceC, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -144,7 +142,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res It("ensure the nginx C resource is not created", func() { Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err == nil { return fmt.Errorf("nginx C deployment %s is created", deployC) } @@ -154,15 +152,15 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res It("restart maestro agent", func() { // patch maestro agent replicas back - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro-agent").Patch(ctx, "maestro-agent", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroAgentReplicas)), metav1.PatchOptions{ - FieldManager: "testconsumer.ClientSet", + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments(agentTestOpts.agentNamespace).Patch(ctx, "maestro-agent", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroAgentReplicas)), metav1.PatchOptions{ + FieldManager: "testagentTestOpts.kubeClientSet", }) Expect(err).ShouldNot(HaveOccurred()) Expect(*deploy.Spec.Replicas).To(Equal(int32(maestroAgentReplicas))) // ensure maestro agent pod is up and running Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro-agent").List(ctx, metav1.ListOptions{ + pods, err := agentTestOpts.kubeClientSet.CoreV1().Pods(agentTestOpts.agentNamespace).List(ctx, metav1.ListOptions{ LabelSelector: "app=maestro-agent", }) if err != nil { @@ -185,7 +183,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res It("ensure the nginx A resource is updated", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { return err } @@ -198,7 +196,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res It("ensure the nginx B resource is deleted", func() { Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -211,7 +209,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res It("ensure the nginx C resource is created", func() { Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err != nil { return err } @@ -228,7 +226,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -243,7 +241,7 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -256,362 +254,362 @@ var _ = Describe("Spec Resync After Restart", Ordered, Label("e2e-tests-spec-res }) }) -var _ = Describe("Spec Resync After Reconnect", Ordered, Label("e2e-tests-spec-resync-reconnect"), func() { - Context("Resource resync resource spec after maestro agent reconnects", func() { - var maestroServerReplicas, mqttReplicas int - var resourceA, resourceB, resourceC *openapi.Resource - deployA := fmt.Sprintf("nginx-%s", rand.String(5)) - deployB := fmt.Sprintf("nginx-%s", rand.String(5)) - deployC := fmt.Sprintf("nginx-%s", rand.String(5)) - It("post the nginx A resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, deployA, 1) - var resp *http.Response - var err error - resourceA, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resourceA.Id).ShouldNot(BeEmpty()) - - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) - if err != nil { - return err - } - if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 1, got %d", deployA, *deploy.Spec.Replicas) - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("post the nginx B resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, deployB, 1) - var resp *http.Response - var err error - resourceB, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resourceB.Id).ShouldNot(BeEmpty()) - - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) - if err != nil { - return err - } - if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx B deployment %s, expected 1, got %d", deployB, *deploy.Spec.Replicas) - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("delete the grpc-broker service for agent", func() { - err := consumer.ClientSet.CoreV1().Services("maestro").Delete(ctx, "maestro-grpc-broker", metav1.DeleteOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }) - - It("delete the mqtt-broker service for agent", func() { - err := consumer.ClientSet.CoreV1().Services("maestro").Delete(ctx, "maestro-mqtt-agent", metav1.DeleteOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }) - - It("rollout maestro server", func() { - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Get(ctx, "maestro", metav1.GetOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - maestroServerReplicas = int(*deploy.Spec.Replicas) - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ - FieldManager: "testconsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) - - // ensure no running maestro server pods - Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ - LabelSelector: "app=maestro", - }) - if err != nil { - return err - } - if len(pods.Items) > 0 { - return fmt.Errorf("maestro server pods still running") - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - - // patch maestro server replicas to maestroServerReplicas - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroServerReplicas)), metav1.PatchOptions{ - FieldManager: "testconsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(maestroServerReplicas))) - - // ensure maestro server pod is up and running - Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ - LabelSelector: "app=maestro", - }) - if err != nil { - return err - } - if len(pods.Items) != maestroServerReplicas { - return fmt.Errorf("unexpected maestro server pod count, expected %d, got %d", maestroServerReplicas, len(pods.Items)) - } - for _, pod := range pods.Items { - if pod.Status.Phase != "Running" { - return fmt.Errorf("maestro server pod not in running state") - } - if pod.Status.ContainerStatuses[0].State.Running == nil { - return fmt.Errorf("maestro server container not in running state") - } - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("rollout the mqtt-broker", func() { - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Get(ctx, "maestro-mqtt", metav1.GetOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - mqttReplicas = int(*deploy.Spec.Replicas) - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro-mqtt", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ - FieldManager: "testconsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) - - // ensure no running mqtt-broker pods - Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ - LabelSelector: "name=maestro-mqtt", - }) - if err != nil { - return err - } - if len(pods.Items) > 0 { - return fmt.Errorf("maestro-mqtt pods still running") - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - - // patch mqtt-broker replicas to mqttReplicas - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro-mqtt", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, mqttReplicas)), metav1.PatchOptions{ - FieldManager: "testconsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(mqttReplicas))) - - // ensure mqtt-broker pod is up and running - Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ - LabelSelector: "name=maestro-mqtt", - }) - if err != nil { - return err - } - if len(pods.Items) != mqttReplicas { - return fmt.Errorf("unexpected maestro-mqtt pod count, expected %d, got %d", mqttReplicas, len(pods.Items)) - } - for _, pod := range pods.Items { - if pod.Status.Phase != "Running" { - return fmt.Errorf("maestro-mqtt pod not in running state") - } - if pod.Status.ContainerStatuses[0].State.Running == nil { - return fmt.Errorf("maestro-mqtt container not in running state") - } - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("patch the nginx A resource", func() { - newRes := helper.NewAPIResource(consumer.Name, deployA, 2) - Eventually(func() error { - patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resourceA.Id). - ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resourceA.Version, Manifest: newRes.Manifest}).Execute() - if err != nil { - return err - } - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("unexpected status code, expected 200, got %d", resp.StatusCode) - } - if *patchedResource.Version != *resourceA.Version+1 { - return fmt.Errorf("unexpected version, expected %d, got %d", *resourceA.Version+1, *patchedResource.Version) - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("ensure the nginx A resource is not updated", func() { - Consistently(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) - if err != nil { - return nil - } - if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 1, got %d", deployA, *deploy.Spec.Replicas) - } - return nil - }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("delete the nginx B resource", func() { - resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceB.Id).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - }) - - It("ensure the nginx B resource is not deleted", func() { - Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) - if err != nil { - if errors.IsNotFound(err) { - return fmt.Errorf("nginx B deployment %s is deleted", deployB) - } - } - return nil - }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("post the nginx C resource to the maestro api", func() { - res := helper.NewAPIResource(consumer.Name, deployC, 1) - var resp *http.Response - var err error - resourceC, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resourceC.Id).ShouldNot(BeEmpty()) - }) - - It("ensure the nginx C resource is not created", func() { - Consistently(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) - if err == nil { - return fmt.Errorf("nginx C deployment %s is created", deployC) - } - return nil - }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("recreate the mqtt-broker service for agent", func() { - mqttAgentService := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "maestro-mqtt-agent", - Namespace: "maestro", - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - "name": "maestro-mqtt", - }, - Ports: []corev1.ServicePort{ - { - Name: "mosquitto", - Protocol: corev1.ProtocolTCP, - Port: 1883, - TargetPort: intstr.FromInt(1883), - }, - }, - Type: corev1.ServiceTypeClusterIP, - }, - } - - _, err := consumer.ClientSet.CoreV1().Services("maestro").Create(ctx, mqttAgentService, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }) - - It("recreate the grpc-broker service for agent", func() { - grpcBrokerService := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "maestro-grpc-broker", - Namespace: "maestro", - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - "app": "maestro", - }, - Ports: []corev1.ServicePort{ - { - Name: "grpc-broker", - Protocol: corev1.ProtocolTCP, - Port: 8091, - TargetPort: intstr.FromInt(8091), - }, - }, - Type: corev1.ServiceTypeClusterIP, - }, - } - _, err := consumer.ClientSet.CoreV1().Services("maestro").Create(ctx, grpcBrokerService, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }) - - It("ensure the nginx A resource is updated", func() { - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) - if err != nil { - return err - } - if *deploy.Spec.Replicas != 2 { - return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 2, got %d", deployA, *deploy.Spec.Replicas) - } - return nil - }, 3*time.Minute, 3*time.Second).ShouldNot(HaveOccurred()) - }) - - It("ensure the nginx B resource is deleted", func() { - Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) - if err != nil { - if errors.IsNotFound(err) { - return nil - } - return err - } - return fmt.Errorf("nginx B deployment %s still exists", deployB) - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("ensure the nginx C resource is created", func() { - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) - if err != nil { - return err - } - if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx C deployment %s, expected 1, got %d", deployC, *deploy.Spec.Replicas) - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("delete the nginx A and nginx C resources", func() { - resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceA.Id).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - - Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) - if err != nil { - if errors.IsNotFound(err) { - return nil - } - return err - } - return fmt.Errorf("nginx A deployment %s still exists", deployA) - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - - resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceC.Id).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - - Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) - if err != nil { - if errors.IsNotFound(err) { - return nil - } - return err - } - return fmt.Errorf("nginx C deployment %s still exists", deployC) - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - }) -}) +// var _ = Describe("Spec Resync After Reconnect", Ordered, Label("e2e-tests-spec-resync-reconnect"), func() { +// Context("Resource resync resource spec after maestro agent reconnects", func() { +// var maestroServerReplicas, mqttReplicas int +// var resourceA, resourceB, resourceC *openapi.Resource +// deployA := fmt.Sprintf("nginx-%s", rand.String(5)) +// deployB := fmt.Sprintf("nginx-%s", rand.String(5)) +// deployC := fmt.Sprintf("nginx-%s", rand.String(5)) +// It("post the nginx A resource to the maestro api", func() { +// res := helper.NewAPIResource(agentTestOpts.consumerName, deployA, 1) +// var resp *http.Response +// var err error +// resourceA, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusCreated)) +// Expect(*resourceA.Id).ShouldNot(BeEmpty()) + +// Eventually(func() error { +// deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) +// if err != nil { +// return err +// } +// if *deploy.Spec.Replicas != 1 { +// return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 1, got %d", deployA, *deploy.Spec.Replicas) +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("post the nginx B resource to the maestro api", func() { +// res := helper.NewAPIResource(agentTestOpts.consumerName, deployB, 1) +// var resp *http.Response +// var err error +// resourceB, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusCreated)) +// Expect(*resourceB.Id).ShouldNot(BeEmpty()) + +// Eventually(func() error { +// deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) +// if err != nil { +// return err +// } +// if *deploy.Spec.Replicas != 1 { +// return fmt.Errorf("unexpected replicas for nginx B deployment %s, expected 1, got %d", deployB, *deploy.Spec.Replicas) +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("delete the grpc-broker service for agent", func() { +// err := serverTestOpts.kubeClientSet.CoreV1().Services(serverTestOpts.serverNamespace).Delete(ctx, "maestro-grpc-broker", metav1.DeleteOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// }) + +// It("delete the mqtt-broker service for agent", func() { +// err := serverTestOpts.kubeClientSet.CoreV1().Services(serverTestOpts.serverNamespace).Delete(ctx, "maestro-mqtt-agent", metav1.DeleteOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// }) + +// It("rollout maestro server", func() { +// deploy, err := serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Get(ctx, "maestro", metav1.GetOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// maestroServerReplicas = int(*deploy.Spec.Replicas) +// deploy, err = serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Patch(ctx, "maestro", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ +// FieldManager: "serverTestOpts.kubeClientSet", +// }) +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) + +// // ensure no running maestro server pods +// Eventually(func() error { +// pods, err := serverTestOpts.kubeClientSet.CoreV1().Pods(serverTestOpts.serverNamespace).List(ctx, metav1.ListOptions{ +// LabelSelector: "app=maestro", +// }) +// if err != nil { +// return err +// } +// if len(pods.Items) > 0 { +// return fmt.Errorf("maestro server pods still running") +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + +// // patch maestro server replicas to maestroServerReplicas +// deploy, err = serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Patch(ctx, "maestro", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroServerReplicas)), metav1.PatchOptions{ +// FieldManager: "serverTestOpts.kubeClientSet", +// }) +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(*deploy.Spec.Replicas).To(Equal(int32(maestroServerReplicas))) + +// // ensure maestro server pod is up and running +// Eventually(func() error { +// pods, err := serverTestOpts.kubeClientSet.CoreV1().Pods(serverTestOpts.serverNamespace).List(ctx, metav1.ListOptions{ +// LabelSelector: "app=maestro", +// }) +// if err != nil { +// return err +// } +// if len(pods.Items) != maestroServerReplicas { +// return fmt.Errorf("unexpected maestro server pod count, expected %d, got %d", maestroServerReplicas, len(pods.Items)) +// } +// for _, pod := range pods.Items { +// if pod.Status.Phase != "Running" { +// return fmt.Errorf("maestro server pod not in running state") +// } +// if pod.Status.ContainerStatuses[0].State.Running == nil { +// return fmt.Errorf("maestro server container not in running state") +// } +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("rollout the mqtt-broker", func() { +// deploy, err := serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Get(ctx, "maestro-mqtt", metav1.GetOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// mqttReplicas = int(*deploy.Spec.Replicas) +// deploy, err = serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Patch(ctx, "maestro-mqtt", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ +// FieldManager: "serverTestOpts.kubeClientSet", +// }) +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) + +// // ensure no running mqtt-broker pods +// Eventually(func() error { +// pods, err := serverTestOpts.kubeClientSet.CoreV1().Pods(serverTestOpts.serverNamespace).List(ctx, metav1.ListOptions{ +// LabelSelector: "name=maestro-mqtt", +// }) +// if err != nil { +// return err +// } +// if len(pods.Items) > 0 { +// return fmt.Errorf("maestro-mqtt pods still running") +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + +// // patch mqtt-broker replicas to mqttReplicas +// deploy, err = serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Patch(ctx, "maestro-mqtt", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, mqttReplicas)), metav1.PatchOptions{ +// FieldManager: "serverTestOpts.kubeClientSet", +// }) +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(*deploy.Spec.Replicas).To(Equal(int32(mqttReplicas))) + +// // ensure mqtt-broker pod is up and running +// Eventually(func() error { +// pods, err := serverTestOpts.kubeClientSet.CoreV1().Pods(serverTestOpts.serverNamespace).List(ctx, metav1.ListOptions{ +// LabelSelector: "name=maestro-mqtt", +// }) +// if err != nil { +// return err +// } +// if len(pods.Items) != mqttReplicas { +// return fmt.Errorf("unexpected maestro-mqtt pod count, expected %d, got %d", mqttReplicas, len(pods.Items)) +// } +// for _, pod := range pods.Items { +// if pod.Status.Phase != "Running" { +// return fmt.Errorf("maestro-mqtt pod not in running state") +// } +// if pod.Status.ContainerStatuses[0].State.Running == nil { +// return fmt.Errorf("maestro-mqtt container not in running state") +// } +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("patch the nginx A resource", func() { +// newRes := helper.NewAPIResource(agentTestOpts.consumerName, deployA, 2) +// Eventually(func() error { +// patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(ctx, *resourceA.Id). +// ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resourceA.Version, Manifest: newRes.Manifest}).Execute() +// if err != nil { +// return err +// } +// if resp.StatusCode != http.StatusOK { +// return fmt.Errorf("unexpected status code, expected 200, got %d", resp.StatusCode) +// } +// if *patchedResource.Version != *resourceA.Version+1 { +// return fmt.Errorf("unexpected version, expected %d, got %d", *resourceA.Version+1, *patchedResource.Version) +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("ensure the nginx A resource is not updated", func() { +// Consistently(func() error { +// deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) +// if err != nil { +// return nil +// } +// if *deploy.Spec.Replicas != 1 { +// return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 1, got %d", deployA, *deploy.Spec.Replicas) +// } +// return nil +// }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("delete the nginx B resource", func() { +// resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceB.Id).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) +// }) + +// It("ensure the nginx B resource is not deleted", func() { +// Consistently(func() error { +// _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) +// if err != nil { +// if errors.IsNotFound(err) { +// return fmt.Errorf("nginx B deployment %s is deleted", deployB) +// } +// } +// return nil +// }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("post the nginx C resource to the maestro api", func() { +// res := helper.NewAPIResource(agentTestOpts.consumerName, deployC, 1) +// var resp *http.Response +// var err error +// resourceC, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusCreated)) +// Expect(*resourceC.Id).ShouldNot(BeEmpty()) +// }) + +// It("ensure the nginx C resource is not created", func() { +// Consistently(func() error { +// _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) +// if err == nil { +// return fmt.Errorf("nginx C deployment %s is created", deployC) +// } +// return nil +// }, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("recreate the mqtt-broker service for agent", func() { +// mqttAgentService := &corev1.Service{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "maestro-mqtt-agent", +// Namespace: serverTestOpts.serverNamespace, +// }, +// Spec: corev1.ServiceSpec{ +// Selector: map[string]string{ +// "name": "maestro-mqtt", +// }, +// Ports: []corev1.ServicePort{ +// { +// Name: "mosquitto", +// Protocol: corev1.ProtocolTCP, +// Port: 1883, +// TargetPort: intstr.FromInt(1883), +// }, +// }, +// Type: corev1.ServiceTypeClusterIP, +// }, +// } + +// _, err := serverTestOpts.kubeClientSet.CoreV1().Services(serverTestOpts.serverNamespace).Create(ctx, mqttAgentService, metav1.CreateOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// }) + +// It("recreate the grpc-broker service for agent", func() { +// grpcBrokerService := &corev1.Service{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "maestro-grpc-broker", +// Namespace: serverTestOpts.serverNamespace, +// }, +// Spec: corev1.ServiceSpec{ +// Selector: map[string]string{ +// "app": "maestro", +// }, +// Ports: []corev1.ServicePort{ +// { +// Name: "grpc-broker", +// Protocol: corev1.ProtocolTCP, +// Port: 8091, +// TargetPort: intstr.FromInt(8091), +// }, +// }, +// Type: corev1.ServiceTypeClusterIP, +// }, +// } +// _, err := serverTestOpts.kubeClientSet.CoreV1().Services(serverTestOpts.serverNamespace).Create(ctx, grpcBrokerService, metav1.CreateOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// }) + +// It("ensure the nginx A resource is updated", func() { +// Eventually(func() error { +// deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) +// if err != nil { +// return err +// } +// if *deploy.Spec.Replicas != 2 { +// return fmt.Errorf("unexpected replicas for nginx A deployment %s, expected 2, got %d", deployA, *deploy.Spec.Replicas) +// } +// return nil +// }, 3*time.Minute, 3*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("ensure the nginx B resource is deleted", func() { +// Eventually(func() error { +// _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployB, metav1.GetOptions{}) +// if err != nil { +// if errors.IsNotFound(err) { +// return nil +// } +// return err +// } +// return fmt.Errorf("nginx B deployment %s still exists", deployB) +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("ensure the nginx C resource is created", func() { +// Eventually(func() error { +// deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) +// if err != nil { +// return err +// } +// if *deploy.Spec.Replicas != 1 { +// return fmt.Errorf("unexpected replicas for nginx C deployment %s, expected 1, got %d", deployC, *deploy.Spec.Replicas) +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("delete the nginx A and nginx C resources", func() { +// resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceA.Id).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + +// Eventually(func() error { +// _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployA, metav1.GetOptions{}) +// if err != nil { +// if errors.IsNotFound(err) { +// return nil +// } +// return err +// } +// return fmt.Errorf("nginx A deployment %s still exists", deployA) +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + +// resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resourceC.Id).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + +// Eventually(func() error { +// _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, deployC, metav1.GetOptions{}) +// if err != nil { +// if errors.IsNotFound(err) { +// return nil +// } +// return err +// } +// return fmt.Errorf("nginx C deployment %s still exists", deployC) +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) +// }) +// }) diff --git a/test/e2e/pkg/status_resync_test.go b/test/e2e/pkg/status_resync_test.go index a2292333..0b500274 100644 --- a/test/e2e/pkg/status_resync_test.go +++ b/test/e2e/pkg/status_resync_test.go @@ -14,7 +14,6 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/rand" ) @@ -24,7 +23,7 @@ var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status var resource *openapi.Resource name := fmt.Sprintf("nginx-%s", rand.String(5)) It("post the nginx resource with non-default service account to the maestro api", func() { - res := helper.NewAPIResourceWithSA(consumer.Name, name, name, 1) + res := helper.NewAPIResourceWithSA(agentTestOpts.consumerName, name, name, 1) var resp *http.Response var err error resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() @@ -33,7 +32,7 @@ var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status Expect(*resource.Id).ShouldNot(BeEmpty()) Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) + deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } @@ -66,20 +65,20 @@ var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status }) It("shut down maestro server", func() { - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Get(ctx, "maestro", metav1.GetOptions{}) + deploy, err := serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Get(ctx, "maestro", metav1.GetOptions{}) Expect(err).ShouldNot(HaveOccurred()) maestroServerReplicas = int(*deploy.Spec.Replicas) // patch maestro server replicas to 0 - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ - FieldManager: "testConsumer.ClientSet", + deploy, err = serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Patch(ctx, "maestro", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ + FieldManager: "serverTestOpts.kubeClientSet", }) Expect(err).ShouldNot(HaveOccurred()) Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) // ensure no running maestro server pods Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ + pods, err := serverTestOpts.kubeClientSet.CoreV1().Pods(serverTestOpts.serverNamespace).List(ctx, metav1.ListOptions{ LabelSelector: "app=maestro", }) if err != nil { @@ -93,7 +92,7 @@ var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status }) It("create serviceaccount for nginx deployment", func() { - _, err := consumer.ClientSet.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ + _, err := agentTestOpts.kubeClientSet.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, @@ -101,21 +100,21 @@ var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status Expect(err).ShouldNot(HaveOccurred()) // delete the nginx deployment to tigger recreating - err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, name, metav1.DeleteOptions{}) + err = agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Delete(ctx, name, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) It("restart maestro server", func() { // patch maestro server replicas back - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroServerReplicas)), metav1.PatchOptions{ - FieldManager: "testConsumer.ClientSet", + deploy, err := serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Patch(ctx, "maestro", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, maestroServerReplicas)), metav1.PatchOptions{ + FieldManager: "serverTestOpts.kubeClientSet", }) Expect(err).ShouldNot(HaveOccurred()) Expect(*deploy.Spec.Replicas).To(Equal(int32(maestroServerReplicas))) // ensure maestro server pod is up and running Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ + pods, err := serverTestOpts.kubeClientSet.CoreV1().Pods(serverTestOpts.serverNamespace).List(ctx, metav1.ListOptions{ LabelSelector: "app=maestro", }) if err != nil { @@ -162,7 +161,7 @@ var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) + _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { return nil @@ -172,195 +171,195 @@ var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status return fmt.Errorf("nginx deployment still exists") }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) - err = consumer.ClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, name, metav1.DeleteOptions{}) + err = agentTestOpts.kubeClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, name, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) }) }) -var _ = Describe("Status Resync After Reconnect", Ordered, Label("e2e-tests-status-resync-reconnect"), func() { - Context("Resource resync resource status after maestro server reconnects", func() { - var mqttReplicas int - var resource *openapi.Resource - name := fmt.Sprintf("nginx-%s", rand.String(5)) - It("post the nginx resource with non-default service account to the maestro api", func() { - res := helper.NewAPIResourceWithSA(consumer.Name, name, name, 1) - var resp *http.Response - var err error - resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusCreated)) - Expect(*resource.Id).ShouldNot(BeEmpty()) - - Eventually(func() error { - deploy, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return err - } - if *deploy.Spec.Replicas != 1 { - return fmt.Errorf("unexpected replicas for nginx deployment %s, expected 1, got %d", name, *deploy.Spec.Replicas) - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - - gotResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, *resource.Id).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusOK)) - Expect(*gotResource.Id).To(Equal(*resource.Id)) - Expect(*gotResource.Version).To(Equal(*resource.Version)) - - Eventually(func() error { - gotResource, _, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, *resource.Id).Execute() - if err != nil { - return err - } - statusJSON, err := json.Marshal(gotResource.Status) - if err != nil { - return err - } - if !strings.Contains(string(statusJSON), "error looking up service account default/nginx") { - return fmt.Errorf("unexpected status, expected error looking up service account default/nginx, got %s", string(statusJSON)) - } - return nil - }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) - }) - - It("delete the mqtt-broker service for server", func() { - err := consumer.ClientSet.CoreV1().Services("maestro").Delete(ctx, "maestro-mqtt-server", metav1.DeleteOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }) - - It("create serviceaccount for nginx deployment", func() { - _, err := consumer.ClientSet.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - }, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - - // delete the nginx deployment to tigger recreating - err = consumer.ClientSet.AppsV1().Deployments("default").Delete(ctx, name, metav1.DeleteOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }) - - It("Rollout the mqtt-broker", func() { - deploy, err := consumer.ClientSet.AppsV1().Deployments("maestro").Get(ctx, "maestro-mqtt", metav1.GetOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - mqttReplicas = int(*deploy.Spec.Replicas) - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro-mqtt", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ - FieldManager: "testConsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) - - // ensure no running mqtt-broker pods - Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ - LabelSelector: "name=maestro-mqtt", - }) - if err != nil { - return err - } - if len(pods.Items) > 0 { - return fmt.Errorf("maestro-mqtt pods still running") - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - - // patch mqtt-broker replicas to mqttReplicas - deploy, err = consumer.ClientSet.AppsV1().Deployments("maestro").Patch(ctx, "maestro-mqtt", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, mqttReplicas)), metav1.PatchOptions{ - FieldManager: "testConsumer.ClientSet", - }) - Expect(err).ShouldNot(HaveOccurred()) - Expect(*deploy.Spec.Replicas).To(Equal(int32(mqttReplicas))) - - // ensure mqtt-broker pod is up and running - Eventually(func() error { - pods, err := consumer.ClientSet.CoreV1().Pods("maestro").List(ctx, metav1.ListOptions{ - LabelSelector: "name=maestro-mqtt", - }) - if err != nil { - return err - } - if len(pods.Items) != mqttReplicas { - return fmt.Errorf("unexpected maestro-mqtt pod count, expected %d, got %d", mqttReplicas, len(pods.Items)) - } - for _, pod := range pods.Items { - if pod.Status.Phase != "Running" { - return fmt.Errorf("maestro-mqtt pod not in running state") - } - if pod.Status.ContainerStatuses[0].State.Running == nil { - return fmt.Errorf("maestro-mqtt container not in running state") - } - } - return nil - }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) - }) - - It("recreate the mqtt-broker service for server", func() { - mqttServerService := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "maestro-mqtt-server", - Namespace: "maestro", - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - "name": "maestro-mqtt", - }, - Ports: []corev1.ServicePort{ - { - Name: "mosquitto", - Protocol: corev1.ProtocolTCP, - Port: 1883, - TargetPort: intstr.FromInt(1883), - }, - }, - Type: corev1.ServiceTypeClusterIP, - }, - } - - _, err := consumer.ClientSet.CoreV1().Services("maestro").Create(ctx, mqttServerService, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }) - - It("ensure the resource status is resynced", func() { - Eventually(func() error { - gotResource, _, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, *resource.Id).Execute() - if err != nil { - return err - } - if _, ok := gotResource.Status["ContentStatus"]; !ok { - return fmt.Errorf("unexpected status, expected contains ContentStatus, got %v", gotResource.Status) - } - statusJSON, err := json.Marshal(gotResource.Status) - if err != nil { - return err - } - if strings.Contains(string(statusJSON), "error looking up service account default/nginx") { - return fmt.Errorf("unexpected status, should not contain error looking up service account default/nginx, got %s", string(statusJSON)) - } - return nil - }, 3*time.Minute, 3*time.Second).ShouldNot(HaveOccurred()) - }) - - It("delete the nginx resource", func() { - resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource.Id).Execute() - Expect(err).ShouldNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) - - Eventually(func() error { - _, err := consumer.ClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) - if err != nil { - if errors.IsNotFound(err) { - return nil - } - return err - } - return fmt.Errorf("nginx deployment still exists") - }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) - - err = consumer.ClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, name, metav1.DeleteOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }) - }) -}) +// var _ = Describe("Status Resync After Reconnect", Ordered, Label("e2e-tests-status-resync-reconnect"), func() { +// Context("Resource resync resource status after maestro server reconnects", func() { +// var mqttReplicas int +// var resource *openapi.Resource +// name := fmt.Sprintf("nginx-%s", rand.String(5)) +// It("post the nginx resource with non-default service account to the maestro api", func() { +// res := helper.NewAPIResourceWithSA(agentTestOpts.consumerName, name, name, 1) +// var resp *http.Response +// var err error +// resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(ctx).Resource(res).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusCreated)) +// Expect(*resource.Id).ShouldNot(BeEmpty()) + +// Eventually(func() error { +// deploy, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) +// if err != nil { +// return err +// } +// if *deploy.Spec.Replicas != 1 { +// return fmt.Errorf("unexpected replicas for nginx deployment %s, expected 1, got %d", name, *deploy.Spec.Replicas) +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + +// gotResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, *resource.Id).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusOK)) +// Expect(*gotResource.Id).To(Equal(*resource.Id)) +// Expect(*gotResource.Version).To(Equal(*resource.Version)) + +// Eventually(func() error { +// gotResource, _, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, *resource.Id).Execute() +// if err != nil { +// return err +// } +// statusJSON, err := json.Marshal(gotResource.Status) +// if err != nil { +// return err +// } +// if !strings.Contains(string(statusJSON), "error looking up service account default/nginx") { +// return fmt.Errorf("unexpected status, expected error looking up service account default/nginx, got %s", string(statusJSON)) +// } +// return nil +// }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("delete the mqtt-broker service for server", func() { +// err := serverTestOpts.kubeClientSet.CoreV1().Services(serverTestOpts.serverNamespace).Delete(ctx, "maestro-mqtt-server", metav1.DeleteOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// }) + +// It("create serviceaccount for nginx deployment", func() { +// _, err := agentTestOpts.kubeClientSet.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: name, +// }, +// }, metav1.CreateOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) + +// // delete the nginx deployment to tigger recreating +// err = agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Delete(ctx, name, metav1.DeleteOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// }) + +// It("Rollout the mqtt-broker", func() { +// deploy, err := serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Get(ctx, "maestro-mqtt", metav1.GetOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// mqttReplicas = int(*deploy.Spec.Replicas) +// deploy, err = serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Patch(ctx, "maestro-mqtt", types.MergePatchType, []byte(`{"spec":{"replicas":0}}`), metav1.PatchOptions{ +// FieldManager: "serverTestOpts.kubeClientSet", +// }) +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(*deploy.Spec.Replicas).To(Equal(int32(0))) + +// // ensure no running mqtt-broker pods +// Eventually(func() error { +// pods, err := serverTestOpts.kubeClientSet.CoreV1().Pods(serverTestOpts.serverNamespace).List(ctx, metav1.ListOptions{ +// LabelSelector: "name=maestro-mqtt", +// }) +// if err != nil { +// return err +// } +// if len(pods.Items) > 0 { +// return fmt.Errorf("maestro-mqtt pods still running") +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + +// // patch mqtt-broker replicas to mqttReplicas +// deploy, err = serverTestOpts.kubeClientSet.AppsV1().Deployments(serverTestOpts.serverNamespace).Patch(ctx, "maestro-mqtt", types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, mqttReplicas)), metav1.PatchOptions{ +// FieldManager: "serverTestOpts.kubeClientSet", +// }) +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(*deploy.Spec.Replicas).To(Equal(int32(mqttReplicas))) + +// // ensure mqtt-broker pod is up and running +// Eventually(func() error { +// pods, err := serverTestOpts.kubeClientSet.CoreV1().Pods(serverTestOpts.serverNamespace).List(ctx, metav1.ListOptions{ +// LabelSelector: "name=maestro-mqtt", +// }) +// if err != nil { +// return err +// } +// if len(pods.Items) != mqttReplicas { +// return fmt.Errorf("unexpected maestro-mqtt pod count, expected %d, got %d", mqttReplicas, len(pods.Items)) +// } +// for _, pod := range pods.Items { +// if pod.Status.Phase != "Running" { +// return fmt.Errorf("maestro-mqtt pod not in running state") +// } +// if pod.Status.ContainerStatuses[0].State.Running == nil { +// return fmt.Errorf("maestro-mqtt container not in running state") +// } +// } +// return nil +// }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("recreate the mqtt-broker service for server", func() { +// mqttServerService := &corev1.Service{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "maestro-mqtt-server", +// Namespace: serverTestOpts.serverNamespace, +// }, +// Spec: corev1.ServiceSpec{ +// Selector: map[string]string{ +// "name": "maestro-mqtt", +// }, +// Ports: []corev1.ServicePort{ +// { +// Name: "mosquitto", +// Protocol: corev1.ProtocolTCP, +// Port: 1883, +// TargetPort: intstr.FromInt(1883), +// }, +// }, +// Type: corev1.ServiceTypeClusterIP, +// }, +// } + +// _, err := serverTestOpts.kubeClientSet.CoreV1().Services(serverTestOpts.serverNamespace).Create(ctx, mqttServerService, metav1.CreateOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// }) + +// It("ensure the resource status is resynced", func() { +// Eventually(func() error { +// gotResource, _, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, *resource.Id).Execute() +// if err != nil { +// return err +// } +// if _, ok := gotResource.Status["ContentStatus"]; !ok { +// return fmt.Errorf("unexpected status, expected contains ContentStatus, got %v", gotResource.Status) +// } +// statusJSON, err := json.Marshal(gotResource.Status) +// if err != nil { +// return err +// } +// if strings.Contains(string(statusJSON), "error looking up service account default/nginx") { +// return fmt.Errorf("unexpected status, should not contain error looking up service account default/nginx, got %s", string(statusJSON)) +// } +// return nil +// }, 3*time.Minute, 3*time.Second).ShouldNot(HaveOccurred()) +// }) + +// It("delete the nginx resource", func() { +// resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(ctx, *resource.Id).Execute() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + +// Eventually(func() error { +// _, err := agentTestOpts.kubeClientSet.AppsV1().Deployments("default").Get(ctx, name, metav1.GetOptions{}) +// if err != nil { +// if errors.IsNotFound(err) { +// return nil +// } +// return err +// } +// return fmt.Errorf("nginx deployment still exists") +// }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) + +// err = agentTestOpts.kubeClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, name, metav1.DeleteOptions{}) +// Expect(err).ShouldNot(HaveOccurred()) +// }) +// }) +// }) diff --git a/test/e2e/pkg/suite_test.go b/test/e2e/pkg/suite_test.go index 0af54542..e33b5e4b 100644 --- a/test/e2e/pkg/suite_test.go +++ b/test/e2e/pkg/suite_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes" @@ -32,21 +33,35 @@ import ( "github.com/openshift-online/maestro/test" ) +type agentTestOptions struct { + agentNamespace string + consumerName string + kubeConfig string + kubeClientSet kubernetes.Interface + workClientSet workclientset.Interface +} + +type serverTestOptions struct { + serverNamespace string + kubeConfig string + kubeClientSet kubernetes.Interface +} + var ( + serverTestOpts *serverTestOptions + agentTestOpts *agentTestOptions apiServerAddress string - grpcServerAddress string - grpcClient pbv1.CloudEventServiceClient - workClient workv1client.WorkV1Interface apiClient *openapi.APIClient - sourceID string + grpcServerAddress string + grpcCertDir string grpcConn *grpc.ClientConn + grpcClient pbv1.CloudEventServiceClient grpcOptions *grpcoptions.GRPCOptions - consumer *ConsumerOptions + sourceID string + sourceWorkClient workv1client.WorkV1Interface helper *test.Helper cancel context.CancelFunc ctx context.Context - grpcCertDir string - kubeWorkClient workclientset.Interface ) func TestE2E(t *testing.T) { @@ -56,12 +71,16 @@ func TestE2E(t *testing.T) { } func init() { - consumer = &ConsumerOptions{} + serverTestOpts = &serverTestOptions{} + agentTestOpts = &agentTestOptions{} klog.SetOutput(GinkgoWriter) - flag.StringVar(&apiServerAddress, "api-server", "", "Maestro API server address") + flag.StringVar(&apiServerAddress, "api-server", "", "Maestro Restful API server address") flag.StringVar(&grpcServerAddress, "grpc-server", "", "Maestro gRPC server address") - flag.StringVar(&consumer.Name, "consumer-name", "", "Consumer name is used to identify the consumer") - flag.StringVar(&consumer.KubeConfig, "consumer-kubeconfig", "", "Path to kubeconfig file") + flag.StringVar(&serverTestOpts.serverNamespace, "server-namespace", "maestro", "Namespace where the maestro server is running") + flag.StringVar(&serverTestOpts.kubeConfig, "server-kubeconfig", "", "Path to the kubeconfig file for the maestro server") + flag.StringVar(&agentTestOpts.agentNamespace, "agent-namespace", "maestro-agent", "Namespace where the maestro agent is running") + flag.StringVar(&agentTestOpts.consumerName, "consumer-name", "", "Consumer name is used to identify the consumer") + flag.StringVar(&agentTestOpts.kubeConfig, "agent-kubeconfig", "", "Path to the kubeconfig file for the maestro agent") } var _ = BeforeSuite(func() { @@ -89,45 +108,57 @@ var _ = BeforeSuite(func() { } apiClient = openapi.NewAPIClient(cfg) - grpcCertDir, err := os.MkdirTemp("/tmp", "maestro-grpc-certs-") + var err error + grpcCertDir, err = os.MkdirTemp("/tmp", "maestro-grpc-certs-") Expect(err).To(Succeed()) - // validate the consumer kubeconfig and name - restConfig, err := clientcmd.BuildConfigFromFlags("", consumer.KubeConfig) - Expect(err).To(Succeed()) - consumer.ClientSet, err = kubernetes.NewForConfig(restConfig) + // validate the server kubeconfig and initialize the kube client + serverRestConfig, err := clientcmd.BuildConfigFromFlags("", serverTestOpts.kubeConfig) Expect(err).To(Succeed()) - kubeWorkClient, err = workclientset.NewForConfig(restConfig) + serverTestOpts.kubeClientSet, err = kubernetes.NewForConfig(serverRestConfig) Expect(err).To(Succeed()) - Expect(consumer.Name).NotTo(BeEmpty(), "consumer name is not provided") - grpcCertSrt, err := consumer.ClientSet.CoreV1().Secrets("maestro").Get(ctx, "maestro-grpc-cert", metav1.GetOptions{}) + // validate the agent consumer name && kubeconfig and initialize the kube client & work client + Expect(agentTestOpts.consumerName).NotTo(BeEmpty(), "consumer name is not provided") + agentRestConfig, err := clientcmd.BuildConfigFromFlags("", agentTestOpts.kubeConfig) Expect(err).To(Succeed()) - grpcServerCAFile := fmt.Sprintf("%s/ca.crt", grpcCertDir) - grpcClientCert := fmt.Sprintf("%s/client.crt", grpcCertDir) - grpcClientKey := fmt.Sprintf("%s/client.key", grpcCertDir) - Expect(os.WriteFile(grpcServerCAFile, grpcCertSrt.Data["ca.crt"], 0644)).To(Succeed()) - Expect(os.WriteFile(grpcClientCert, grpcCertSrt.Data["client.crt"], 0644)).To(Succeed()) - Expect(os.WriteFile(grpcClientKey, grpcCertSrt.Data["client.key"], 0644)).To(Succeed()) - - grpcClientTokenSrt, err := consumer.ClientSet.CoreV1().Secrets("maestro").Get(ctx, "grpc-client-token", metav1.GetOptions{}) + agentTestOpts.kubeClientSet, err = kubernetes.NewForConfig(agentRestConfig) + Expect(err).To(Succeed()) + agentTestOpts.workClientSet, err = workclientset.NewForConfig(agentRestConfig) Expect(err).To(Succeed()) - grpcClientTokenFile := fmt.Sprintf("%s/token", grpcCertDir) - Expect(os.WriteFile(grpcClientTokenFile, grpcClientTokenSrt.Data["token"], 0644)).To(Succeed()) + // initialize the grpc source options grpcOptions = grpcoptions.NewGRPCOptions() grpcOptions.URL = grpcServerAddress - grpcOptions.CAFile = grpcServerCAFile - grpcOptions.TokenFile = grpcClientTokenFile sourceID = "sourceclient-test" + rand.String(5) + grpcCertSrt, err := serverTestOpts.kubeClientSet.CoreV1().Secrets(serverTestOpts.serverNamespace).Get(ctx, "maestro-grpc-cert", metav1.GetOptions{}) + if !errors.IsNotFound(err) { + // retrieve the grpc cert from the maestro server and write to the grpc cert dir + grpcServerCAFile := fmt.Sprintf("%s/ca.crt", grpcCertDir) + grpcClientCert := fmt.Sprintf("%s/client.crt", grpcCertDir) + grpcClientKey := fmt.Sprintf("%s/client.key", grpcCertDir) + Expect(os.WriteFile(grpcServerCAFile, grpcCertSrt.Data["ca.crt"], 0644)).To(Succeed()) + Expect(os.WriteFile(grpcClientCert, grpcCertSrt.Data["client.crt"], 0644)).To(Succeed()) + Expect(os.WriteFile(grpcClientKey, grpcCertSrt.Data["client.key"], 0644)).To(Succeed()) + grpcClientTokenSrt, err := serverTestOpts.kubeClientSet.CoreV1().Secrets(serverTestOpts.serverNamespace).Get(ctx, "grpc-client-token", metav1.GetOptions{}) + Expect(err).To(Succeed()) + grpcClientTokenFile := fmt.Sprintf("%s/token", grpcCertDir) + Expect(os.WriteFile(grpcClientTokenFile, grpcClientTokenSrt.Data["token"], 0644)).To(Succeed()) + // set CAFile and TokenFile for grpc authz + grpcOptions.CAFile = grpcServerCAFile + grpcOptions.TokenFile = grpcClientTokenFile + // create the clusterrole for grpc authz + Expect(helper.CreateGRPCAuthRule(ctx, serverTestOpts.kubeClientSet, "grpc-pub-sub", "source", sourceID, []string{"pub", "sub"})).To(Succeed()) + + grpcConn, err = helper.CreateGRPCConn(grpcServerAddress, grpcServerCAFile, grpcClientTokenFile) + Expect(err).To(Succeed()) + } else { + grpcConn, err = helper.CreateGRPCConn(grpcServerAddress, "", "") + Expect(err).To(Succeed()) + } - // create the clusterrole for grpc authz - Expect(helper.CreateGRPCAuthRule(ctx, consumer.ClientSet, "grpc-pub-sub", "source", sourceID, []string{"pub", "sub"})).To(Succeed()) - grpcConn, err = helper.CreateGRPCConn(grpcServerAddress, grpcServerCAFile, grpcClientTokenFile) - Expect(err).To(Succeed()) grpcClient = pbv1.NewCloudEventServiceClient(grpcConn) - - workClient, err = grpcsource.NewMaestroGRPCSourceWorkClient( + sourceWorkClient, err = grpcsource.NewMaestroGRPCSourceWorkClient( ctx, apiClient, grpcOptions, @@ -144,17 +175,11 @@ var _ = AfterSuite(func() { cancel() }) -type ConsumerOptions struct { - Name string - KubeConfig string - ClientSet *kubernetes.Clientset -} - func dumpDebugInfo() { // dump the maestro server logs - dumpPodLogs(ctx, consumer.ClientSet, "app=maestro", "maestro") + dumpPodLogs(ctx, serverTestOpts.kubeClientSet, "app=maestro", serverTestOpts.serverNamespace) // dump the maestro agent ogs - dumpPodLogs(ctx, consumer.ClientSet, "app=maestro-agent", "maestro-agent") + dumpPodLogs(ctx, agentTestOpts.kubeClientSet, "app=maestro-agent", agentTestOpts.agentNamespace) } func dumpPodLogs(ctx context.Context, kubeClient kubernetes.Interface, podSelector, podNamespace string) error { diff --git a/test/factories.go b/test/factories.go index 85a6f97e..96c51328 100755 --- a/test/factories.go +++ b/test/factories.go @@ -500,36 +500,41 @@ func (helper *Helper) CreateGRPCAuthRule(ctx context.Context, kubeClient kuberne } func (helper *Helper) CreateGRPCConn(serverAddr, serverCAFile, tokenFile string) (*grpc.ClientConn, error) { - certPool, err := x509.SystemCertPool() - if err != nil { - return nil, err - } + if serverCAFile == "" || tokenFile == "" { + // no TLS and authz + return grpc.Dial(serverAddr, grpc.WithInsecure()) + } else { + certPool, err := x509.SystemCertPool() + if err != nil { + return nil, err + } - caPEM, err := os.ReadFile(serverCAFile) - if err != nil { - return nil, err - } + caPEM, err := os.ReadFile(serverCAFile) + if err != nil { + return nil, err + } - ok := certPool.AppendCertsFromPEM(caPEM) - if !ok { - return nil, fmt.Errorf("failed to append server CA certificate") - } + ok := certPool.AppendCertsFromPEM(caPEM) + if !ok { + return nil, fmt.Errorf("failed to append server CA certificate") + } - tlsConfig := &tls.Config{ - RootCAs: certPool, - MinVersion: tls.VersionTLS13, - MaxVersion: tls.VersionTLS13, - } + tlsConfig := &tls.Config{ + RootCAs: certPool, + MinVersion: tls.VersionTLS13, + MaxVersion: tls.VersionTLS13, + } - token, err := os.ReadFile(tokenFile) - if err != nil { - return nil, err - } + token, err := os.ReadFile(tokenFile) + if err != nil { + return nil, err + } - perRPCCred := oauth.TokenSource{ - TokenSource: oauth2.StaticTokenSource(&oauth2.Token{ - AccessToken: string(token), - })} + perRPCCred := oauth.TokenSource{ + TokenSource: oauth2.StaticTokenSource(&oauth2.Token{ + AccessToken: string(token), + })} - return grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), grpc.WithPerRPCCredentials(perRPCCred)) + return grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), grpc.WithPerRPCCredentials(perRPCCred)) + } } From 85faa5f055b371d7095953b78d2384f64f3ead95 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Thu, 24 Oct 2024 16:29:40 +0800 Subject: [PATCH 38/67] add more examples. (#204) Signed-off-by: morvencao --- README.md | 2 +- examples/grpc/README.md | 41 +++++ examples/grpc/cloudevent-bundle-delete.json | 12 ++ .../grpc/cloudevent-bundle-status-resync.json | 13 ++ examples/grpc/cloudevent-bundle-update.json | 80 +++++++++ examples/{ => grpc}/cloudevent-bundle.json | 44 ++--- examples/grpc/cloudevent-delete.json | 12 ++ examples/grpc/cloudevent-status-resync.json | 13 ++ examples/grpc/cloudevent-update.json | 62 +++++++ examples/grpc/cloudevent.json | 62 +++++++ examples/{ => grpc}/grpcclient.go | 31 ++++ examples/resource-in-db.md | 154 ++++++++++++++++++ examples/resource.json | 38 +++++ 13 files changed, 541 insertions(+), 23 deletions(-) create mode 100644 examples/grpc/README.md create mode 100644 examples/grpc/cloudevent-bundle-delete.json create mode 100644 examples/grpc/cloudevent-bundle-status-resync.json create mode 100644 examples/grpc/cloudevent-bundle-update.json rename examples/{ => grpc}/cloudevent-bundle.json (66%) create mode 100644 examples/grpc/cloudevent-delete.json create mode 100644 examples/grpc/cloudevent-status-resync.json create mode 100644 examples/grpc/cloudevent-update.json create mode 100644 examples/grpc/cloudevent.json rename examples/{ => grpc}/grpcclient.go (74%) create mode 100644 examples/resource-in-db.md create mode 100644 examples/resource.json diff --git a/README.md b/README.md index 5376d0de..f7d68652 100755 --- a/README.md +++ b/README.md @@ -356,7 +356,7 @@ $ oc -n maestro port-forward svc/maestro-grpc 8090 & 3. Create a resource bundle with multiple resources using the gRPC client, for example: ```shell -go run ./examples/grpcclient.go -cloudevents_json_file ./examples/cloudevent-bundle.json -grpc_server localhost:8090 +go run ./examples/grpc/grpcclient.go -cloudevents_json_file ./examples/grpc/cloudevent-bundle.json -grpc_server localhost:8090 ``` 4. Get the resource bundle with multiple resources, for example: diff --git a/examples/grpc/README.md b/examples/grpc/README.md new file mode 100644 index 00000000..67d7ac2b --- /dev/null +++ b/examples/grpc/README.md @@ -0,0 +1,41 @@ +# CURD Resource/Bundle with gRPC Client + +## Preparation + +1. Enable gRPC server by passing `--enable-grpc-server=true` to the maestro server start command, for example: + +```shell +$ oc -n maestro patch deploy/maestro --type=json -p='[{"op": "add", "path": "/spec/template/spec/containers/0/command/-", "value": "--enable-grpc-server=true"}]' +``` + +2. Port-forward the gRPC service to your local machine, for example: + +```shell +$ oc -n maestro port-forward svc/maestro-grpc 8090 & +``` + +## Operate Resource with gRPC client + +```shell +# create +go run ./grpcclient.go -grpc_server localhost:8090 -cloudevents_json_file ./cloudevent.json + +# update +go run ./grpcclient.go -grpc_server localhost:8090 -cloudevents_json_file ./cloudevent-update.json + +# delete +go run ./grpcclient.go -grpc_server localhost:8090 -cloudevents_json_file ./cloudevent-delete.json +``` + +## Operate Resource Bundle with gRPC client + +```shell +# create +go run ./grpcclient.go -grpc_server localhost:8090 -cloudevents_json_file ./cloudevent-bundle.json + +# update +go run ./grpcclient.go -grpc_server localhost:8090 -cloudevents_json_file ./cloudevent-bundle-update.json + +# delete +go run ./grpcclient.go -grpc_server localhost:8090 -cloudevents_json_file ./cloudevent-bundle-delete.json +``` diff --git a/examples/grpc/cloudevent-bundle-delete.json b/examples/grpc/cloudevent-bundle-delete.json new file mode 100644 index 00000000..bf035487 --- /dev/null +++ b/examples/grpc/cloudevent-bundle-delete.json @@ -0,0 +1,12 @@ +{ + "specversion": "1.0", + "id": "aa27051a-5578-4e03-b737-5d6416d09694", + "type": "io.open-cluster-management.works.v1alpha1.manifestbundles.spec.delete_request", + "source": "grpc", + "clustername": "cluster1", + "resourceid": "68ebf474-6709-48bb-b760-386181268064", + "resourceversion": 1, + "deletiontimestamp": "2024-10-15T09:54:06.582625606Z", + "datacontenttype": "application/json", + "data": {} +} \ No newline at end of file diff --git a/examples/grpc/cloudevent-bundle-status-resync.json b/examples/grpc/cloudevent-bundle-status-resync.json new file mode 100644 index 00000000..06d4ff92 --- /dev/null +++ b/examples/grpc/cloudevent-bundle-status-resync.json @@ -0,0 +1,13 @@ +{ + "specversion": "1.0", + "id": "ff8b8e9b-d433-4707-bedd-66d52bbfb9f1", + "type": "io.open-cluster-management.works.v1alpha1.manifestbundles.status.resync_request", + "source": "grpc", + "time": "2024-10-15T17:31:05Z", + "clustername": "", + "originalsource": "", + "datacontenttype": "application/json", + "data": { + "statusHashes": [] + } +} \ No newline at end of file diff --git a/examples/grpc/cloudevent-bundle-update.json b/examples/grpc/cloudevent-bundle-update.json new file mode 100644 index 00000000..388f491c --- /dev/null +++ b/examples/grpc/cloudevent-bundle-update.json @@ -0,0 +1,80 @@ +{ + "specversion": "1.0", + "id": "9dbcc8ec-c92e-4686-8ea3-0a0def70fa06", + "type": "io.open-cluster-management.works.v1alpha1.manifestbundles.spec.update_request", + "source": "grpc", + "clustername": "cluster1", + "resourceid": "68ebf474-6709-48bb-b760-386181268064", + "resourceversion": 1, + "datacontenttype": "application/json", + "data": { + "manifests": [ + { + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": { + "name": "web", + "namespace": "default" + } + }, + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "web", + "namespace": "default" + }, + "spec": { + "replicas": 2, + "selector": { + "matchLabels": { + "app": "web" + } + }, + "template": { + "metadata": { + "labels": { + "app": "web" + } + }, + "spec": { + "containers": [ + { + "image": "nginxinc/nginx-unprivileged", + "name": "nginx" + } + ] + } + } + } + } + ], + "deleteOption": { + "propagationPolicy": "Foreground" + }, + "manifestConfigs": [ + { + "resourceIdentifier": { + "group": "apps", + "resource": "deployments", + "namespace": "default", + "name": "web" + }, + "feedbackRules": [ + { + "type": "JSONPaths", + "jsonPaths": [ + { + "name": "status", + "path": ".status" + } + ] + } + ], + "updateStrategy": { + "type": "ServerSideApply" + } + } + ] + } +} \ No newline at end of file diff --git a/examples/cloudevent-bundle.json b/examples/grpc/cloudevent-bundle.json similarity index 66% rename from examples/cloudevent-bundle.json rename to examples/grpc/cloudevent-bundle.json index 54b03d7a..269b2be0 100644 --- a/examples/cloudevent-bundle.json +++ b/examples/grpc/cloudevent-bundle.json @@ -18,36 +18,36 @@ } }, { - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "name": "web", - "namespace": "default" - }, - "spec": { - "replicas": 1, - "selector": { - "matchLabels": { - "app": "web" - } + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "web", + "namespace": "default" }, - "template": { - "metadata": { - "labels": { + "spec": { + "replicas": 1, + "selector": { + "matchLabels": { "app": "web" } }, - "spec": { - "containers": [ - { - "image": "nginxinc/nginx-unprivileged", - "name": "nginx" + "template": { + "metadata": { + "labels": { + "app": "web" } - ] + }, + "spec": { + "containers": [ + { + "image": "nginxinc/nginx-unprivileged", + "name": "nginx" + } + ] + } } } } - } ], "deleteOption": { "propagationPolicy": "Foreground" diff --git a/examples/grpc/cloudevent-delete.json b/examples/grpc/cloudevent-delete.json new file mode 100644 index 00000000..793365c7 --- /dev/null +++ b/examples/grpc/cloudevent-delete.json @@ -0,0 +1,12 @@ +{ + "specversion": "1.0", + "id": "e718bb21-e8c8-436f-b6a4-16a5afd17caf", + "type": "io.open-cluster-management.works.v1alpha1.manifests.spec.delete_request", + "source": "grpc", + "clustername": "cluster1", + "resourceid": "eec95cda-03d6-4514-a9bd-29da9cf7ede2", + "deletiontimestamp": "2024-10-15T09:46:06.582625606Z", + "resourceversion": 1, + "datacontenttype": "application/json", + "data": {} +} \ No newline at end of file diff --git a/examples/grpc/cloudevent-status-resync.json b/examples/grpc/cloudevent-status-resync.json new file mode 100644 index 00000000..586f3587 --- /dev/null +++ b/examples/grpc/cloudevent-status-resync.json @@ -0,0 +1,13 @@ +{ + "specversion": "1.0", + "id": "ff8b8e9b-d433-4707-bedd-66d52bbfb9f1", + "type": "io.open-cluster-management.works.v1alpha1.manifests.status.resync_request", + "source": "grpc", + "time": "2024-02-05T17:31:05Z", + "clustername": "", + "originalsource": "", + "datacontenttype": "application/json", + "data": { + "statusHashes": [] + } +} \ No newline at end of file diff --git a/examples/grpc/cloudevent-update.json b/examples/grpc/cloudevent-update.json new file mode 100644 index 00000000..983e957a --- /dev/null +++ b/examples/grpc/cloudevent-update.json @@ -0,0 +1,62 @@ +{ + "specversion": "1.0", + "id": "ec41ece3-84f5-42b7-92fd-ad478c6e0be6", + "type": "io.open-cluster-management.works.v1alpha1.manifests.spec.update_request", + "source": "grpc", + "clustername": "cluster1", + "resourceid": "eec95cda-03d6-4514-a9bd-29da9cf7ede2", + "resourceversion": 1, + "datacontenttype": "application/json", + "data": { + "manifest": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "nginx", + "namespace": "default" + }, + "spec": { + "replicas": 2, + "selector": { + "matchLabels": { + "app": "nginx" + } + }, + "template": { + "metadata": { + "labels": { + "app": "nginx" + } + }, + "spec": { + "containers": [ + { + "image": "nginxinc/nginx-unprivileged", + "name": "nginx" + } + ] + } + } + } + }, + "deleteOption": { + "propagationPolicy": "Foreground" + }, + "configOption": { + "feedbackRules": [ + { + "type": "JSONPaths", + "jsonPaths": [ + { + "name": "status", + "path": ".status" + } + ] + } + ], + "updateStrategy": { + "type": "ServerSideApply" + } + } + } +} \ No newline at end of file diff --git a/examples/grpc/cloudevent.json b/examples/grpc/cloudevent.json new file mode 100644 index 00000000..a1be4469 --- /dev/null +++ b/examples/grpc/cloudevent.json @@ -0,0 +1,62 @@ +{ + "specversion": "1.0", + "id": "8beb9296-f423-4bd2-932c-01015e7034dc", + "type": "io.open-cluster-management.works.v1alpha1.manifests.spec.create_request", + "source": "grpc", + "clustername": "cluster1", + "resourceid": "eec95cda-03d6-4514-a9bd-29da9cf7ede2", + "resourceversion": 1, + "datacontenttype": "application/json", + "data": { + "manifest": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "nginx", + "namespace": "default" + }, + "spec": { + "replicas": 1, + "selector": { + "matchLabels": { + "app": "nginx" + } + }, + "template": { + "metadata": { + "labels": { + "app": "nginx" + } + }, + "spec": { + "containers": [ + { + "image": "nginxinc/nginx-unprivileged", + "name": "nginx" + } + ] + } + } + } + }, + "deleteOption": { + "propagationPolicy": "Foreground" + }, + "configOption": { + "feedbackRules": [ + { + "type": "JSONPaths", + "jsonPaths": [ + { + "name": "status", + "path": ".status" + } + ] + } + ], + "updateStrategy": { + "type": "ServerSideApply" + } + } + } +} \ No newline at end of file diff --git a/examples/grpcclient.go b/examples/grpc/grpcclient.go similarity index 74% rename from examples/grpcclient.go rename to examples/grpc/grpcclient.go index 99ab720d..7cede7d7 100644 --- a/examples/grpcclient.go +++ b/examples/grpc/grpcclient.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "flag" + "io" "log" "os" @@ -22,6 +23,7 @@ var ( serverAddr = flag.String("grpc_server", "localhost:8090", "The server address in the format of host:port") serverHostOverride = flag.String("server_host_override", "x.test.example.com", "The server name used to verify the hostname returned by the TLS handshake") cloudEventFile = flag.String("cloudevents_json_file", "", "The absolute file path containing the CloudEvent resource") + subscribeStatus = flag.Bool("subscribe_status", false, "If true, subscribe to the CloudEvent resource status.") ) func main() { @@ -68,4 +70,33 @@ func main() { log.Printf("=======================================") log.Printf("Published spec with cloudevent:\n%v\n\n", evt) log.Printf("=======================================") + + if *subscribeStatus { + subReq := &pbv1.SubscriptionRequest{ + Source: "grpc", + } + + subClient, err := client.Subscribe(ctx, subReq) + if err != nil { + log.Fatalf("failed to subscribe: %v", err) + } + + for { + pvEvt, err := subClient.Recv() + if err == io.EOF { + break + } + if err != nil { + log.Fatalf("failed to receive cloudevent: %v", err) + } + evt, err := binding.ToEvent(ctx, grpcprotocol.NewMessage(pvEvt)) + if err != nil { + log.Fatalf("failed to convert status from protobuf to cloudevent: %v", err) + } + + log.Printf("=======================================") + log.Printf("Received status with cloudevent:\n%v\n", evt) + log.Printf("=======================================") + } + } } diff --git a/examples/resource-in-db.md b/examples/resource-in-db.md new file mode 100644 index 00000000..81cbecc6 --- /dev/null +++ b/examples/resource-in-db.md @@ -0,0 +1,154 @@ +# Maestro Resource in Database + +```psql +# select jsonb_pretty(resources.manifest) from resources; + jsonb_pretty +------------------------------------------------------------------------ + { + + "id": "a9c6b876-6e43-4a48-9e17-94ad85bda223", + + "data": { + + "manifest": { + + "kind": "Deployment", + + "spec": { + + "replicas": 1, + + "selector": { + + "matchLabels": { + + "app": "nginx" + + } + + }, + + "template": { + + "spec": { + + "containers": [ + + { + + "name": "nginx", + + "image": "nginxinc/nginx-unprivileged"+ + } + + ] + + }, + + "metadata": { + + "labels": { + + "app": "nginx" + + } + + } + + } + + }, + + "metadata": { + + "name": "nginx1", + + "namespace": "default" + + }, + + "apiVersion": "apps/v1" + + }, + + "configOption": { + + "feedbackRules": [ + + { + + "type": "JSONPaths", + + "jsonPaths": [ + + { + + "name": "status", + + "path": ".status" + + } + + ] + + } + + ], + + "updateStrategy": { + + "type": "ServerSideApply" + + } + + }, + + "deleteOption": { + + "propagationPolicy": "Foreground" + + } + + }, + + "time": "2024-03-18T12:57:58.661205844Z", + + "type": "....", + + "source": "maestro", + + "clustername": "", + + "specversion": "1.0", + + "originalsource": "", + + "datacontenttype": "application/json" + + } +(1 row) + + +# select jsonb_pretty(resources.status) from resources; + jsonb_pretty +-------------------------------------------------------------------- + { + "id": "0fd2b15f-e4d5-4ecb-a5fb-455284d27e2b", + "data": { + "status": { + "conditions": [ + { + "type": "Applied", + "reason": "AppliedManifestComplete", + "status": "True", + "message": "Apply manifest complete", + "lastTransitionTime": "2024-03-18T12:57:58Z" + }, + { + "type": "Available", + "reason": "ResourceAvailable", + "status": "True", + "message": "Resource is available", + "lastTransitionTime": "2024-03-18T12:57:58Z" + }, + { + "type": "StatusFeedbackSynced", + "reason": "StatusFeedbackSynced", + "status": "True", + "message": "", + "lastTransitionTime": "2024-03-18T12:57:58Z" + } + ], + "resourceMeta": { + "kind": "Deployment", + "name": "nginx1", + "group": "apps", + "ordinal": 0, + "version": "v1", + "resource": "deployments", + "namespace": "default" + }, + "statusFeedback": { + "values": [ + { + "name": "status", + "fieldValue": { + "type": "JsonRaw", + "jsonRaw": "{\"availableReplicas\":1,\"conditions\":[{\"lastTransitionTime\":\"2024-03-18T12:58:04Z\",\"lastUpdateTime\":\"2024-03-18T12:58:04Z\",\"m + essage\":\"Deployment has minimum availability.\",\"reason\":\"MinimumReplicasAvailable\",\"status\":\"True\",\"type\":\"Available\"},{\"lastTransitionTime\":\"2024-03-18T12:57:58Z\",\"lastUpdateTime\":\"2024-03-18T12:58:04Z\",\"message\":\"ReplicaSet \\\"nginx1-5d6b548959\\\" has successfully progressed.\",\"reason\":\"NewReplicaSetAvailable\",\"status\ + ":\"True\",\"type\":\"Progressing\"}],\"observedGeneration\":1,\"readyReplicas\":1,\"replicas\":1,\"updatedReplicas\":1}" + } + } + ] + } + }, + "conditions": [ + { + "type": "Applied", + "reason": "AppliedManifestWorkComplete", + "status": "True", + "message": "Apply manifest work complete", + "lastTransitionTime": "2024-03-18T12:57:58Z" + }, + { + "type": "Available", + "reason": "ResourcesAvailable", + "status": "True", + "message": "All resources are available", + "lastTransitionTime": "2024-03-18T12:57:58Z" + } + ] + }, + "time": "2024-03-18T12:58:11.020848168Z", + "type": "io.open-cluster-management.works.v1alpha1.manifests.status.update_request", + "source": "b288a9da-8bfe-4c82-94cc-2b48e773fc46-work-agent", + "resourceid": "dc970bd3-da6d-4a63-992b-dc0ae0419a7c", + "sequenceid": "1769709885668200448", + "clustername": "b288a9da-8bfe-4c82-94cc-2b48e773fc46", + "specversion": "1.0", + "originalsource": "maestro", + "datacontenttype": "application/json", + "resourceversion": "1" + } +(1 row) +``` diff --git a/examples/resource.json b/examples/resource.json new file mode 100644 index 00000000..8e55ca8b --- /dev/null +++ b/examples/resource.json @@ -0,0 +1,38 @@ +{ + "name": "nginx", + "consumer_name": "cluster1", + "version": 1, + "manifest": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "nginx", + "namespace": "default" + }, + "spec": { + "replicas": 1, + "selector": { + "matchLabels": { + "app": "nginx" + } + }, + "template": { + "metadata": { + "labels": { + "app": "nginx" + } + }, + "spec": { + "serviceAccount": "nginx", + "containers": [ + { + "image": "nginxinc/nginx-unprivileged", + "imagePullPolicy": "IfNotPresent", + "name": "nginx" + } + ] + } + } + } + } +} \ No newline at end of file From 28626e25956b13ccdd47ce417630c7fd6af8b4cd Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:41:02 +0800 Subject: [PATCH 39/67] chore(deps): update konflux references (#191) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-pull-request.yaml | 16 ++++++++-------- .tekton/maestro-push.yaml | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index a41d9e18..9c29a5e8 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -40,7 +40,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8e0f8cad75e6f674d72a874385b69c4651afc0c9dcc59feffe0d85844687d852 + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:1580a8766406207d3a7500cc0c62f8ec4cd935d772008a74dd71ec7e94af2f45 - name: kind value: task resolver: bundles @@ -166,7 +166,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:9e6c4db5a666ea0e1e747e03d63f46e5617a6b9852c26871f9d50891d778dfa2 + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:68a87cafeb43367160497d91a1a66bceef7acc179e809e8eb3996c1deb096042 - name: kind value: task resolver: bundles @@ -191,7 +191,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:1b75828f2b7193ec9c567b907fdc0b2c1bb08cca4ab2dfcecbe9ff84f836cfc8 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:69af2302a0a579f428ea196a2787013d58a6bec503d231d3ef860af7e82b96e9 - name: kind value: task resolver: bundles @@ -226,7 +226,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:d47b0b67109940b264cff6995941aa56c0517562b4939b85d6ac3ed750bf59f1 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:bb66cadcc615fc653c61e64363e9e5abf83dfe1aba10334c79a8d7189f67656b - name: kind value: task resolver: bundles @@ -278,7 +278,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:1f17ef7ab9859d6e2215ef2ed532ebc15e516ba09226b8cae77907a7a8b7cedd + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:b91642a29e3fd204f724ce9e6ab97f3799b1d0102f6458a10e45f840281409ca - name: kind value: task resolver: bundles @@ -300,7 +300,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:b8c51079ea1110e1095c229e184e3c340120ba211a63a200e836706f5a35361c + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:89ca5c9ddcaf609509aaed9c937c2a72cf400810e3a7892adfb9ac247a13693d - name: kind value: task resolver: bundles @@ -317,7 +317,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.2@sha256:479bd0d9aaa7b377ff5f8ad93168d44807455646f2161688637cb2e4e0b990d9 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.2@sha256:278b1a5e2b5d151e29782f9ec98cce5e794af4d284471449569f61a34de0f9a2 - name: kind value: task resolver: bundles @@ -347,7 +347,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:4c1a1cd74eecfcd93222903ea28319a8068f2d5c9678e4db14e2c605831ad90c + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:10976247ae6c9ae7b04670e8d52e7b521c4ce98806891ddcd7248d3c10b56980 - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index 5dfec77f..6c239cee 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -37,7 +37,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8e0f8cad75e6f674d72a874385b69c4651afc0c9dcc59feffe0d85844687d852 + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:1580a8766406207d3a7500cc0c62f8ec4cd935d772008a74dd71ec7e94af2f45 - name: kind value: task resolver: bundles @@ -163,7 +163,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:9e6c4db5a666ea0e1e747e03d63f46e5617a6b9852c26871f9d50891d778dfa2 + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:68a87cafeb43367160497d91a1a66bceef7acc179e809e8eb3996c1deb096042 - name: kind value: task resolver: bundles @@ -188,7 +188,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:1b75828f2b7193ec9c567b907fdc0b2c1bb08cca4ab2dfcecbe9ff84f836cfc8 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:69af2302a0a579f428ea196a2787013d58a6bec503d231d3ef860af7e82b96e9 - name: kind value: task resolver: bundles @@ -223,7 +223,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:d47b0b67109940b264cff6995941aa56c0517562b4939b85d6ac3ed750bf59f1 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:bb66cadcc615fc653c61e64363e9e5abf83dfe1aba10334c79a8d7189f67656b - name: kind value: task resolver: bundles @@ -275,7 +275,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:1f17ef7ab9859d6e2215ef2ed532ebc15e516ba09226b8cae77907a7a8b7cedd + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:b91642a29e3fd204f724ce9e6ab97f3799b1d0102f6458a10e45f840281409ca - name: kind value: task resolver: bundles @@ -297,7 +297,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:b8c51079ea1110e1095c229e184e3c340120ba211a63a200e836706f5a35361c + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:89ca5c9ddcaf609509aaed9c937c2a72cf400810e3a7892adfb9ac247a13693d - name: kind value: task resolver: bundles @@ -314,7 +314,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.2@sha256:479bd0d9aaa7b377ff5f8ad93168d44807455646f2161688637cb2e4e0b990d9 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.2@sha256:278b1a5e2b5d151e29782f9ec98cce5e794af4d284471449569f61a34de0f9a2 - name: kind value: task resolver: bundles @@ -344,7 +344,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:4c1a1cd74eecfcd93222903ea28319a8068f2d5c9678e4db14e2c605831ad90c + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:10976247ae6c9ae7b04670e8d52e7b521c4ce98806891ddcd7248d3c10b56980 - name: kind value: task resolver: bundles From 3774acd0dd5f5caba9a77b2098cbcd5be1e11b34 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:57:51 +0800 Subject: [PATCH 40/67] chore(deps): update docker.io/library/eclipse-mosquitto docker tag to v2.0.20 (#198) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/integration-test.yaml | 2 +- .tekton/unit-test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.tekton/integration-test.yaml b/.tekton/integration-test.yaml index 80b5215b..4507e70d 100644 --- a/.tekton/integration-test.yaml +++ b/.tekton/integration-test.yaml @@ -124,7 +124,7 @@ spec: volumeMounts: - mountPath: /work name: pgdata - - image: docker.io/library/eclipse-mosquitto:2.0.18 + - image: docker.io/library/eclipse-mosquitto:2.0.20 name: mqtt-test volumeMounts: - mountPath: /mosquitto/data diff --git a/.tekton/unit-test.yaml b/.tekton/unit-test.yaml index a55686e8..07c7ec5c 100644 --- a/.tekton/unit-test.yaml +++ b/.tekton/unit-test.yaml @@ -124,7 +124,7 @@ spec: volumeMounts: - mountPath: /work name: pgdata - - image: docker.io/library/eclipse-mosquitto:2.0.18 + - image: docker.io/library/eclipse-mosquitto:2.0.20 name: mqtt-test volumeMounts: - mountPath: /mosquitto/data From 130006893a5acdf13a231f598ba9cb6db766cd6b Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Mon, 28 Oct 2024 16:51:16 +0800 Subject: [PATCH 41/67] ganerate custom test report based on env. (#206) Signed-off-by: morvencao --- test/e2e/pkg/reporter/reporter.go | 187 ++++++++++++++++++++++++++++++ test/e2e/pkg/suite_test.go | 11 ++ 2 files changed, 198 insertions(+) create mode 100644 test/e2e/pkg/reporter/reporter.go diff --git a/test/e2e/pkg/reporter/reporter.go b/test/e2e/pkg/reporter/reporter.go new file mode 100644 index 00000000..1bdd0064 --- /dev/null +++ b/test/e2e/pkg/reporter/reporter.go @@ -0,0 +1,187 @@ +package reporter + +import ( + "encoding/xml" + "fmt" + "os" + "strings" + "time" + + "github.com/onsi/ginkgo/v2/types" +) + +type JUnitTestSuite struct { + XMLName xml.Name `xml:"testsuite"` + // Name maps onto the description of the test suite - maps onto Report.SuiteDescription + Name string `xml:"name,attr"` + // Package maps onto the absolute path to the test suite - maps onto Report.SuitePath + Package string `xml:"package,attr"` + // Tests maps onto the total number of specs in the test suite (this includes any suite nodes such as BeforeSuite) + Tests int `xml:"tests,attr"` + // Disabled maps onto specs that are pending + Disabled int `xml:"disabled,attr"` + // Skiped maps onto specs that are skipped + Skipped int `xml:"skipped,attr"` + // Errors maps onto specs that panicked or were interrupted + Errors int `xml:"errors,attr"` + // Failures maps onto specs that failed + Failures int `xml:"failures,attr"` + // Time is the time in seconds to execute all the test suite - maps onto Report.RunTime + Time float64 `xml:"time,attr"` + // Timestamp is the ISO 8601 formatted start-time of the suite - maps onto Report.StartTime + Timestamp string `xml:"timestamp,attr"` + // TestCases capture the individual specs + TestCases []JUnitTestCase `xml:"testcase"` +} + +type JUnitTestCase struct { + // Name maps onto the full text of the spec - equivalent to "[SpecReport.LeafNodeType] SpecReport.FullText()" + Name string `xml:"name,attr"` + // Classname maps onto the name of the test suite - equivalent to Report.SuiteDescription + Classname string `xml:"classname,attr"` + // Status maps onto the string representation of SpecReport.State + Status string `xml:"status,attr"` + // Time is the time in seconds to execute the spec - maps onto SpecReport.RunTime + Time float64 `xml:"time,attr"` + // Skipped is populated with a message if the test was skipped or pending + Skipped *JUnitSkipped `xml:"skipped,omitempty"` + // Error is populated if the test panicked or was interrupted + Error *JUnitError `xml:"error,omitempty"` + // Failure is populated if the test failed + Failure *JUnitFailure `xml:"failure,omitempty"` + // SystemOut maps onto any captured stdout/stderr output - maps onto SpecReport.CapturedStdOutErr + SystemOut string `xml:"system-out,omitempty"` + // SystemOut maps onto any captured GinkgoWriter output - maps onto SpecReport.CapturedGinkgoWriterOutput + SystemErr string `xml:"system-err,omitempty"` +} + +type JUnitSkipped struct { + // Message maps onto "pending" if the test was marked pending, "skipped" if the test was marked skipped, and "skipped - REASON" if the user called Skip(REASON) + Message string `xml:"message,attr"` +} + +type JUnitError struct { + // Message maps onto the panic/exception thrown - equivalent to SpecReport.Failure.ForwardedPanic - or to "interrupted" + Message string `xml:"message,attr"` + // Type is one of "panicked" or "interrupted" + Type string `xml:"type,attr"` + // Description maps onto the captured stack trace for a panic, or the failure message for an interrupt which will include the dump of running goroutines + Description string `xml:",chardata"` +} + +type JUnitFailure struct { + // Message maps onto the failure message - equivalent to SpecReport.Failure.Message + Message string `xml:"message,attr"` + // Type is "failed" + Type string `xml:"type,attr"` + // Description maps onto the location and stack trace of the failure + Description string `xml:",chardata"` +} + +func GenerateJUnitReport(report types.Report, dst string) error { + suite := JUnitTestSuite{ + Name: report.SuiteDescription, + Package: report.SuitePath, + Time: report.RunTime.Seconds(), + Timestamp: report.StartTime.Format("2006-01-02T15:04:05"), + } + for _, spec := range report.SpecReports { + if spec.FullText() != "" { + name := spec.LeafNodeText + labels := spec.Labels() + if len(labels) > 0 { + name = name + " [" + strings.Join(labels, ", ") + "]" + } + + test := JUnitTestCase{ + Name: name, + Classname: report.SuiteDescription, + Status: spec.State.String(), + Time: spec.RunTime.Seconds(), + SystemOut: systemOutForUnstructureReporters(spec), + SystemErr: spec.CapturedGinkgoWriterOutput, + } + + suite.Tests += 1 + + switch spec.State { + case types.SpecStateSkipped: + message := "skipped" + if spec.Failure.Message != "" { + message += " - " + spec.Failure.Message + } + test.Skipped = &JUnitSkipped{Message: message} + suite.Skipped += 1 + case types.SpecStatePending: + test.Skipped = &JUnitSkipped{Message: "pending"} + suite.Disabled += 1 + case types.SpecStateFailed: + test.Failure = &JUnitFailure{ + Message: spec.Failure.Message, + Type: "failed", + Description: fmt.Sprintf("%s\n%s", spec.Failure.Location.String(), spec.Failure.Location.FullStackTrace), + } + suite.Failures += 1 + case types.SpecStateInterrupted: + test.Error = &JUnitError{ + Message: "interrupted", + Type: "interrupted", + Description: spec.Failure.Message, + } + suite.Errors += 1 + case types.SpecStateAborted: + test.Failure = &JUnitFailure{ + Message: spec.Failure.Message, + Type: "aborted", + Description: fmt.Sprintf("%s\n%s", spec.Failure.Location.String(), spec.Failure.Location.FullStackTrace), + } + suite.Errors += 1 + case types.SpecStatePanicked: + test.Error = &JUnitError{ + Message: spec.Failure.ForwardedPanic, + Type: "panicked", + Description: fmt.Sprintf("%s\n%s", spec.Failure.Location.String(), spec.Failure.Location.FullStackTrace), + } + suite.Errors += 1 + } + + suite.TestCases = append(suite.TestCases, test) + } + } + + junitReport := []JUnitTestSuite{suite} + + f, err := os.Create(dst) + if err != nil { + return err + } + _, err = f.WriteString(xml.Header) + if err != nil { + return err + } + encoder := xml.NewEncoder(f) + encoder.Indent(" ", " ") + err = encoder.Encode(junitReport) + if err != nil { + return err + } + + return f.Close() +} + +func systemOutForUnstructureReporters(spec types.SpecReport) string { + systemOut := spec.CapturedStdOutErr + if len(spec.ReportEntries) > 0 { + systemOut += "\nReport Entries:\n" + for i, entry := range spec.ReportEntries { + systemOut += fmt.Sprintf("%s\n%s\n%s\n", entry.Name, entry.Location, entry.Time.Format(time.RFC3339Nano)) + if representation := entry.StringRepresentation(); representation != "" { + systemOut += representation + "\n" + } + if i+1 < len(spec.ReportEntries) { + systemOut += "--\n" + } + } + } + return systemOut +} diff --git a/test/e2e/pkg/suite_test.go b/test/e2e/pkg/suite_test.go index e33b5e4b..f8cb9b3b 100644 --- a/test/e2e/pkg/suite_test.go +++ b/test/e2e/pkg/suite_test.go @@ -31,6 +31,7 @@ import ( "github.com/openshift-online/maestro/pkg/api/openapi" "github.com/openshift-online/maestro/pkg/client/cloudevents/grpcsource" "github.com/openshift-online/maestro/test" + "github.com/openshift-online/maestro/test/e2e/pkg/reporter" ) type agentTestOptions struct { @@ -175,6 +176,16 @@ var _ = AfterSuite(func() { cancel() }) +var _ = ReportAfterSuite("Maestro e2e Test Report", func(report Report) { + junitReportFile := os.Getenv("JUNIT_REPORT_FILE") + if junitReportFile != "" { + err := reporter.GenerateJUnitReport(report, junitReportFile) + if err != nil { + log.Printf("Failed to generate the report due to: %v", err) + } + } +}) + func dumpDebugInfo() { // dump the maestro server logs dumpPodLogs(ctx, serverTestOpts.kubeClientSet, "app=maestro", serverTestOpts.serverNamespace) From 3c09e09c8dda0f85bb26f2798b44811f230b8973 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:52:14 +0800 Subject: [PATCH 42/67] chore(deps): update konflux references (#207) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-pull-request.yaml | 4 ++-- .tekton/maestro-push.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index 9c29a5e8..f7c824f6 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -226,7 +226,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:bb66cadcc615fc653c61e64363e9e5abf83dfe1aba10334c79a8d7189f67656b + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:79bfd61dc67a505f8a7025181a7651f73479742eb10d9bc35f2d73254629d4f3 - name: kind value: task resolver: bundles @@ -317,7 +317,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.2@sha256:278b1a5e2b5d151e29782f9ec98cce5e794af4d284471449569f61a34de0f9a2 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:a35e1b1e108fe50737e47d5d71368ec882809fdd854096691d4e6fa7bc67e77b - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index 6c239cee..cbaee34e 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -223,7 +223,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:bb66cadcc615fc653c61e64363e9e5abf83dfe1aba10334c79a8d7189f67656b + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:79bfd61dc67a505f8a7025181a7651f73479742eb10d9bc35f2d73254629d4f3 - name: kind value: task resolver: bundles @@ -314,7 +314,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.2@sha256:278b1a5e2b5d151e29782f9ec98cce5e794af4d284471449569f61a34de0f9a2 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:a35e1b1e108fe50737e47d5d71368ec882809fdd854096691d4e6fa7bc67e77b - name: kind value: task resolver: bundles From 1de63c6075f2c95c9661d790d164019f60d789f3 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Mon, 28 Oct 2024 17:03:54 +0800 Subject: [PATCH 43/67] add retry for source client in serverside apply e2e test. (#208) Signed-off-by: morvencao --- test/e2e/pkg/serverside_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/e2e/pkg/serverside_test.go b/test/e2e/pkg/serverside_test.go index e4859a5d..1deec711 100644 --- a/test/e2e/pkg/serverside_test.go +++ b/test/e2e/pkg/serverside_test.go @@ -121,8 +121,10 @@ var _ = Describe("Server Side Apply", Ordered, Label("e2e-tests-serverside-apply nestedWorkNamespace := "default" work := NewNestedManifestWork(nestedWorkNamespace, workName, nestedWorkName) - _, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) + Eventually(func() error { + _, err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Create(ctx, work, metav1.CreateOptions{}) + return err + }, 5*time.Minute, 5*time.Second).ShouldNot(HaveOccurred()) // make sure the nested work is created Eventually(func() error { @@ -148,7 +150,7 @@ var _ = Describe("Server Side Apply", Ordered, Label("e2e-tests-serverside-apply return nil }, 1*time.Minute, 1*time.Second).Should(BeNil()) - err = sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) + err := sourceWorkClient.ManifestWorks(agentTestOpts.consumerName).Delete(ctx, workName, metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) }) }) From dae3b677bca54074837e7ef64d2ed9e790009be5 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 1 Nov 2024 09:31:33 +0800 Subject: [PATCH 44/67] The template to run maestro in ROSA (#209) Signed-off-by: Wei Liu --- templates/agent-template-rosa.yml | 318 ++++++++++++++++++++++++ templates/service-template-rosa.yml | 362 ++++++++++++++++++++++++++++ 2 files changed, 680 insertions(+) create mode 100644 templates/agent-template-rosa.yml create mode 100644 templates/service-template-rosa.yml diff --git a/templates/agent-template-rosa.yml b/templates/agent-template-rosa.yml new file mode 100644 index 00000000..bb63bd4f --- /dev/null +++ b/templates/agent-template-rosa.yml @@ -0,0 +1,318 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + name: maestro-agent + annotations: + openshift.io/display-name: maestro-agent + description: agent to connect to maestro service. + tags: maestro-agent + iconClass: icon-shadowman + template.openshift.io/provider-display-name: Red Hat, Inc. + template.openshift.io/documentation-url: https://gitlab.cee.redhat.com/service/ +labels: + template: maestro-agent +parameters: + +- name: AGENT_NAMESPACE + description: namespace of maestro agent + +- name: CONSUMER_NAME + displayName: Treat CONSUMER_NAME as cluster name + required: true + +- name: IMAGE_REGISTRY + displayName: Image Registry + required: true + +- name: IMAGE_REPOSITORY + displayName: Image Repository + required: true + +- name: IMAGE_TAG + displayName: Image tag + value: latest + +- name: MQTT_HOST + description: Hostname for the mqtt broker + +- name: KLOG_V + displayName: KLOG V Level + description: Log verbosity level + value: "4" + +objects: +- apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + metadata: + name: appliedmanifestworks.work.open-cluster-management.io + spec: + group: work.open-cluster-management.io + names: + kind: AppliedManifestWork + listKind: AppliedManifestWorkList + plural: appliedmanifestworks + singular: appliedmanifestwork + scope: Cluster + preserveUnknownFields: false + versions: + - name: v1 + schema: + openAPIV3Schema: + description: AppliedManifestWork represents an applied manifestwork on managed cluster that is placed on a managed cluster. An AppliedManifestWork links to a manifestwork on a hub recording resources deployed in the managed cluster. When the agent is removed from managed cluster, cluster-admin on managed cluster can delete appliedmanifestwork to remove resources deployed by the agent. The name of the appliedmanifestwork must be in the format of {hash of hub's first kube-apiserver url}-{manifestwork name} + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec represents the desired configuration of AppliedManifestWork. + type: object + properties: + agentID: + description: AgentID represents the ID of the work agent who is to handle this AppliedManifestWork. + type: string + hubHash: + description: HubHash represents the hash of the first hub kube apiserver to identify which hub this AppliedManifestWork links to. + type: string + manifestWorkName: + description: ManifestWorkName represents the name of the related manifestwork on the hub. + type: string + status: + description: Status represents the current status of AppliedManifestWork. + type: object + properties: + appliedResources: + description: AppliedResources represents a list of resources defined within the manifestwork that are applied. Only resources with valid GroupVersionResource, namespace, and name are suitable. An item in this slice is deleted when there is no mapped manifest in manifestwork.Spec or by finalizer. The resource relating to the item will also be removed from managed cluster. The deleted resource may still be present until the finalizers for that resource are finished. However, the resource will not be undeleted, so it can be removed from this list and eventual consistency is preserved. + type: array + items: + description: AppliedManifestResourceMeta represents the group, version, resource, name and namespace of a resource. Since these resources have been created, they must have valid group, version, resource, namespace, and name. + type: object + required: + - name + - resource + - version + properties: + group: + description: Group is the API Group of the Kubernetes resource, empty string indicates it is in core group. + type: string + name: + description: Name is the name of the Kubernetes resource. + type: string + namespace: + description: Name is the namespace of the Kubernetes resource, empty string indicates it is a cluster scoped resource. + type: string + resource: + description: Resource is the resource name of the Kubernetes resource. + type: string + uid: + description: UID is set on successful deletion of the Kubernetes resource by controller. The resource might be still visible on the managed cluster after this field is set. It is not directly settable by a client. + type: string + version: + description: Version is the version of the Kubernetes resource. + type: string + evictionStartTime: + description: 'EvictionStartTime represents the current appliedmanifestwork will be evicted after a grace period. An appliedmanifestwork will be evicted from the managed cluster in the following two scenarios: - the manifestwork of the current appliedmanifestwork is missing on the hub, or - the appliedmanifestwork hub hash does not match the current hub hash of the work agent.' + type: string + format: date-time + served: true + storage: true + subresources: + status: {} + status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] + +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: maestro-agent:agent + rules: + # Allow agent to managed appliedmanifestworks + - apiGroups: ["work.open-cluster-management.io"] + resources: ["appliedmanifestworks"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["work.open-cluster-management.io"] + resources: ["appliedmanifestworks/status"] + verbs: ["patch", "update"] + - apiGroups: ["work.open-cluster-management.io"] + resources: ["appliedmanifestworks/finalizers"] + verbs: ["update"] + # Allow agent to check executor permissions + - apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: ["create"] + - apiGroups: [""] + resources: ["serviceaccounts"] + verbs: ["impersonate"] + +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: maestro-agent:agent + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: maestro-agent:agent + subjects: + - kind: ServiceAccount + name: maestro-agent-sa + namespace: ${AGENT_NAMESPACE} + +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: maestro-agent:execution-admin + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + # We deploy a controller that could work with permission lower than cluster-admin, the tradeoff is + # responsivity because list/watch cannot be maintained over too many namespaces. + name: cluster-admin + subjects: + - kind: ServiceAccount + name: maestro-agent-sa + namespace: ${AGENT_NAMESPACE} + +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: maestro-agent:execution + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: maestro-agent:execution + subjects: + - kind: ServiceAccount + name: maestro-agent-sa + namespace: ${AGENT_NAMESPACE} + +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: maestro-agent:agent + namespace: ${AGENT_NAMESPACE} + rules: + # leader election needs to operate configmaps + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch", "create", "delete", "update", "patch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["create", "get", "list", "update", "watch", "patch"] + - apiGroups: ["", "events.k8s.io"] + resources: ["events"] + verbs: ["create", "patch", "update"] + +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: maestro-agent:agent + namespace: ${AGENT_NAMESPACE} + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: maestro-agent:agent + subjects: + - kind: ServiceAccount + name: maestro-agent-sa + namespace: ${AGENT_NAMESPACE} + +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: maestro-agent:agent:extension-apiserver + namespace: kube-system + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: maestro-agent:agent:extension-apiserver + subjects: + - kind: ServiceAccount + name: maestro-agent-sa + namespace: ${AGENT_NAMESPACE} + +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: maestro-agent:agent:extension-apiserver + namespace: kube-system + rules: + - apiGroups: [""] + resources: ["configmaps"] + resourceNames: ["extension-apiserver-authentication"] + verbs: ["get", "list", "watch"] + +- kind: Deployment + apiVersion: apps/v1 + metadata: + name: maestro-agent + namespace: ${AGENT_NAMESPACE} + labels: + app: maestro-agent + spec: + replicas: 1 + selector: + matchLabels: + app: maestro-agent + template: + metadata: + labels: + app: maestro-agent + spec: + serviceAccountName: maestro-agent-sa + containers: + - name: maestro-agent + image: ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}:${IMAGE_TAG} + imagePullPolicy: IfNotPresent + command: + - /usr/local/bin/maestro + - agent + - --consumer-name=${CONSUMER_NAME} + - --workload-source-driver=mqtt + - --workload-source-config=/secrets/mqtt/config.yaml + - --cloudevents-client-id=${CONSUMER_NAME} + - -v=${KLOG_V} + volumeMounts: + - name: mqtt + mountPath: /secrets/mqtt + - name: mqtt-creds + mountPath: /secrets/mqtt-creds + volumes: + - name: mqtt + secret: + secretName: maestro-agent-mqtt + - name: mqtt-creds + secret: + secretName: maestro-agent-mqtt-creds + +- apiVersion: v1 + kind: Secret + metadata: + name: maestro-agent-mqtt + namespace: ${AGENT_NAMESPACE} + stringData: + config.yaml: | + brokerHost: ${MQTT_HOST}:8883 + caFile: /secrets/mqtt-creds/ca.crt + clientCertFile: /secrets/mqtt-creds/client.crt + clientKeyFile: /secrets/mqtt-creds/client.key + topics: + sourceEvents: sources/maestro/consumers/${CONSUMER_NAME}/sourceevents + agentEvents: sources/maestro/consumers/${CONSUMER_NAME}/agentevents + +- kind: ServiceAccount + apiVersion: v1 + metadata: + name: maestro-agent-sa + namespace: ${AGENT_NAMESPACE} + labels: + app: maestro-agent diff --git a/templates/service-template-rosa.yml b/templates/service-template-rosa.yml new file mode 100644 index 00000000..b5c85c1f --- /dev/null +++ b/templates/service-template-rosa.yml @@ -0,0 +1,362 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + name: maestro-service + annotations: + openshift.io/display-name: maestro + description: Example Service API for the Unified Hybrid Cloud deployment + tags: golang,uhc,service-delivery + iconClass: icon-shadowman + template.openshift.io/provider-display-name: Red Hat, Inc. + template.openshift.io/documentation-url: https://gitlab.cee.redhat.com/service/ +labels: + template: maestro +parameters: + +- name: ENVIRONMENT + displayName: Environment + description: Which Account Manager environment to use for this deployment + value: production + +- name: IMAGE_REGISTRY + displayName: Image Registry + required: true + +- name: IMAGE_REPOSITORY + displayName: Image Repository + required: true + +- name: IMAGE_TAG + displayName: Image tag + value: latest + +- name: MQTT_HOST + description: Hostname for the mqtt broker + +- name: KLOG_V + displayName: KLOG V Level + description: Log verbosity level + value: "4" + +- name: MEMORY_REQUEST + description: Memory request for the API pods. + value: "512Mi" + +- name: MEMORY_LIMIT + description: Memory limit for the API pods. + value: "1Gi" + +- name: CPU_REQUEST + description: CPU request for the API pods. + value: "200m" + +- name: CPU_LIMIT + description: CPU limit for the API pods. + value: "1" + +- name: SERVER_REPLICAS + description: Number of replicas of the service to run. + value: "3" + +- name: ENABLE_JWT + displayName: Enable JWT + description: Enable JWT authentication validation + value: "false" + +- name: ENABLE_HTTPS + displayName: Enable HTTPS + description: Enable HTTPS rather than HTTP + value: "false" + +- name: HTTP_SERVER_BINDPORT + displayName: HTTP Server Bindport + description: HTTP server bind port + value: "8000" + +- name: ENABLE_GRPC_SERVER + displayName: Enable gRPC Server + description: Enable gRPC server + value: "true" + +- name: GRPC_SERVER_BINDPORT + displayName: gRPC Server Bindport + description: gRPC server bind port + value: "8090" + +- name: METRICS_SERVER_BINDPORT + displayName: Metrics Server Bindport + description: Metrics server bind port + value: "8080" + +- name: HEALTH_CHECK_SERVER_BINDPORT + displayName: Health check Server Bindport + description: Health check server bind port + value: "8083" + +- name: HTTP_SERVER_HOSTNAME + displayName: HTTP Server Hostname + description: Server's public hostname + value: "" + +- name: ENABLE_AUTHZ + displayName: Enable Authz + description: Enable Authorization on endpoints, should only be disabled for debug + value: "true" + +- name: DB_MAX_OPEN_CONNS + displayName: Maximum Open Database Connections + description: Maximum number of open database connections per pod + value: "50" + +- name: DB_SSLMODE + displayName: DB SSLmode + description: Database ssl mode (disable | require | verify-ca | verify-full) + value: "verify-full" + +- name: ENABLE_DB_DEBUG + displayName: Enable DB Debug + description: framework's debug mode + value: "false" + +- name: ENABLE_METRICS_HTTPS + displayName: Enable Metrics HTTPS + description: Enable HTTPS for metrics server + value: "false" + +- name: ENABLE_OCM_MOCK + displayName: Enable OCM Mock + description: Enable mock uhc client + value: "true" + +- name: HTTP_READ_TIMEOUT + displayName: HTTP Read Timeout + description: HTTP server read timeout + value: 5s + +- name: HTTP_WRITE_TIMEOUT + displayName: HTTP Write Timeout + description: HTTP server write timeout + value: 30s + +- name: LABEL_METRICS_INCLUSION_DURATION + displayName: Label metrics inclusion duration + description: A cluster's last telemetry date needs be within in this duration in order to have labels collected + value: "168h" + +- name: MAESTRO_SERVER_EXPOSURE + displayName: The type of service to be used to expose the Maestro Server + value: "ClusterIP" + +objects: + - kind: Deployment + apiVersion: apps/v1 + metadata: + name: maestro + labels: + app: maestro + spec: + selector: + matchLabels: + app: maestro + replicas: ${SERVER_REPLICAS} + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + app: maestro + spec: + serviceAccountName: maestro + volumes: + - name: db + secret: + secretName: maestro-db + - name: mqtt + secret: + secretName: maestro-mqtt + - name: mqtt-creds + secret: + secretName: mqtt-creds + initContainers: + - name: migration + image: ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}:${IMAGE_TAG} + imagePullPolicy: IfNotPresent + volumeMounts: + - name: db + mountPath: /secrets/db + command: + - /usr/local/bin/maestro + - migration + - --db-host-file=/secrets/db/db.host + - --db-port-file=/secrets/db/db.port + - --db-user-file=/secrets/db/db.user + - --db-password-file=/secrets/db/db.password + - --db-name-file=/secrets/db/db.name + - --db-rootcert=/secrets/db/db.ca_cert + - --db-sslmode=${DB_SSLMODE} + - --alsologtostderr + - -v=${KLOG_V} + containers: + - name: service + image: ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}:${IMAGE_TAG} + imagePullPolicy: IfNotPresent + volumeMounts: + - name: db + mountPath: /secrets/db + - name: mqtt + mountPath: /secrets/mqtt + - name: mqtt-creds + mountPath: /secrets/mqtt-creds + readOnly: true + env: + - name: "AMS_ENV" + value: "${ENVIRONMENT}" + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + command: + - /usr/local/bin/maestro + - server + - --client-id=maestro-$(POD_NAME) + - --db-host-file=/secrets/db/db.host + - --db-port-file=/secrets/db/db.port + - --db-user-file=/secrets/db/db.user + - --db-password-file=/secrets/db/db.password + - --db-name-file=/secrets/db/db.name + - --db-rootcert=/secrets/db/db.ca_cert + - --db-sslmode=${DB_SSLMODE} + - --db-max-open-connections=${DB_MAX_OPEN_CONNS} + - --message-broker-config-file=/secrets/mqtt/config.yaml + - --message-broker-type=mqtt + - --enable-ocm-mock=${ENABLE_OCM_MOCK} + - --enable-jwt=${ENABLE_JWT} + - --enable-https=${ENABLE_HTTPS} + - --enable-grpc-server=${ENABLE_GRPC_SERVER} + - --disable-grpc-tls=true + - --server-hostname=${HTTP_SERVER_HOSTNAME} + - --http-server-bindport=${HTTP_SERVER_BINDPORT} + - --grpc-server-bindport=${GRPC_SERVER_BINDPORT} + - --health-check-server-bindport=${HEALTH_CHECK_SERVER_BINDPORT} + - --enable-health-check-https=${ENABLE_HTTPS} + - --enable-authz=${ENABLE_AUTHZ} + - --enable-db-debug=${ENABLE_DB_DEBUG} + - --enable-metrics-https=${ENABLE_METRICS_HTTPS} + - --enable-sentry=false + - --http-read-timeout=${HTTP_READ_TIMEOUT} + - --http-write-timeout=${HTTP_WRITE_TIMEOUT} + - --label-metrics-inclusion-duration=${LABEL_METRICS_INCLUSION_DURATION} + - --alsologtostderr + - -v=${KLOG_V} + resources: + requests: + cpu: ${CPU_REQUEST} + memory: ${MEMORY_REQUEST} + limits: + cpu: ${CPU_LIMIT} + memory: ${MEMORY_LIMIT} + livenessProbe: + httpGet: + path: /api/maestro + port: 8000 + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 5 + readinessProbe: + httpGet: + path: /healthcheck + port: 8083 + scheme: HTTP + httpHeaders: + - name: User-Agent + value: Probe + initialDelaySeconds: 20 + periodSeconds: 10 + + - kind: Service + apiVersion: v1 + metadata: + name: maestro + labels: + app: maestro + port: api + spec: + type: ${MAESTRO_SERVER_EXPOSURE} + selector: + app: maestro + ports: + - port: 8000 + targetPort: 8000 + protocol: TCP + + # Services for diagnostic ports (not part of main service because we + # don't want exposing them externally through same route). + - kind: Service + apiVersion: v1 + metadata: + name: maestro-metrics + labels: + app: maestro + port: metrics + spec: + selector: + app: maestro + ports: + - port: 8080 + targetPort: 8080 + name: metrics + + - kind: Service + apiVersion: v1 + metadata: + name: maestro-grpc + labels: + app: maestro-grpc + port: grpc + spec: + selector: + app: maestro + ports: + - port: 8090 + targetPort: 8090 + protocol: TCP + + - apiVersion: v1 + kind: Service + metadata: + name: maestro-healthcheck + labels: + app: maestro + port: healthcheck + spec: + selector: + app: maestro + ports: + - port: 8083 + targetPort: 8083 + + - apiVersion: v1 + kind: Secret + metadata: + name: maestro-mqtt + stringData: + config.yaml: | + brokerHost: ${MQTT_HOST}:8883 + caFile: /secrets/mqtt-creds/ca.crt + clientCertFile: /secrets/mqtt-creds/client.crt + clientKeyFile: /secrets/mqtt-creds/client.key + topics: + sourceEvents: sources/maestro/consumers/+/sourceevents + agentEvents: $share/statussubscribers/sources/maestro/consumers/+/agentevents + + - kind: ServiceAccount + apiVersion: v1 + metadata: + name: maestro + labels: + app: maestro From fbf6408a86fc42344f334e4037d8af6e7a11a205 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 1 Nov 2024 09:57:12 +0800 Subject: [PATCH 45/67] support run e2e in rosa env (#211) Signed-off-by: Wei Liu --- test/e2e/pkg/status_resync_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/e2e/pkg/status_resync_test.go b/test/e2e/pkg/status_resync_test.go index 0b500274..171d3af5 100644 --- a/test/e2e/pkg/status_resync_test.go +++ b/test/e2e/pkg/status_resync_test.go @@ -170,9 +170,6 @@ var _ = Describe("Status Resync After Restart", Ordered, Label("e2e-tests-status } return fmt.Errorf("nginx deployment still exists") }, 2*time.Minute, 2*time.Second).ShouldNot(HaveOccurred()) - - err = agentTestOpts.kubeClientSet.CoreV1().ServiceAccounts("default").Delete(ctx, name, metav1.DeleteOptions{}) - Expect(err).ShouldNot(HaveOccurred()) }) }) }) From f07dfc00400e6a4fce3cc224f8467bee15340562 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 1 Nov 2024 14:27:02 +0800 Subject: [PATCH 46/67] Upgrade open-cluster-management/go-sdk (#212) Signed-off-by: Wei Liu --- go.mod | 10 +++++----- go.sum | 22 ++++++++++++++-------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 58f7c82e..b6dfd565 100755 --- a/go.mod +++ b/go.mod @@ -51,9 +51,9 @@ require ( k8s.io/client-go v0.30.3 k8s.io/component-base v0.30.3 k8s.io/klog/v2 v2.130.1 - open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c - open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff - open-cluster-management.io/sdk-go v0.14.1-0.20241009075853-0c5ba39fd113 + open-cluster-management.io/api v0.15.0 + open-cluster-management.io/ocm v0.15.0 + open-cluster-management.io/sdk-go v0.15.1-0.20241031061311-f50d6e83dae3 sigs.k8s.io/yaml v1.4.0 ) @@ -73,7 +73,7 @@ require ( github.com/confluentinc/confluent-kafka-go/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/eclipse/paho.golang v0.21.0 // indirect @@ -84,7 +84,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/swag v0.22.4 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect diff --git a/go.sum b/go.sum index 3e4a6035..7d38707b 100644 --- a/go.sum +++ b/go.sum @@ -80,8 +80,9 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/denisenkom/go-mssqldb v0.0.0-20190423183735-731ef375ac02/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= @@ -145,8 +146,9 @@ github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= @@ -390,6 +392,8 @@ github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vyg github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/mochi-mqtt/server/v2 v2.6.5 h1:9PiQ6EJt/Dx0ut0Fuuir4F6WinO/5Bpz9szujNwm+q8= +github.com/mochi-mqtt/server/v2 v2.6.5/go.mod h1:TqztjKGO0/ArOjJt9x9idk0kqPT3CVN8Pb+l+PS5Gdo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -461,6 +465,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -836,12 +842,12 @@ k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7F k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c h1:gYfgkX/U6fv2d3Ly8D6N1GM9zokORupLSgCxx791zZw= -open-cluster-management.io/api v0.14.1-0.20240627145512-bd6f2229b53c/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= -open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff h1:nGP34ECvH6G8ihcF0Q6ZzpYGjvRrJ/yOcj1Dc3z/H48= -open-cluster-management.io/ocm v0.14.1-0.20240906021855-b6763a13c0ff/go.mod h1:bt8jy8oaXSTTlv6RtRSz4Ea8II15SH1PZJZs34ZWOU4= -open-cluster-management.io/sdk-go v0.14.1-0.20241009075853-0c5ba39fd113 h1:VSIxKaQyL1AaT+3TmOYnUlAkEX3lKG40zPuGPjXBP6M= -open-cluster-management.io/sdk-go v0.14.1-0.20241009075853-0c5ba39fd113/go.mod h1:VUykb6x2KAljQHql6vnPcE40MQvA4JQNKvwT7JIbrkM= +open-cluster-management.io/api v0.15.0 h1:lRee1KOlGHZb2scTA7ff9E9Fxt2hJc7jpkHnaCbvkOU= +open-cluster-management.io/api v0.15.0/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= +open-cluster-management.io/ocm v0.15.0 h1:anXQzvQUhM/DT8FcKVi4n8AY97IA5DVI0mb8R1wsvbs= +open-cluster-management.io/ocm v0.15.0/go.mod h1:d6ubRiBaouiQ+yV+wFAmarpU7I77nXhkJnQJf8gLZC4= +open-cluster-management.io/sdk-go v0.15.1-0.20241031061311-f50d6e83dae3 h1:Dw10oC4N54TJDYt9c8SyRD0du80aS3MSvvBUFWlZyTI= +open-cluster-management.io/sdk-go v0.15.1-0.20241031061311-f50d6e83dae3/go.mod h1:fi5WBsbC5K3txKb8eRLuP0Sim/Oqz/PHX18skAEyjiA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= From 34d57d5d2faefe77620f29aa8cccc109c4b04945 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 1 Nov 2024 15:00:55 +0800 Subject: [PATCH 47/67] use 2 braces for int type in templates (#213) Signed-off-by: Wei Liu --- templates/service-template-rosa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/service-template-rosa.yml b/templates/service-template-rosa.yml index b5c85c1f..366abc47 100644 --- a/templates/service-template-rosa.yml +++ b/templates/service-template-rosa.yml @@ -159,7 +159,7 @@ objects: selector: matchLabels: app: maestro - replicas: ${SERVER_REPLICAS} + replicas: ${{SERVER_REPLICAS}} strategy: rollingUpdate: maxSurge: 25% From 42899b6b74d986ff87a3e375ad972af1a25853e5 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Tue, 5 Nov 2024 11:03:55 +0800 Subject: [PATCH 48/67] add setup scripts and templates for aro-hcp. (#214) * add setup scripts and templates for aro-hcp. Signed-off-by: morvencao * deploy aro-hcp env using upstream. Signed-off-by: morvencao * apply comments. Signed-off-by: morvencao --------- Signed-off-by: morvencao --- .gitignore | 4 +- test/e2e/setup/aro/Makefile | 61 ++++++++++++++++++++++++ test/e2e/setup/aro/README.md | 91 ++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 test/e2e/setup/aro/Makefile create mode 100644 test/e2e/setup/aro/README.md diff --git a/.gitignore b/.gitignore index 4c06cbde..6df1bed4 100755 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,6 @@ test/e2e/.consumer_name test/e2e/.external_host_ip test/e2e/report/* unit-test-results.json -integration-test-results.json \ No newline at end of file +integration-test-results.json + +test/e2e/setup/aro/aro-hcp \ No newline at end of file diff --git a/test/e2e/setup/aro/Makefile b/test/e2e/setup/aro/Makefile new file mode 100644 index 00000000..0b42590e --- /dev/null +++ b/test/e2e/setup/aro/Makefile @@ -0,0 +1,61 @@ +# define the variables +REPO_URL = https://github.com/Azure/ARO-HCP.git +BRANCH = maestro-light-setup +CLONE_DIR = aro-hcp + +# clone the repo +clone: + @if [ -d $(CLONE_DIR) ]; then \ + echo "Removing existing directory $(CLONE_DIR)..."; \ + rm -rf $(CLONE_DIR); \ + fi; \ + echo "Cloning repository..."; \ + git clone $(REPO_URL) -b $(BRANCH) $(CLONE_DIR) +.PHONY: clone + +# create the cluster (svc-cluster or mgmt-cluster) +cluster: clone +ifndef AKSCONFIG + $(error "Must set AKSCONFIG") +endif + @$(MAKE) -C $(CLONE_DIR)/dev-infrastructure cluster +.PHONY: cluster + +# grant admin access to the cluster +aks.admin-access: +ifndef AKSCONFIG + $(error "Must set AKSCONFIG") +endif + @$(MAKE) -C $(CLONE_DIR)/dev-infrastructure aks.admin-access +.PHONY: aks.admin-access + +# retrieve the kubeconfig +aks.kubeconfig: +ifndef AKSCONFIG + $(error "Must set AKSCONFIG") +endif + @$(MAKE) -C $(CLONE_DIR)/dev-infrastructure aks.kubeconfig +.PHONY: aks.kubeconfig + +# deploy the maestro server +deploy-server: + @AKSCONFIG=svc-cluster $(MAKE) -C $(CLONE_DIR)/maestro deploy-server +.PHONY: deploy-server + +# deploy the maestro agent +deploy-agent: + @AKSCONFIG=mgmt-cluster $(MAKE) -C $(CLONE_DIR)/maestro deploy-agent +.PHONY: deploy-agent + +# register the maestro agent +register-agent: + @AKSCONFIG=svc-cluster $(MAKE) -C $(CLONE_DIR)/maestro register-agent +.PHONY: register-agent + +# clean up the resources +clean: +ifndef AKSCONFIG + $(error "Must set AKSCONFIG") +endif + @$(MAKE) -C $(CLONE_DIR)/dev-infrastructure clean +.PHONY: clean diff --git a/test/e2e/setup/aro/README.md b/test/e2e/setup/aro/README.md new file mode 100644 index 00000000..ec5e4524 --- /dev/null +++ b/test/e2e/setup/aro/README.md @@ -0,0 +1,91 @@ +# Maestro ARO-HCP Env Setup + +## Prerequisites + +* `az` version >= 2.60, `jq`, `make`, [kubelogin](https://azure.github.io/kubelogin/install.html), `kubectl` version >= 1.30, `helm` +* `az login` with service principal (azure AD user support is WIP) + +### Create Service Cluster + +Change those flags accordingly and then run the following command. Depending on the selected features, this may take a while: + + ```bash + AKSCONFIG=svc-cluster make cluster + ``` + +### Create Management Cluster + +A Management Cluster depends on certain resources found in the resource group of the Service Cluster. Therefore, a standalone Management Cluster can't be created right now and requires a Service Cluster + + ```bash + AKSCONFIG=mgmt-cluster make cluster + ``` + +### Access AKS Clusters + + ```bash + AKSCONFIG=svc-cluster make aks.admin-access # one time + AKSCONFIG=svc-cluster make aks.kubeconfig + AKSCONFIG=svc-cluster export KUBECONFIG=${HOME}/.kube/${AKSCONFIG}.kubeconfig + kubectl get ns + ``` + + (Replace `svc` with `mgmt` for management clusters) + +### Cleanup + +Setting the correct `AKSCONFIG`, this will cleanup all resources created in Azure + + ```bash + AKSCONFIG=svc-cluster make clean + ``` + + (Replace `svc` with `mgmt` for management clusters) + +## Deploy Maestro to AKS Clusters + +### Maestro Server + +> Make sure your `KUBECONFIG` points to the service cluster!!! + +> The service cluster has no ingress. To interact with the services you need to use `kubectl port-forward` + + ```bash + AKSCONFIG=svc-cluster make deploy-server + ``` + +To validate, have a look at the `maestro` namespace on the service cluster. Some pod restarts are expected in the first 1 minute until the containerized DB is ready. + +To access the HTTP and GRPC endpoints of maestro, run + + ```bash + kubectl port-forward svc/maestro 8001:8000 -n maestro + kubectl port-forward svc/maestro-grpc 8090 -n maestro + ``` + +If you need to restart the maestro server during testing and don't want the port-forward process to be broken, you can install the kubectl relay plugin from [https://github.com/knight42/krelay](https://github.com/knight42/krelay) and perform the port forward using the following steps: + + + ```bash + kubectl relay svc/maestro 8001:8000 -n maestro + kubectl relay svc/maestro-grpc 8090 -n maestro + ``` + +## Maestro Agent + +> Make sure your `KUBECONFIG` points to the management cluster!!! + +First install the agent + + ```bash + AKSCONFIG=mgmt-cluster make deploy-agent + ``` + +Then register it with the Maestro Server + +Make sure your `KUBECONFIG` points to the service cluster, then run + + ```bash + cd maestro + AKSCONFIG=svc-cluster make register-agent + ``` From 8d6765a5acff491204d994504c49712b32ce24ad Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Wed, 6 Nov 2024 16:46:55 +0800 Subject: [PATCH 49/67] run maestro with rosa (#215) Signed-off-by: Wei Liu --- .gitignore | 4 +- test/e2e/setup/rosa/Makefile | 30 +++ test/e2e/setup/rosa/README.md | 100 ++++++++++ test/e2e/setup/rosa/setup/agent.sh | 87 +++++++++ .../aws-iot-policies/consumer.template.json | 41 ++++ .../aws-iot-policies/source.template.json | 43 +++++ test/e2e/setup/rosa/setup/e2e.sh | 40 ++++ test/e2e/setup/rosa/setup/maestro.sh | 175 ++++++++++++++++++ test/e2e/setup/rosa/setup/teardown.sh | 46 +++++ 9 files changed, 564 insertions(+), 2 deletions(-) create mode 100644 test/e2e/setup/rosa/Makefile create mode 100644 test/e2e/setup/rosa/README.md create mode 100755 test/e2e/setup/rosa/setup/agent.sh create mode 100644 test/e2e/setup/rosa/setup/aws-iot-policies/consumer.template.json create mode 100644 test/e2e/setup/rosa/setup/aws-iot-policies/source.template.json create mode 100755 test/e2e/setup/rosa/setup/e2e.sh create mode 100755 test/e2e/setup/rosa/setup/maestro.sh create mode 100755 test/e2e/setup/rosa/setup/teardown.sh diff --git a/.gitignore b/.gitignore index 6df1bed4..af4e2dc4 100755 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ hack/mosquitto-passwd.txt vendor/ # Ignore test data +_output test/e2e/.kubeconfig test/e2e/.consumer_id test/e2e/.consumer_name @@ -59,5 +60,4 @@ test/e2e/.external_host_ip test/e2e/report/* unit-test-results.json integration-test-results.json - -test/e2e/setup/aro/aro-hcp \ No newline at end of file +test/e2e/setup/aro/aro-hcp diff --git a/test/e2e/setup/rosa/Makefile b/test/e2e/setup/rosa/Makefile new file mode 100644 index 00000000..d9b3bc8e --- /dev/null +++ b/test/e2e/setup/rosa/Makefile @@ -0,0 +1,30 @@ +SHELL:=/bin/bash + +e2e_dir=$(shell cd ${PWD}/../.. && pwd -P) + +rosa/setup-maestro: + ./setup/maestro.sh +.PHONY: rosa/setup-maestro + +rosa/setup-agent: + ./setup/agent.sh +.PHONY: rosa/setup-agent + +rosa/setup-e2e: + ./setup/e2e.sh +.PHONY: rosa/setup-e2e + +rosa/e2e-test: rosa/setup-e2e + ginkgo -v --fail-fast --label-filter="!(e2e-tests-spec-resync-reconnect||e2e-tests-status-resync-reconnect)" \ + --output-dir="$(e2e_dir)/report" --json-report=report.json --junit-report=report.xml \ + ${e2e_dir}/pkg -- \ + -api-server="http://127.0.0.1:8000" \ + -grpc-server="127.0.0.1:8090" \ + -server-kubeconfig=$(KUBECONFIG) \ + -agent-kubeconfig=$(KUBECONFIG) \ + -consumer-name=${PWD}/_output/consumer_id +.PHONY: rosa/e2e-test + +rosa/teardown: + ./setup/teardown.sh +.PHONY: rosa/teardown diff --git a/test/e2e/setup/rosa/README.md b/test/e2e/setup/rosa/README.md new file mode 100644 index 00000000..075cef20 --- /dev/null +++ b/test/e2e/setup/rosa/README.md @@ -0,0 +1,100 @@ +## Setup Maestro in ROSA env + +This demonstrates how to deploy the Maestro in ROSA env. + +### Prerequisites + +- Install the CLIs: `oc`, `rosa`, `aws` and `jq` +- Ensue your `aws` CLI is logined with your AWS account and your AWS account should have the permissions to operate AWS IoT and AWS RDS PostgreSQL in your provided region +- Prepare two ROSA clusters, one is used as Service Cluster and the other is used as Management Cluster, e.g. + +```sh +rosa create cluster --cluster-name=service --region=us-west-2 --sts --mode=auto +rosa create cluster --cluster-name=management --region=us-west-2 --sts --mode=auto +``` + +### Setup Maestro server in your Service Cluster + +```sh +export REGION="" # e.g. us-west-2 +export CLUSTER_ID="" # e.g. service +export KUBECONFIG="" + +make rosa/setup-maestro +``` + +This will +- Create AWS IoT client certs and policy for Maestro server in your region +- Create AWS RDS PostgreSQL for Maestro server in your region +- Deploy the Maestro server on the given cluster + +After the Maestro server is deployed, you can run following commands to start the Maestro RESTful service and GRPC service in your local host + +```sh +oc port-forward svc/maestro 8000 -n maestro +oc port-forward svc/maestro-grpc 8090 -n maestro +``` + +Then create a consumer in the Maestro, e.g. + +```sh +curl -s -X POST -H "Content-Type: application/json" http://127.0.0.1:8000/api/maestro/v1/consumers -d '{"name": "management"}' +``` + +### Setup Maestro agent in your Management Cluster + +```sh +export REGION="" # e.g. us-west-2 +export CONSUMER_ID="" # e.g. management +export KUBECONFIG="" + +make rosa/setup-agent +``` + +This will +- Create AWS IoT client certs and policy for Maestro agent in your region +- Deploy the Maestro agent on the given cluster + +### Cleanup + +```sh +export REGION="" + +make rosa/teardown + +# delete your rosa clusters, e.g. +rosa delete cluster --cluster=service +rosa delete cluster --cluster=management +``` + +## Run Maestro e2e on a ROSA cluster + +### Prepare + +1. Install the following CLIs `oc`, `rosa`, `aws`, `jq` and [`krelay` plugin](https://github.com/knight42/krelay) +2. Create a rosa cluster + +```sh +rosa create cluster --cluster-name=maestro-e2e --region=us-west-2 --sts --mode=auto +``` + +### Run e2e + +```sh +export KUBECONFIG="" +export REGION="" +export CLUSTER_ID="" + +make rosa/e2e-test +``` + +### Cleanup + +```sh +export REGION="" + +make rosa/teardown + +# delete your rosa clusters, e.g. +rosa delete cluster --cluster=maestro-e2e +``` diff --git a/test/e2e/setup/rosa/setup/agent.sh b/test/e2e/setup/rosa/setup/agent.sh new file mode 100755 index 00000000..0ba6dd46 --- /dev/null +++ b/test/e2e/setup/rosa/setup/agent.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +##################### +# Setup Maestro agent +##################### + +PWD="$(cd "$(dirname ${BASH_SOURCE[0]})" ; pwd -P)" +ROOT_DIR="$(cd ${PWD}/.. && pwd -P)" + +region=${REGION:-""} +consumer_id=${CONSUMER_ID:-""} + +if [ -z "$region" ]; then + echo "region is required" + exit 1 +fi + +if [ -z "$consumer_id" ]; then + echo "consumer id is required" + exit 1 +fi + +echo "Setup Maestro agent in ${region} (consumer_id=${consumer_id})" + +IMAGE_REGISTRY=${IMAGE_REGISTRY:="quay.io/redhat-user-workloads/maestro-rhtap-tenant/maestro"} +IMAGE_REPOSITORY="maestro" +IMAGE_TAG=${IMAGE_TAG:-"1de63c6075f2c95c9661d790d164019f60d789f3"} + +output_dir=${ROOT_DIR}/_output +certs_dir=${output_dir}/aws-certs +consumer_cert_dir=${certs_dir}/iot/consumers +policies_dir=${output_dir}/aws-policies + +mkdir -p ${consumer_cert_dir} +mkdir -p ${policies_dir} + +# Download AWS IoT broker severing CA +echo "Download AWS IoT broker severing CA ...." +curl -s -o ${certs_dir}/iot-ca.pem https://www.amazontrust.com/repository/AmazonRootCA1.pem + +# Generated client certs for AWS IoT clients +echo "Generate AWS IoT client certs for Maestro agent ...." +consumer_cert_arn=$(aws iot create-keys-and-certificate \ + --region ${region} \ + --set-as-active \ + --certificate-pem-outfile "${consumer_cert_dir}/${consumer_id}.crt" \ + --public-key-outfile "${consumer_cert_dir}/${consumer_id}.public.key" \ + --private-key-outfile "${consumer_cert_dir}/${consumer_id}.private.key" | jq -r '.certificateArn') +echo "Maestro agent AWS IoT client certs are generated ($consumer_cert_arn)" + +# Attach policies for AWS IoT clients +aws_account=$(aws sts get-caller-identity --region ${region} --output json | jq -r '.Account') + +echo "Generate AWS IoT policy for Maestro agent ...." +cat $PWD/aws-iot-policies/consumer.template.json | sed "s/{region}/${region}/g" | sed "s/{aws_account}/${aws_account}/g" | sed "s/{consumer_id}/${consumer_id}/g" > $policies_dir/${consumer_id}.json +policy_name=$(aws iot create-policy \ + --region ${region} \ + --policy-name maestro-${consumer_id} \ + --policy-document "file://${policies_dir}/${consumer_id}.json" | jq -r '.policyName') +aws iot attach-policy --region ${region} --policy-name maestro-${consumer_id} --target ${consumer_cert_arn} +echo "Maestro agent AWS IoT policy $policy_name is generated" + +# Get AWS IoT broker endpoint +mqtt_host=$(aws iot describe-endpoint --region ${region} --endpoint-type iot:Data-ATS | jq -r '.endpointAddress') +echo "AWS IoT broke: ${mqtt_host}:8883" + +sleep 30 + +# Deploy Maestro agent +oc create namespace maestro-agent || true +oc -n maestro-agent delete secrets maestro-agent-mqtt-creds --ignore-not-found +oc -n maestro-agent create secret generic maestro-agent-mqtt-creds \ + --from-file=ca.crt="${certs_dir}/iot-ca.pem" \ + --from-file=client.crt="${consumer_cert_dir}/${consumer_id}.crt" \ + --from-file=client.key="${consumer_cert_dir}/${consumer_id}.private.key" + +oc process --filename="https://raw.githubusercontent.com/openshift-online/maestro/refs/heads/main/templates/agent-template-rosa.yml" \ + --local="true" \ + --param="AGENT_NAMESPACE=maestro-agent" \ + --param="CONSUMER_NAME=${consumer_id}" \ + --param="IMAGE_REGISTRY=${IMAGE_REGISTRY}" \ + --param="IMAGE_REPOSITORY=${IMAGE_REPOSITORY}" \ + --param="IMAGE_TAG=${IMAGE_TAG}" \ + --param="MQTT_HOST=${mqtt_host}" > ${output_dir}/maestro-${consumer_id}-rosa.json + +oc apply -f ${output_dir}/maestro-${consumer_id}-rosa.json +oc -n maestro-agent wait deploy/maestro-agent --for condition=Available=True --timeout=300s diff --git a/test/e2e/setup/rosa/setup/aws-iot-policies/consumer.template.json b/test/e2e/setup/rosa/setup/aws-iot-policies/consumer.template.json new file mode 100644 index 00000000..1e55c8a1 --- /dev/null +++ b/test/e2e/setup/rosa/setup/aws-iot-policies/consumer.template.json @@ -0,0 +1,41 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "iot:Connect" + ], + "Resource": [ + "arn:aws:iot:{region}:{aws_account}:client/{consumer_id}-client" + ] + }, + { + "Effect": "Allow", + "Action": [ + "iot:Publish" + ], + "Resource": [ + "arn:aws:iot:{region}:{aws_account}:topic/sources/maestro/consumers/{consumer_id}/agentevents" + ] + }, + { + "Effect": "Allow", + "Action": [ + "iot:Subscribe" + ], + "Resource": [ + "arn:aws:iot:{region}:{aws_account}:topicfilter/sources/maestro/consumers/{consumer_id}/sourceevents" + ] + }, + { + "Effect": "Allow", + "Action": [ + "iot:Receive" + ], + "Resource": [ + "arn:aws:iot:{region}:{aws_account}:topic/sources/maestro/consumers/{consumer_id}/sourceevents" + ] + } + ] +} diff --git a/test/e2e/setup/rosa/setup/aws-iot-policies/source.template.json b/test/e2e/setup/rosa/setup/aws-iot-policies/source.template.json new file mode 100644 index 00000000..dff03a32 --- /dev/null +++ b/test/e2e/setup/rosa/setup/aws-iot-policies/source.template.json @@ -0,0 +1,43 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "iot:Connect" + ], + "Resource": [ + "*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "iot:Publish" + ], + "Resource": [ + "arn:aws:iot:{region}:{aws_account}:topic/sources/maestro/consumers/*/sourceevents" + ] + }, + { + "Effect": "Allow", + "Action": [ + "iot:Subscribe" + ], + "Resource": [ + "arn:aws:iot:{region}:{aws_account}:topicfilter/sources/maestro/consumers/+/agentevents", + "arn:aws:iot:{region}:{aws_account}:topicfilter/$share/statussubscribers/sources/maestro/consumers/+/agentevents" + ] + }, + { + "Effect": "Allow", + "Action": [ + "iot:Receive" + ], + "Resource": [ + "arn:aws:iot:{region}:{aws_account}:topic/sources/maestro/consumers/*/agentevents", + "arn:aws:iot:{region}:{aws_account}:topic/$share/statussubscribers/sources/maestro/consumers/*/agentevents" + ] + } + ] +} diff --git a/test/e2e/setup/rosa/setup/e2e.sh b/test/e2e/setup/rosa/setup/e2e.sh new file mode 100755 index 00000000..d03d5377 --- /dev/null +++ b/test/e2e/setup/rosa/setup/e2e.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +##################### +# Setup Maestro e2e +##################### + +PWD="$(cd "$(dirname ${BASH_SOURCE[0]})" ; pwd -P)" +ROSA_DIR="$(cd ${PWD}/.. && pwd -P)" + +output_dir=${ROSA_DIR}/_output + +mkdir -p $output_dir + +echo "$output_dir" + +# Setup Maestro server +CLUSTER_VPC=$vpc ${PWD}/maestro.sh +sleep 90 # wait the maestro service ready + +# Start Maestro servers +exec oc relay service/maestro 8000:8000 -n maestro > ${output_dir}/maestro.svc.log 2>&1 & +maestro_server_pid=$! +echo "Maestro server started: $maestro_server_pid" +echo "$maestro_server_pid" > ${output_dir}/maestro_server.pid +exec oc relay service/maestro-grpc 8090:8090 -n maestro > ${output_dir}/maestro-grpc.svc.log 2>&1 & +maestro_grpc_server_pid=$! +echo "Maestro GRPC server started: $maestro_grpc_server_pid" +echo "$maestro_grpc_server_pid" > ${output_dir}/maestro_grpc_server.pid + +# need to wait the relay build the connection before we get the consumer id +sleep 15 + +# Prepare a consumer +consumer_id=$(curl -s -X POST -H "Content-Type: application/json" http://127.0.0.1:8000/api/maestro/v1/consumers -d '{}' | jq -r '.id') +echo $consumer_id > ${output_dir}/consumer_id +echo "Consumer $consumer_id is created" + +# Setup Maestro agent +oc apply -f https://raw.githubusercontent.com/open-cluster-management-io/api/release-0.14/work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml +CONSUMER_ID=$consumer_id ${PWD}/agent.sh diff --git a/test/e2e/setup/rosa/setup/maestro.sh b/test/e2e/setup/rosa/setup/maestro.sh new file mode 100755 index 00000000..21714aab --- /dev/null +++ b/test/e2e/setup/rosa/setup/maestro.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env bash + +###################### +# Setup Maestro server +###################### + +PWD="$(cd "$(dirname ${BASH_SOURCE[0]})" ; pwd -P)" +ROSA_DIR="$(cd ${PWD}/.. && pwd -P)" + +region=${REGION:-""} +cluster_id=${CLUSTER_ID:-""} + +if [ -z "$region" ]; then + echo "region is required" + exit 1 +fi + +if [ -z "$cluster_id" ]; then + echo "cluster id is required" + exit 1 +fi + +# Find Maestro server vpc +rosa_infra_id=$(rosa describe cluster --region=${region} --cluster=${cluster_id} -ojson | jq -r '.infra_id') +vpc=$(aws ec2 describe-vpcs --region=${region} \ + --filters Name=tag:Name,Values=${rosa_infra_id}-vpc | jq -r '.Vpcs[0].VpcId') + +echo "Setup Maestro in ${region} (cluster=$cluster_id,vpc=$vpc)" + +IMAGE_REGISTRY=${IMAGE_REGISTRY:-"quay.io/redhat-user-workloads/maestro-rhtap-tenant/maestro"} +IMAGE_REPOSITORY=${IMAGE_REPOSITORY:-"maestro"} +IMAGE_TAG=${IMAGE_TAG:-"1de63c6075f2c95c9661d790d164019f60d789f3"} + +output_dir=${ROSA_DIR}/_output +certs_dir=${output_dir}/aws-certs +source_cert_dir=${certs_dir}/iot/source +policies_dir=${output_dir}/aws-policies + +source_id="maestro" + +mkdir -p ${source_cert_dir} +mkdir -p ${policies_dir} + +db_pw=$(LC_CTYPE=C tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c 16) +echo "$db_pw" > $output_dir/db.password + +# Download AWS IoT broker severing CA +echo "Download AWS IoT broker and database severing CA ...." +curl -s -o ${certs_dir}/iot-ca.pem https://www.amazontrust.com/repository/AmazonRootCA1.pem +curl -s -o ${certs_dir}/db-ca.pem "https://truststore.pki.rds.amazonaws.com/${region}/${region}-bundle.pem" + +# Generate client certs for AWS IoT clients +echo "Generate AWS IoT client certs for Maestro ...." +maestro_cert_arn=$(aws iot create-keys-and-certificate \ + --region ${region} \ + --set-as-active \ + --certificate-pem-outfile "${source_cert_dir}/${source_id}.crt" \ + --public-key-outfile "${source_cert_dir}/${source_id}.public.key" \ + --private-key-outfile "${source_cert_dir}/${source_id}.private.key" | jq -r '.certificateArn') +echo "Mastro AWS IoT client certs are generated ($maestro_cert_arn)" + +# Attach policies for AWS IoT clients +echo "Generate AWS IoT policy for Maestro ...." +aws_account=$(aws sts get-caller-identity --region ${region} --output json | jq -r '.Account') + +cat $PWD/aws-iot-policies/source.template.json | sed "s/{region}/${region}/g" | sed "s/{aws_account}/${aws_account}/g" > $policies_dir/source.json +policy_name=$(aws iot create-policy \ + --region ${region} \ + --policy-name ${source_id} \ + --policy-document "file://${policies_dir}/source.json" | jq -r '.policyName') +aws iot attach-policy --region ${region} --policy-name ${source_id} --target ${maestro_cert_arn} +echo "Maestro AWS IoT policy $policy_name is generated" + +# Allow AWS PostgrepSQL connection in the default security group +echo "Prepare AWS RDS PostgrepSQL for Maestro in ${region} (${vpc}) ...." +sg=$(aws ec2 get-security-groups-for-vpc \ + --region ${region} \ + --vpc-id ${vpc} \ + --query "SecurityGroupForVpcs[?GroupName=='default'].GroupId" | jq -r '.[0]') +result=$(aws ec2 authorize-security-group-ingress \ + --region ${region} \ + --group-id ${sg} \ + --protocol tcp --port 5432 --cidr 0.0.0.0/0 | jq -r '.Return') +echo "PostgrepSQL inbound rule is added to ${sg} (${result})" + +# Create a database subnet group for AWS PostgrepSQL +subnets="" +subnets_counts=0 +for subnet in $(aws ec2 describe-subnets --region ${region} --filters "Name=vpc-id,Values=${vpc}" | jq -r '.Subnets[].SubnetId'); do + subnets="$subnets,\"$subnet\"" + subnets_counts=$((subnets_counts+1)) +done + +if [ $subnets_counts -le 2 ]; then + # The DB subnet group doesn't meet Availability Zone (AZ) coverage requirement. Current AZ coverage: us-west-2a. Add subnets to cover at least 2 AZs. + current_az=$(aws ec2 describe-subnets --region ${region} --filters "Name=vpc-id,Values=${vpc}" | jq -r '.Subnets[0].AvailabilityZone') + for az in $(aws ec2 describe-availability-zones --region=${region} | jq -r '.AvailabilityZones[].ZoneName'); do + if [[ "$az" != "$current_az" ]]; then + subnet=$(aws ec2 create-subnet \ + --region=${region} \ + --vpc-id ${vpc} \ + --availability-zone ${az} \ + --cidr-block 10.0.64.0/18 \ + --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=maestro-db-subnet-${az}}]" | jq -r '.Subnet.SubnetId') + subnets="$subnets,\"$subnet\"" + break + fi + done +fi + +db_subnet_group=$(aws rds create-db-subnet-group \ + --region ${region} \ + --db-subnet-group-name maestrosubnetgroup \ + --db-subnet-group-description "Maestro DB subnet group" \ + --subnet-ids "[${subnets:1}]" | jq -r '.DBSubnetGroup.DBSubnetGroupName') +echo "PostgrepSQL subnet group ${db_subnet_group} is created" + +# Create AWS PostgrepSQL +db_id=$(aws rds create-db-instance \ + --region ${region} \ + --engine postgres \ + --engine-version 14.10 \ + --allocated-storage 20 \ + --db-instance-class db.t4g.large \ + --db-subnet-group-name ${db_subnet_group} \ + --db-instance-identifier maestro \ + --db-name maestro \ + --master-username maestro \ + --master-user-password "${db_pw}" | jq -r '.DBInstance.DBInstanceIdentifier') +db_id=maestro +i=1 +while [ $i -le 20 ] +do + db_status=$(aws rds describe-db-instances --region ${region} --db-instance-identifier ${db_id} | jq -r '.DBInstances[0].DBInstanceStatus') + echo "[$i] DB status: ${db_status}" + if [[ "$db_status" == "available" ]]; then + break + fi + i=$((i + 1)) + sleep 30 +done + +# Get AWS IoT broker and PostgrepSQL endpoints +mqtt_host=$(aws iot describe-endpoint --region ${region} --endpoint-type iot:Data-ATS | jq -r '.endpointAddress') +db_host=$(aws rds describe-db-instances --region ${region} --db-instance-identifier ${db_id} | jq -r '.DBInstances[0].Endpoint.Address') +echo "AWS IoT broke: ${mqtt_host}:8883" +echo "AWS RDS PostgreSQL: ${db_host}:5432 (${db_id})" + +# Deploy Maestro server +oc create namespace maestro || true + +oc -n maestro delete secrets mqtt-creds --ignore-not-found +oc -n maestro create secret generic mqtt-creds \ + --from-file=ca.crt="${certs_dir}/iot-ca.pem" \ + --from-file=client.crt="${source_cert_dir}/maestro.crt" \ + --from-file=client.key="${source_cert_dir}/maestro.private.key" + +oc -n maestro delete secret maestro-db --ignore-not-found +oc -n maestro create secret generic maestro-db \ + --from-literal=db.name=maestro \ + --from-literal=db.host=${db_host} \ + --from-literal=db.port=5432 \ + --from-literal=db.user=maestro \ + --from-literal=db.password="${db_pw}" \ + --from-file=db.ca_cert="${certs_dir}/db-ca.pem" + +oc process --filename="https://raw.githubusercontent.com/openshift-online/maestro/refs/heads/main/templates/service-template-rosa.yml" \ + --local="true" \ + --param="IMAGE_REGISTRY=${IMAGE_REGISTRY}" \ + --param="IMAGE_REPOSITORY=${IMAGE_REPOSITORY}" \ + --param="IMAGE_TAG=${IMAGE_TAG}" \ + --param="MQTT_HOST=${mqtt_host}" > ${output_dir}/maestro-rosa.json + +oc -n maestro apply -f ${output_dir}/maestro-rosa.json +oc -n maestro wait deploy/maestro --for condition=Available=True --timeout=300s diff --git a/test/e2e/setup/rosa/setup/teardown.sh b/test/e2e/setup/rosa/setup/teardown.sh new file mode 100755 index 00000000..33258709 --- /dev/null +++ b/test/e2e/setup/rosa/setup/teardown.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +region=${REGION:-""} + +if [ -z "$region" ]; then + echo "cluster region is required" + exit 1 +fi + +# Delete AWS PostgreSQL +db_status=$(aws rds delete-db-instance --region ${region} --db-instance-identifier maestro --skip-final-snapshot --delete-automated-backups | jq -r '.DBInstance.DBInstanceStatus') +echo "Deleting maestro db ($db_status)" + +i=1 +while [ $i -le 20 ] +do + db_status=$(aws rds describe-db-instances --region ${region} --db-instance-identifier maestro | jq -r '.DBInstances[0].DBInstanceStatus') + if [[ -z "$db_status" ]]; then + echo "DB is deleted" + break + fi + echo "[$i] DB status: ${db_status}" + i=$((i + 1)) + sleep 30 +done + +aws rds delete-db-subnet-group --region ${region} --db-subnet-group-name maestrosubnetgroup +echo "DB db subnet group is removed" + +# Remove AWS IoT polices and certificates +for cert_id in $(aws iot list-certificates --region ${region} | jq -r '.certificates[].certificateId'); do + cert_arn=$(aws iot describe-certificate --region ${region} --certificate-id $cert_id | jq -r '.certificateDescription.certificateArn') + # List all + for policy_name in $(aws iot list-attached-policies --region ${region} --target $cert_arn | jq -r '.policies[].policyName'); do + if [[ $policy_name == maestro* ]]; then + echo "delelet policy $policy_name" + aws iot detach-policy --region ${region} --target $cert_arn --policy-name $policy_name + aws iot delete-policy --region ${region} --policy-name $policy_name + + echo "delelet certificate $cert_id" + aws iot update-certificate --region ${region} --certificate-id $cert_id --new-status REVOKED + sleep 5 + aws iot delete-certificate --region ${region} --certificate-id $cert_id + fi + done +done From f088dc320a744275a5143b883d0ce8e745630571 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Tue, 19 Nov 2024 14:43:26 +0800 Subject: [PATCH 50/67] register cloud events metrics. (#217) * register metrics. Signed-off-by: morvencao * add testing. Signed-off-by: morvencao --------- Signed-off-by: morvencao --- cmd/maestro/agent/cmd.go | 7 +++++++ go.mod | 2 +- go.sum | 4 ++-- pkg/client/cloudevents/source_client.go | 3 ++- test/integration/resource_test.go | 20 ++++++++++++++++++++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/cmd/maestro/agent/cmd.go b/cmd/maestro/agent/cmd.go index bde78ba6..4e23a36e 100644 --- a/cmd/maestro/agent/cmd.go +++ b/cmd/maestro/agent/cmd.go @@ -8,11 +8,13 @@ import ( "github.com/spf13/pflag" utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilflag "k8s.io/component-base/cli/flag" + "k8s.io/component-base/metrics/legacyregistry" "k8s.io/component-base/version" ocmfeature "open-cluster-management.io/api/feature" commonoptions "open-cluster-management.io/ocm/pkg/common/options" "open-cluster-management.io/ocm/pkg/features" "open-cluster-management.io/ocm/pkg/work/spoke" + "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" ) var ( @@ -20,6 +22,11 @@ var ( agentOption = spoke.NewWorkloadAgentOptions() ) +func init() { + // register the cloud events metrics for the agent + generic.RegisterCloudEventsMetrics(legacyregistry.Registerer()) +} + // by default uses 1M as the limit for state feedback const maxJSONRawLength int32 = 1024 * 1024 diff --git a/go.mod b/go.mod index b6dfd565..2f01877a 100755 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( k8s.io/klog/v2 v2.130.1 open-cluster-management.io/api v0.15.0 open-cluster-management.io/ocm v0.15.0 - open-cluster-management.io/sdk-go v0.15.1-0.20241031061311-f50d6e83dae3 + open-cluster-management.io/sdk-go v0.15.1-0.20241118094717-4b0d20455f47 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index 7d38707b..7bb2a03b 100644 --- a/go.sum +++ b/go.sum @@ -846,8 +846,8 @@ open-cluster-management.io/api v0.15.0 h1:lRee1KOlGHZb2scTA7ff9E9Fxt2hJc7jpkHnaC open-cluster-management.io/api v0.15.0/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= open-cluster-management.io/ocm v0.15.0 h1:anXQzvQUhM/DT8FcKVi4n8AY97IA5DVI0mb8R1wsvbs= open-cluster-management.io/ocm v0.15.0/go.mod h1:d6ubRiBaouiQ+yV+wFAmarpU7I77nXhkJnQJf8gLZC4= -open-cluster-management.io/sdk-go v0.15.1-0.20241031061311-f50d6e83dae3 h1:Dw10oC4N54TJDYt9c8SyRD0du80aS3MSvvBUFWlZyTI= -open-cluster-management.io/sdk-go v0.15.1-0.20241031061311-f50d6e83dae3/go.mod h1:fi5WBsbC5K3txKb8eRLuP0Sim/Oqz/PHX18skAEyjiA= +open-cluster-management.io/sdk-go v0.15.1-0.20241118094717-4b0d20455f47 h1:1gNvY3quZ6CWeXnwCLAXuEoNjGGZL+U4uS79vuo8API= +open-cluster-management.io/sdk-go v0.15.1-0.20241118094717-4b0d20455f47/go.mod h1:fi5WBsbC5K3txKb8eRLuP0Sim/Oqz/PHX18skAEyjiA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= diff --git a/pkg/client/cloudevents/source_client.go b/pkg/client/cloudevents/source_client.go index 0c0bff28..0b61f8f5 100644 --- a/pkg/client/cloudevents/source_client.go +++ b/pkg/client/cloudevents/source_client.go @@ -9,6 +9,7 @@ import ( "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/logger" "github.com/openshift-online/maestro/pkg/services" + "github.com/prometheus/client_golang/prometheus" cegeneric "open-cluster-management.io/sdk-go/pkg/cloudevents/generic" ceoptions "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options" cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" @@ -42,7 +43,7 @@ func NewSourceClient(sourceOptions *ceoptions.CloudEventsSourceOptions, resource } // register resource resync metrics for cloud event source client - cegeneric.RegisterResourceResyncMetrics() + cegeneric.RegisterCloudEventsMetrics(prometheus.DefaultRegisterer) return &SourceClientImpl{ Codec: codec, diff --git a/test/integration/resource_test.go b/test/integration/resource_test.go index 08a9e613..a66f07a8 100755 --- a/test/integration/resource_test.go +++ b/test/integration/resource_test.go @@ -186,6 +186,17 @@ func TestResourcePost(t *testing.T) { Expect(contentStatus["availableReplicas"]).To(Equal(float64(1))) Expect(contentStatus["readyReplicas"]).To(Equal(float64(1))) Expect(contentStatus["updatedReplicas"]).To(Equal(float64(1))) + + // check the metrics + time.Sleep(1 * time.Second) + families := getServerMetrics(t, "http://localhost:8080/metrics") + labels := []*prommodel.LabelPair{ + {Name: strPtr("source"), Value: strPtr("maestro")}, + {Name: strPtr("cluster"), Value: strPtr(clusterName)}, + {Name: strPtr("type"), Value: strPtr("io.open-cluster-management.works.v1alpha1.manifests")}, + } + checkServerCounterMetric(t, families, "cloudevents_sent_total", labels, 3.0) + checkServerCounterMetric(t, families, "cloudevents_received_total", labels, 3.0) } func TestResourcePostWithoutName(t *testing.T) { @@ -777,6 +788,7 @@ func TestResourceFromGRPC(t *testing.T) { }, 10*time.Second, 1*time.Second).Should(Succeed()) // check the metrics + time.Sleep(1 * time.Second) families := getServerMetrics(t, "http://localhost:8080/metrics") labels := []*prommodel.LabelPair{ {Name: strPtr("type"), Value: strPtr("Publish")}, @@ -807,6 +819,14 @@ func TestResourceFromGRPC(t *testing.T) { {Name: strPtr("code"), Value: strPtr("OK")}, } checkServerCounterMetric(t, families, "grpc_server_processed_total", labels, 0.0) + + labels = []*prommodel.LabelPair{ + {Name: strPtr("source"), Value: strPtr("maestro")}, + {Name: strPtr("cluster"), Value: strPtr(clusterName)}, + {Name: strPtr("type"), Value: strPtr("io.open-cluster-management.works.v1alpha1.manifestbundles")}, + } + checkServerCounterMetric(t, families, "cloudevents_sent_total", labels, 3.0) + checkServerCounterMetric(t, families, "cloudevents_received_total", labels, 3.0) } func TestResourceBundleFromGRPC(t *testing.T) { From 1e9b714c69ee31e6262e64f02c5a17ab1ef34795 Mon Sep 17 00:00:00 2001 From: Hui Chen Date: Thu, 21 Nov 2024 11:42:51 +0800 Subject: [PATCH 51/67] add aks metrics enable (#219) Signed-off-by: hchenxa --- test/e2e/setup/aro/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/e2e/setup/aro/Makefile b/test/e2e/setup/aro/Makefile index 0b42590e..b653b942 100644 --- a/test/e2e/setup/aro/Makefile +++ b/test/e2e/setup/aro/Makefile @@ -52,6 +52,14 @@ register-agent: @AKSCONFIG=svc-cluster $(MAKE) -C $(CLONE_DIR)/maestro register-agent .PHONY: register-agent +# enable the aks metrics +enable-aks-metrics: clone +ifndef AKSCONFIG + $(error "Must set AKSCONFIG") +endif + @$(MAKE) -C $(CLONE_DIR)/dev-infrastructure enable-aks-metrics +.PHONY: enable-aks-metrics + # clean up the resources clean: ifndef AKSCONFIG From a72e9da17d36f1186781709e0e69eb8ce1397e59 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:41:01 +0800 Subject: [PATCH 52/67] chore(deps): update openapitools/openapi-generator-cli docker tag to v7.10.0 (#218) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- Dockerfile.openapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.openapi b/Dockerfile.openapi index 0ef5c504..bf305114 100755 --- a/Dockerfile.openapi +++ b/Dockerfile.openapi @@ -1,4 +1,4 @@ -FROM openapitools/openapi-generator-cli:v7.9.0 +FROM openapitools/openapi-generator-cli:v7.10.0 RUN apt-get update RUN apt-get install -y make sudo git From aa5ea954fa20aab15ea3e21167c904aa5623547e Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:41:25 +0800 Subject: [PATCH 53/67] chore(deps): update docker.io/library/postgres docker tag to v17.2 (#216) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/integration-test.yaml | 2 +- .tekton/unit-test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.tekton/integration-test.yaml b/.tekton/integration-test.yaml index 4507e70d..03beff27 100644 --- a/.tekton/integration-test.yaml +++ b/.tekton/integration-test.yaml @@ -110,7 +110,7 @@ spec: ) echo -n "$TEST_OUTPUT" | tee $(results.TEST_OUTPUT.path) sidecars: - - image: docker.io/library/postgres:17.0 + - image: docker.io/library/postgres:17.2 name: database-test env: - name: PGDATA diff --git a/.tekton/unit-test.yaml b/.tekton/unit-test.yaml index 07c7ec5c..79c8cb08 100644 --- a/.tekton/unit-test.yaml +++ b/.tekton/unit-test.yaml @@ -110,7 +110,7 @@ spec: ) echo -n "$TEST_OUTPUT" | tee $(results.TEST_OUTPUT.path) sidecars: - - image: docker.io/library/postgres:17.0 + - image: docker.io/library/postgres:17.2 name: database-test env: - name: PGDATA From e26dd50cbaedffc697eaeffa3cb4e0dfbf79388e Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:41:44 +0800 Subject: [PATCH 54/67] chore(deps): update konflux references (#210) Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> Co-authored-by: red-hat-konflux[bot] <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-pull-request.yaml | 22 +++++++++++----------- .tekton/maestro-push.yaml | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml index f7c824f6..7fdf2120 100644 --- a/.tekton/maestro-pull-request.yaml +++ b/.tekton/maestro-pull-request.yaml @@ -40,7 +40,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:1580a8766406207d3a7500cc0c62f8ec4cd935d772008a74dd71ec7e94af2f45 + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8062d5b13b5236030407cbd620a75cb7c091f43be178eeefea58d2e3dddcaa74 - name: kind value: task resolver: bundles @@ -59,7 +59,7 @@ spec: - name: name value: summary - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:abdf426424f1331c27be80ed98a0fbcefb8422767d1724308b9d57b37f977155 + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:ac5b078500566c204eaa23e3aea1e2f7e003ac750514198419cb322a2eaf177a - name: kind value: task resolver: bundles @@ -149,7 +149,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:596b7c11572bb94eb67d9ffb4375068426e2a8249ff2792ce04ad2a4bc593a63 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:07b8eb6a9533525a397c296246d3eb6ec4771b520a1bfee817ce2b7ede25c43d - name: kind value: task resolver: bundles @@ -166,7 +166,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:68a87cafeb43367160497d91a1a66bceef7acc179e809e8eb3996c1deb096042 + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:a3e22f57fbf8398fbe93fbeeb38e03756cd073182d6d109fe8e8cde57b561603 - name: kind value: task resolver: bundles @@ -191,7 +191,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:69af2302a0a579f428ea196a2787013d58a6bec503d231d3ef860af7e82b96e9 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:cdf98845bbed169e488daef426d1cfdde85c586655abcf89c61da6538d93f70c - name: kind value: task resolver: bundles @@ -226,7 +226,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:79bfd61dc67a505f8a7025181a7651f73479742eb10d9bc35f2d73254629d4f3 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:570831e48df71f3578eb6f083d5fe5ee5c9affa5edbd1c648474ceef4553373e - name: kind value: task resolver: bundles @@ -249,7 +249,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:14b91ad9124b722b44222685013faaf9af8ac5b66030d9abeb1c61da3c118cdd + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:c07c3f9813e87832468fc72912c6e8ef995a442a32248cc35d77b8c0f5e516e2 - name: kind value: task resolver: bundles @@ -278,7 +278,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:b91642a29e3fd204f724ce9e6ab97f3799b1d0102f6458a10e45f840281409ca + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:566ae0df80f8447558595a996627bf0b5482dc0eaa9fbc33b8154587aed51a05 - name: kind value: task resolver: bundles @@ -300,7 +300,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:89ca5c9ddcaf609509aaed9c937c2a72cf400810e3a7892adfb9ac247a13693d + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:bcc01fe4689fbb87ca335d7efea88ec800e05d8796f0828fca984349b7844b09 - name: kind value: task resolver: bundles @@ -317,7 +317,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:a35e1b1e108fe50737e47d5d71368ec882809fdd854096691d4e6fa7bc67e77b + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:4ada9949fd195b50e33605ef06bb52a9bfb523d88529392972ac7a051d5bb549 - name: kind value: task resolver: bundles @@ -347,7 +347,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:10976247ae6c9ae7b04670e8d52e7b521c4ce98806891ddcd7248d3c10b56980 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3e2891c232dc03fb5c7746fc615e1827afbd6931843e42b19cb8a6c04276ed32 - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml index cbaee34e..21973a16 100644 --- a/.tekton/maestro-push.yaml +++ b/.tekton/maestro-push.yaml @@ -37,7 +37,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:1580a8766406207d3a7500cc0c62f8ec4cd935d772008a74dd71ec7e94af2f45 + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8062d5b13b5236030407cbd620a75cb7c091f43be178eeefea58d2e3dddcaa74 - name: kind value: task resolver: bundles @@ -56,7 +56,7 @@ spec: - name: name value: summary - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:abdf426424f1331c27be80ed98a0fbcefb8422767d1724308b9d57b37f977155 + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:ac5b078500566c204eaa23e3aea1e2f7e003ac750514198419cb322a2eaf177a - name: kind value: task resolver: bundles @@ -146,7 +146,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:596b7c11572bb94eb67d9ffb4375068426e2a8249ff2792ce04ad2a4bc593a63 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:07b8eb6a9533525a397c296246d3eb6ec4771b520a1bfee817ce2b7ede25c43d - name: kind value: task resolver: bundles @@ -163,7 +163,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:68a87cafeb43367160497d91a1a66bceef7acc179e809e8eb3996c1deb096042 + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:a3e22f57fbf8398fbe93fbeeb38e03756cd073182d6d109fe8e8cde57b561603 - name: kind value: task resolver: bundles @@ -188,7 +188,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:69af2302a0a579f428ea196a2787013d58a6bec503d231d3ef860af7e82b96e9 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:cdf98845bbed169e488daef426d1cfdde85c586655abcf89c61da6538d93f70c - name: kind value: task resolver: bundles @@ -223,7 +223,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:79bfd61dc67a505f8a7025181a7651f73479742eb10d9bc35f2d73254629d4f3 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:570831e48df71f3578eb6f083d5fe5ee5c9affa5edbd1c648474ceef4553373e - name: kind value: task resolver: bundles @@ -246,7 +246,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:14b91ad9124b722b44222685013faaf9af8ac5b66030d9abeb1c61da3c118cdd + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:c07c3f9813e87832468fc72912c6e8ef995a442a32248cc35d77b8c0f5e516e2 - name: kind value: task resolver: bundles @@ -275,7 +275,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:b91642a29e3fd204f724ce9e6ab97f3799b1d0102f6458a10e45f840281409ca + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:566ae0df80f8447558595a996627bf0b5482dc0eaa9fbc33b8154587aed51a05 - name: kind value: task resolver: bundles @@ -297,7 +297,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:89ca5c9ddcaf609509aaed9c937c2a72cf400810e3a7892adfb9ac247a13693d + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:bcc01fe4689fbb87ca335d7efea88ec800e05d8796f0828fca984349b7844b09 - name: kind value: task resolver: bundles @@ -314,7 +314,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:a35e1b1e108fe50737e47d5d71368ec882809fdd854096691d4e6fa7bc67e77b + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:4ada9949fd195b50e33605ef06bb52a9bfb523d88529392972ac7a051d5bb549 - name: kind value: task resolver: bundles @@ -344,7 +344,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:10976247ae6c9ae7b04670e8d52e7b521c4ce98806891ddcd7248d3c10b56980 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3e2891c232dc03fb5c7746fc615e1827afbd6931843e42b19cb8a6c04276ed32 - name: kind value: task resolver: bundles From 3b44db3e3e4654028572bfbf858646d9fdba7ebc Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Mon, 25 Nov 2024 15:54:42 +0800 Subject: [PATCH 55/67] update sdk-go to fix resync unstable (#220) Signed-off-by: Wei Liu --- go.mod | 89 ++++++++++--------- go.sum | 237 ++++++++++++++++++++++++++++--------------------- test/helper.go | 2 +- 3 files changed, 184 insertions(+), 144 deletions(-) diff --git a/go.mod b/go.mod index 2f01877a..842b119d 100755 --- a/go.mod +++ b/go.mod @@ -21,39 +21,39 @@ require ( github.com/golang/glog v1.2.1 github.com/google/uuid v1.6.0 github.com/gorilla/handlers v1.5.1 - github.com/gorilla/mux v1.8.0 + github.com/gorilla/mux v1.8.1 github.com/jinzhu/inflection v1.0.0 github.com/lib/pq v1.10.7 github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 - github.com/onsi/ginkgo/v2 v2.20.0 - github.com/onsi/gomega v1.34.1 + github.com/onsi/ginkgo/v2 v2.22.0 + github.com/onsi/gomega v1.35.1 github.com/openshift-online/ocm-common v0.0.0-20240620110211-2ecfa6ec5707 github.com/openshift-online/ocm-sdk-go v0.1.421 - github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81 - github.com/prometheus/client_golang v1.18.0 - github.com/prometheus/client_model v0.5.0 - github.com/prometheus/common v0.45.0 + github.com/openshift/library-go v0.0.0-20241107160307-0064ad7bd060 + github.com/prometheus/client_golang v1.20.5 + github.com/prometheus/client_model v0.6.1 + github.com/prometheus/common v0.55.0 github.com/segmentio/ksuid v1.0.2 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/yaacov/tree-search-language v0.0.0-20190923184055-1c2dad2e354b go.uber.org/zap v1.27.0 - golang.org/x/oauth2 v0.20.0 + golang.org/x/oauth2 v0.21.0 google.golang.org/grpc v1.65.0 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.35.1 gopkg.in/resty.v1 v1.12.0 gorm.io/datatypes v1.2.0 gorm.io/driver/postgres v1.5.0 gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11 - k8s.io/api v0.30.3 - k8s.io/apimachinery v0.30.3 - k8s.io/apiserver v0.30.3 - k8s.io/client-go v0.30.3 - k8s.io/component-base v0.30.3 + k8s.io/api v0.31.3 + k8s.io/apimachinery v0.31.3 + k8s.io/apiserver v0.31.3 + k8s.io/client-go v0.31.3 + k8s.io/component-base v0.31.3 k8s.io/klog/v2 v2.130.1 - open-cluster-management.io/api v0.15.0 - open-cluster-management.io/ocm v0.15.0 - open-cluster-management.io/sdk-go v0.15.1-0.20241118094717-4b0d20455f47 + open-cluster-management.io/api v0.15.1-0.20241120090202-cb7ce98ab874 + open-cluster-management.io/ocm v0.15.1-0.20241125065026-7a190f1a2b18 + open-cluster-management.io/sdk-go v0.15.1-0.20241125015855-1536c3970f8f sigs.k8s.io/yaml v1.4.0 ) @@ -61,8 +61,8 @@ require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr/antlr4 v0.0.0-20200712162734-eb1adaa8a7a6 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect - github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect @@ -78,8 +78,10 @@ require ( github.com/docker/distribution v2.8.1+incompatible // indirect github.com/eclipse/paho.golang v0.21.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/felixge/fgprof v0.9.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect @@ -90,11 +92,11 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.17.8 // indirect + github.com/google/cel-go v0.20.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect github.com/gorilla/css v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect @@ -106,27 +108,29 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/microcosm-cc/bluemonday v1.0.23 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openshift/api v0.0.0-20240527133614-ba11c1587003 // indirect - github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 // indirect + github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f // indirect + github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pkg/profile v1.3.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/pkg/profile v1.7.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/robfig/cron v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/smartystreets/goconvey v1.8.1 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.10 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect - go.etcd.io/etcd/client/v3 v3.5.10 // indirect + github.com/x448/float16 v0.8.4 // indirect + go.etcd.io/etcd/api/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/v3 v3.5.14 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect @@ -138,30 +142,31 @@ require ( go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.26.0 // indirect + golang.org/x/crypto v0.29.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.23.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.26.0 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/mysql v1.4.7 // indirect - k8s.io/apiextensions-apiserver v0.30.3 // indirect - k8s.io/kms v0.30.3 // indirect - k8s.io/kube-aggregator v0.30.3 // indirect + k8s.io/apiextensions-apiserver v0.31.3 // indirect + k8s.io/kms v0.31.3 // indirect + k8s.io/kube-aggregator v0.31.3 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 // indirect - sigs.k8s.io/controller-runtime v0.18.5 // indirect + k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect + sigs.k8s.io/controller-runtime v0.19.2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/go.sum b/go.sum index 7bb2a03b..6d37a926 100644 --- a/go.sum +++ b/go.sum @@ -28,11 +28,11 @@ github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9Pq github.com/antlr/antlr4 v0.0.0-20190518164840-edae2a1c9b4b/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y= github.com/antlr/antlr4 v0.0.0-20200712162734-eb1adaa8a7a6 h1:LHiO9PmM+glloVgvAWMK4pzxxbJYYaqV/k+ued9rxSY= github.com/antlr/antlr4 v0.0.0-20200712162734-eb1adaa8a7a6/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= -github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/auth0/go-jwt-middleware v0.0.0-20190805220309-36081240882b h1:CvoEHGmxWl5kONC5icxwqV899dkf4VjOScbxLpllEnw= github.com/auth0/go-jwt-middleware v0.0.0-20190805220309-36081240882b/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -55,6 +55,15 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= +github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991 h1:3/pjormyqkSjF2GHQehTELZ9oqlER4GrJZiVUIk8Fy8= github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991/go.mod h1:xiar5+gk13WqyAUQ/cpcxcjD1IhLe/PeilSfCdPcfMU= @@ -119,12 +128,17 @@ github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88= +github.com/felixge/fgprof v0.9.4/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/getsentry/sentry-go v0.20.0 h1:bwXW98iMRIWxn+4FgPW7vMrjmbym6HblXALmhjHmQaQ= github.com/getsentry/sentry-go v0.20.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -156,6 +170,9 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -196,8 +213,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cel-go v0.17.8 h1:j9m730pMZt1Fc4oKhCLUHfjj6527LuhYcYw0Rl8gqto= -github.com/google/cel-go v0.17.8/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= +github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -215,8 +232,10 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -230,8 +249,8 @@ github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/graphql-go/graphql v0.7.8/go.mod h1:k6yrAYQaSP59DC5UVxbgxESlmVyojThKdORUqGDGmrI= @@ -247,6 +266,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hokaccha/go-prettyjson v0.0.0-20180920040306-f579f869bbfe/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -336,6 +357,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -350,10 +373,13 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -378,8 +404,6 @@ github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71 github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 h1:Z/i1e+gTZrmcGeZyWckaLfucYG6KYOXLWo4co8pZYNY= github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE= github.com/microcosm-cc/bluemonday v1.0.23 h1:SMZe2IGa0NuHvnVNAZ+6B38gsTbi5e4sViiWJyDDqFY= @@ -390,10 +414,10 @@ github.com/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs= github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/mochi-mqtt/server/v2 v2.6.5 h1:9PiQ6EJt/Dx0ut0Fuuir4F6WinO/5Bpz9szujNwm+q8= -github.com/mochi-mqtt/server/v2 v2.6.5/go.mod h1:TqztjKGO0/ArOjJt9x9idk0kqPT3CVN8Pb+l+PS5Gdo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/mochi-mqtt/server/v2 v2.6.6 h1:FmL5ebeIIA+AKo/nX0DF8Yc2MMWFLQCwh3FZBEmg6dQ= +github.com/mochi-mqtt/server/v2 v2.6.6/go.mod h1:TqztjKGO0/ArOjJt9x9idk0kqPT3CVN8Pb+l+PS5Gdo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -407,29 +431,30 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= -github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= -github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= +github.com/opencontainers/runc v1.1.13 h1:98S2srgG9vw0zWcDpFMn5TRrh8kLxa/5OFUstuUhmRs= +github.com/opencontainers/runc v1.1.13/go.mod h1:R016aXacfp/gwQBYw2FDGa9m+n6atbLWrYY8hNMT/sA= github.com/openshift-online/ocm-common v0.0.0-20240620110211-2ecfa6ec5707 h1:i9J9pgnZLd9kIls1axOLJxA3qkbJjYXM2Ut6jRAdxhc= github.com/openshift-online/ocm-common v0.0.0-20240620110211-2ecfa6ec5707/go.mod h1:2NApKjtzSOsW9MVf58LwAnSCSIK48U1Z/m7dWGOQ5fw= github.com/openshift-online/ocm-sdk-go v0.1.421 h1:x4zUDN+32IW98RXhccMKanjODy6HehxwDR68t2MhFPc= github.com/openshift-online/ocm-sdk-go v0.1.421/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y= -github.com/openshift/api v0.0.0-20240527133614-ba11c1587003 h1:ewhIvyXCcvH6m3U02bMFtd/DfsmOSbOCuVzon+zGu7g= -github.com/openshift/api v0.0.0-20240527133614-ba11c1587003/go.mod h1:OOh6Qopf21pSzqNVCB5gomomBXb8o5sGKZxG2KNpaXM= -github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 h1:JtLhaGpSEconE+1IKmIgCOof/Len5ceG6H1pk43yv5U= -github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87/go.mod h1:3IPD4U0qyovZS4EFady2kqY32m8lGcbs/Wx+yprg9z8= -github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81 h1:cAo++YCkjrClksMEAPqK9SLMCroqlbGxNTluxeKGIGc= -github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81/go.mod h1:PdASVamWinll2BPxiUpXajTwZxV8A1pQbWEsCN1od7I= +github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f h1:ya1OmyZm3LIIxI3U9VE9Nyx3ehCHgBwxyFUPflYPWls= +github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo= +github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f h1:FRc0bVNWprihWS0GqQWzb3dY4dkCwpOP3mDw5NwSoR4= +github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f/go.mod h1:KiZi2mJRH1TOJ3FtBDYS6YvUL30s/iIXaGSUrSa36mo= +github.com/openshift/library-go v0.0.0-20241107160307-0064ad7bd060 h1:jiDC7d8d+jmjv2WfiMY0+Uf55q11MGyYkGGqXnfqWTU= +github.com/openshift/library-go v0.0.0-20241107160307-0064ad7bd060/go.mod h1:9B1MYPoLtP9tqjWxcbUNVpwxy68zOH/3EIP6c31dAM0= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= @@ -437,26 +462,29 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.3.0 h1:OQIvuDgm00gWVWGTf4m4mCt6W1/0YqU7Ntg0mySWgaI= -github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= +github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0 h1:AHzMWDxNiAVscJL6+4wkvFRTpMnJqiaZFEKA/osaBXE= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0/go.mod h1:wAR5JopumPtAZnu0Cjv2PSqV4p4QB09LMhc6fZZTXuA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= @@ -520,6 +548,8 @@ github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= @@ -530,22 +560,22 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= -go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= -go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= -go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= -go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= -go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4= -go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= -go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= -go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= -go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM= -go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs= -go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA= -go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc= -go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg= -go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo= +go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0= +go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU= +go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ= +go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI= +go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8= +go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= +go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg= +go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk= +go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= +go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= +go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= +go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= +go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= +go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= go.mongodb.org/mongo-driver v1.0.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -597,8 +627,8 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -642,13 +672,13 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -658,8 +688,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -681,25 +711,28 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -724,8 +757,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -770,14 +803,16 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -820,38 +855,38 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190531162725-42df64e2171a/go.mod h1:wtc9q0E9zm8PjdRMh29DPlTlCCHVzKDwnkT4GskQVzg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= -k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= -k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U= -k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4= -k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= -k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/apiserver v0.30.3 h1:QZJndA9k2MjFqpnyYv/PH+9PE0SHhx3hBho4X0vE65g= -k8s.io/apiserver v0.30.3/go.mod h1:6Oa88y1CZqnzetd2JdepO0UXzQX4ZnOekx2/PtEjrOg= -k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= -k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= -k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s= -k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA= +k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= +k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= +k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u+nciE= +k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4= +k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= +k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.31.3 h1:+1oHTtCB+OheqFEz375D0IlzHZ5VeQKX1KGXnx+TTuY= +k8s.io/apiserver v0.31.3/go.mod h1:PrxVbebxrxQPFhJk4powDISIROkNMKHibTg9lTRQ0Qg= +k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= +k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= +k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ= +k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.30.3 h1:NLg+oN45S2Y3U0WiLRzbS61AY/XrS5JBMZp531Z+Pho= -k8s.io/kms v0.30.3/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4= -k8s.io/kube-aggregator v0.30.3 h1:hy5zfQ7p6BuJgc/XtGp3GBh2MPfOj6b1n3raKKMHOQE= -k8s.io/kube-aggregator v0.30.3/go.mod h1:2SP0IckvQoOwwZN8lmtWUnTZTgIpwOWvidWtxyqLwuk= +k8s.io/kms v0.31.3 h1:XCFmiJn5CCKs8xoOLpCmu42Ubm/KW85wNHybGFcSAYc= +k8s.io/kms v0.31.3/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94= +k8s.io/kube-aggregator v0.31.3 h1:DqHPdTglJHgOfB884AaroyxrML/aL82ASYOh65m7MSk= +k8s.io/kube-aggregator v0.31.3/go.mod h1:Kx59Xjnf0SnY47qf9Or++4y3XCHQ3kR0xk1Di6KFiFU= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= -k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -open-cluster-management.io/api v0.15.0 h1:lRee1KOlGHZb2scTA7ff9E9Fxt2hJc7jpkHnaCbvkOU= -open-cluster-management.io/api v0.15.0/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= -open-cluster-management.io/ocm v0.15.0 h1:anXQzvQUhM/DT8FcKVi4n8AY97IA5DVI0mb8R1wsvbs= -open-cluster-management.io/ocm v0.15.0/go.mod h1:d6ubRiBaouiQ+yV+wFAmarpU7I77nXhkJnQJf8gLZC4= -open-cluster-management.io/sdk-go v0.15.1-0.20241118094717-4b0d20455f47 h1:1gNvY3quZ6CWeXnwCLAXuEoNjGGZL+U4uS79vuo8API= -open-cluster-management.io/sdk-go v0.15.1-0.20241118094717-4b0d20455f47/go.mod h1:fi5WBsbC5K3txKb8eRLuP0Sim/Oqz/PHX18skAEyjiA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= -sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= -sigs.k8s.io/controller-runtime v0.18.5/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY9mD9fNT47QO6HI= +k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +open-cluster-management.io/api v0.15.1-0.20241120090202-cb7ce98ab874 h1:WgkuYXTbJV7EK+qtiMq3soa21faGUKeTG5w0C8Mn1Ok= +open-cluster-management.io/api v0.15.1-0.20241120090202-cb7ce98ab874/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= +open-cluster-management.io/ocm v0.15.1-0.20241125065026-7a190f1a2b18 h1:sLg+JNnjMRE7WwLbzxURYRPD3ZZr/WHydcGC5/jOE/A= +open-cluster-management.io/ocm v0.15.1-0.20241125065026-7a190f1a2b18/go.mod h1:083SWgAjjvkc0TcOwf8wI8HCrCYaUWP860YTs+y8zXY= +open-cluster-management.io/sdk-go v0.15.1-0.20241125015855-1536c3970f8f h1:zeC7QrFNarfK2zY6jGtd+mX+yDrQQmnH/J8A7n5Nh38= +open-cluster-management.io/sdk-go v0.15.1-0.20241125015855-1536c3970f8f/go.mod h1:fi5WBsbC5K3txKb8eRLuP0Sim/Oqz/PHX18skAEyjiA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.19.2 h1:3sPrF58XQEPzbE8T81TN6selQIMGbtYwuaJ6eDssDF8= +sigs.k8s.io/controller-runtime v0.19.2/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 h1:PFWFSkpArPNJxFX4ZKWAk9NSeRoZaXschn+ULa4xVek= diff --git a/test/helper.go b/test/helper.go index 25c9423a..bf8b22df 100755 --- a/test/helper.go +++ b/test/helper.go @@ -292,7 +292,7 @@ func (helper *Helper) StartWorkAgent(ctx context.Context, clusterName string, bu workinformers.WithNamespace(clusterName), ) informer := factory.Work().V1().ManifestWorks() - watcherStore.SetStore(informer.Informer().GetStore()) + watcherStore.SetInformer(informer.Informer()) go informer.Informer().Run(ctx.Done()) From 3a56948922f4bc5f8d921b6975f750f55c0cb88d Mon Sep 17 00:00:00 2001 From: Chunlin Yang Date: Fri, 29 Nov 2024 15:06:34 +0800 Subject: [PATCH 56/67] Support az-entra auth (#221) Signed-off-by: clyang82 --- go.mod | 6 ++++ go.sum | 13 +++++++++ pkg/config/db.go | 38 +++++++++++++++++++++++--- pkg/constants/constants.go | 3 ++ templates/service-template-aro-hcp.yml | 1 + 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 842b119d..cbc03d3d 100755 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/openshift-online/maestro go 1.22.5 require ( + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 github.com/Masterminds/squirrel v1.5.3 github.com/auth0/go-jwt-middleware v0.0.0-20190805220309-36081240882b github.com/buraksezer/consistent v0.10.0 @@ -59,6 +61,8 @@ require ( require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr/antlr4 v0.0.0-20200712162734-eb1adaa8a7a6 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect @@ -90,6 +94,7 @@ require ( github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/cel-go v0.20.1 // indirect @@ -119,6 +124,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f // indirect github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/profile v1.7.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect diff --git a/go.sum b/go.sum index 6d37a926..8167e651 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,16 @@ cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7h cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 h1:1nGuui+4POelzDwI7RG56yfQJHCnKvwfMoU7VsEp+Zg= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0/go.mod h1:99EvauvlcJ1U06amZiksfYz/3aFGyIhWGHVyiZXtBAI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 h1:H+U3Gk9zY56G3u872L82bk4thcsy2Gghb9ExT4Zvm1o= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0/go.mod h1:mgrmMSgaLp9hmax62XQTd0N4aAqSE5E0DulSpVYK7vc= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/squirrel v1.1.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= @@ -181,6 +189,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -458,6 +468,8 @@ github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzb github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -716,6 +728,7 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= diff --git a/pkg/config/db.go b/pkg/config/db.go index 65c95aed..08ab1837 100755 --- a/pkg/config/db.go +++ b/pkg/config/db.go @@ -1,8 +1,12 @@ package config import ( + "context" "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/openshift-online/maestro/pkg/constants" "github.com/spf13/pflag" ) @@ -24,10 +28,16 @@ type DatabaseConfig struct { UsernameFile string `json:"username_file"` PasswordFile string `json:"password_file"` RootCertFile string `json:"certificate_file"` + + AuthMethod string `json:"auth_method"` + TokenRequestScope string `json:"token_request_scope"` } func NewDatabaseConfig() *DatabaseConfig { return &DatabaseConfig{ + AuthMethod: constants.AuthMethodPassword, + TokenRequestScope: "https://ossrdbms-aad.database.windows.net/.default", + Dialect: "postgres", SSLMode: "disable", Debug: false, @@ -43,6 +53,9 @@ func NewDatabaseConfig() *DatabaseConfig { } func (c *DatabaseConfig) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&c.AuthMethod, "db-auth-method", c.AuthMethod, "Configure the authentication to use password as the default and az-entra for Microsoft Entra Authentication in Azure PostgreSQL") + fs.StringVar(&c.TokenRequestScope, "db-token-request-scope", c.TokenRequestScope, "Configure the token request scope for Open-Source Relational Database Management Systems in Azure") + fs.StringVar(&c.HostFile, "db-host-file", c.HostFile, "Database host string file") fs.StringVar(&c.PortFile, "db-port-file", c.PortFile, "Database port file") fs.StringVar(&c.UsernameFile, "db-user-file", c.UsernameFile, "Database username file") @@ -50,7 +63,7 @@ func (c *DatabaseConfig) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&c.NameFile, "db-name-file", c.NameFile, "Database name file") fs.StringVar(&c.RootCertFile, "db-rootcert", c.RootCertFile, "Database root certificate file") fs.StringVar(&c.SSLMode, "db-sslmode", c.SSLMode, "Database ssl mode (disable | require | verify-ca | verify-full)") - fs.BoolVar(&c.Debug, "enable-db-debug", c.Debug, " framework's debug mode") + fs.BoolVar(&c.Debug, "enable-db-debug", c.Debug, "framework's debug mode") fs.IntVar(&c.MaxOpenConnections, "db-max-open-connections", c.MaxOpenConnections, "Maximum open DB connections for this instance") } @@ -70,9 +83,26 @@ func (c *DatabaseConfig) ReadFiles() error { return err } - err = readFileValueString(c.PasswordFile, &c.Password) - if err != nil { - return err + if c.AuthMethod == constants.AuthMethodMicrosoftEntra { + // ARO-HCP environment variable configuration is set by the Azure workload identity webhook. + // Use [WorkloadIdentityCredential] directly when not using the webhook or needing more control over its configuration. + cred, err := azidentity.NewDefaultAzureCredential(nil) + if err != nil { + return err + } + // The access token can be expired. but the existing connections are not invalidated. + // TODO: how to reconnect due to the network is broken etc. Right now, gorm does not have this feature. + // refer to https://github.com/go-gorm/gorm/issues/5602 & https://github.com/go-gorm/gorm/pull/1721. + token, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{Scopes: []string{c.TokenRequestScope}}) + if err != nil { + return err + } + c.Password = token.Token + } else { + err = readFileValueString(c.PasswordFile, &c.Password) + if err != nil { + return err + } } err = readFileValueString(c.NameFile, &c.Name) diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 6467883b..30877d12 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -2,4 +2,7 @@ package constants const ( DefaultSourceID = "maestro" + + AuthMethodPassword = "password" // Standard postgres username/password authentication. + AuthMethodMicrosoftEntra = "az-entra" // Microsoft Entra ID-based token authentication. ) diff --git a/templates/service-template-aro-hcp.yml b/templates/service-template-aro-hcp.yml index 90b5df81..441cfa89 100755 --- a/templates/service-template-aro-hcp.yml +++ b/templates/service-template-aro-hcp.yml @@ -184,6 +184,7 @@ objects: metadata: labels: app: maestro + azure.workload.identity/use: "true" # Required. Only pods with this label can use workload identity. spec: serviceAccountName: maestro volumes: From eb5580b525f99927d4f84d38448592ec63b4d9ce Mon Sep 17 00:00:00 2001 From: red-hat-konflux Date: Mon, 29 Apr 2024 13:21:00 +0000 Subject: [PATCH 57/67] Red Hat Konflux update maestro-main --- .tekton/maestro-main-pull-request.yaml | 422 +++++++++++++++++++++++++ .tekton/maestro-main-push.yaml | 419 ++++++++++++++++++++++++ 2 files changed, 841 insertions(+) create mode 100644 .tekton/maestro-main-pull-request.yaml create mode 100644 .tekton/maestro-main-push.yaml diff --git a/.tekton/maestro-main-pull-request.yaml b/.tekton/maestro-main-pull-request.yaml new file mode 100644 index 00000000..1672bf4e --- /dev/null +++ b/.tekton/maestro-main-pull-request.yaml @@ -0,0 +1,422 @@ +apiVersion: tekton.dev/v1 +kind: PipelineRun +metadata: + annotations: + build.appstudio.openshift.io/repo: https://github.com/stolostron/maestro?rev={{revision}} + build.appstudio.redhat.com/commit_sha: '{{revision}}' + build.appstudio.redhat.com/pull_request_number: '{{pull_request_number}}' + build.appstudio.redhat.com/target_branch: '{{target_branch}}' + pipelinesascode.tekton.dev/max-keep-runs: "3" + pipelinesascode.tekton.dev/on-cel-expression: event == "pull_request" && target_branch + == "main" + creationTimestamp: null + labels: + appstudio.openshift.io/application: maestro-main + appstudio.openshift.io/component: maestro-main + pipelines.appstudio.openshift.io/type: build + name: maestro-main-on-pull-request + namespace: crt-redhat-acm-tenant +spec: + params: + - name: dockerfile + value: Containerfile.rhtap + - name: git-url + value: '{{source_url}}' + - name: image-expires-after + value: 5d + - name: output-image + value: quay.io/redhat-user-workloads/crt-redhat-acm-tenant/maestro-main/maestro-main:on-pr-{{revision}} + - name: path-context + value: . + - name: revision + value: '{{revision}}' + pipelineSpec: + finally: + - name: show-sbom + params: + - name: IMAGE_URL + value: $(tasks.build-container.results.IMAGE_URL) + taskRef: + params: + - name: name + value: show-sbom + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:1f90faefa39c2e4965793c1d8321e7d5d99a6c941276a9094a4e0d483a598fca + - name: kind + value: task + resolver: bundles + - name: show-summary + params: + - name: pipelinerun-name + value: $(context.pipelineRun.name) + - name: git-url + value: $(tasks.clone-repository.results.url)?rev=$(tasks.clone-repository.results.commit) + - name: image-url + value: $(params.output-image) + - name: build-task-status + value: $(tasks.build-container.status) + taskRef: + params: + - name: name + value: summary + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:535fd85afc42c856364653177edeb05cad9f6b9fa51cc893b7a29b099a6c8555 + - name: kind + value: task + resolver: bundles + workspaces: + - name: workspace + workspace: workspace + params: + - description: Source Repository URL + name: git-url + type: string + - default: "" + description: Revision of the Source Repository + name: revision + type: string + - description: Fully Qualified Output Image + name: output-image + type: string + - default: . + description: Path to the source code of an application's component from where + to build image. + name: path-context + type: string + - default: Dockerfile + description: Path to the Dockerfile inside the context specified by parameter + path-context + name: dockerfile + type: string + - default: "false" + description: Force rebuild image + name: rebuild + type: string + - default: "false" + description: Skip checks against built image + name: skip-checks + type: string + - default: "false" + description: Execute the build with network isolation + name: hermetic + type: string + - default: "" + description: Build dependencies to be prefetched by Cachi2 + name: prefetch-input + type: string + - default: "false" + description: Java build + name: java + type: string + - default: "" + description: Image tag expiration time, time values could be something like + 1h, 2d, 3w for hours, days, and weeks, respectively. + name: image-expires-after + - default: "false" + description: Build a source image. + name: build-source-image + type: string + - default: "" + description: Path to a file with build arguments which will be passed to podman + during build + name: build-args-file + type: string + results: + - description: "" + name: IMAGE_URL + value: $(tasks.build-container.results.IMAGE_URL) + - description: "" + name: IMAGE_DIGEST + value: $(tasks.build-container.results.IMAGE_DIGEST) + - description: "" + name: CHAINS-GIT_URL + value: $(tasks.clone-repository.results.url) + - description: "" + name: CHAINS-GIT_COMMIT + value: $(tasks.clone-repository.results.commit) + - description: "" + name: JAVA_COMMUNITY_DEPENDENCIES + value: $(tasks.build-container.results.JAVA_COMMUNITY_DEPENDENCIES) + tasks: + - name: init + params: + - name: image-url + value: $(params.output-image) + - name: rebuild + value: $(params.rebuild) + - name: skip-checks + value: $(params.skip-checks) + taskRef: + params: + - name: name + value: init + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:3d8f01fa59596a998d30dc700fcf7377f09d60008337290eebaeaf604512ce2b + - name: kind + value: task + resolver: bundles + - name: clone-repository + params: + - name: url + value: $(params.git-url) + - name: revision + value: $(params.revision) + runAfter: + - init + taskRef: + params: + - name: name + value: git-clone + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:fffe6234a4d60c63b97af86642369e4931a404f6dc8be0d12743f7651a4dc802 + - name: kind + value: task + resolver: bundles + when: + - input: $(tasks.init.results.build) + operator: in + values: + - "true" + workspaces: + - name: output + workspace: workspace + - name: basic-auth + workspace: git-auth + - name: prefetch-dependencies + params: + - name: input + value: $(params.prefetch-input) + runAfter: + - clone-repository + taskRef: + params: + - name: name + value: prefetch-dependencies + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:6687b3a54a8cbfbb5c2904d447bbb3d48d5739c5e201f6ddf0c4b471a7e35e27 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.hermetic) + operator: in + values: + - "true" + workspaces: + - name: source + workspace: workspace + - name: git-basic-auth + workspace: git-auth + - name: build-container + params: + - name: IMAGE + value: $(params.output-image) + - name: DOCKERFILE + value: $(params.dockerfile) + - name: CONTEXT + value: $(params.path-context) + - name: HERMETIC + value: $(params.hermetic) + - name: PREFETCH_INPUT + value: $(params.prefetch-input) + - name: IMAGE_EXPIRES_AFTER + value: $(params.image-expires-after) + - name: COMMIT_SHA + value: $(tasks.clone-repository.results.commit) + - name: BUILD_ARGS_FILE + value: $(params.build-args-file) + runAfter: + - prefetch-dependencies + taskRef: + params: + - name: name + value: buildah + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:7e5f19d3aa233b9becf90d1ca01697486dc1acb1f1d6d2a0b8d1a1cc07c66249 + - name: kind + value: task + resolver: bundles + when: + - input: $(tasks.init.results.build) + operator: in + values: + - "true" + workspaces: + - name: source + workspace: workspace + - name: build-source-image + params: + - name: BINARY_IMAGE + value: $(params.output-image) + - name: BASE_IMAGES + value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) + runAfter: + - build-container + taskRef: + params: + - name: name + value: source-build + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:90dc9c66eb0123b5e5ff8a1b8c3891e91f0e952899e427eeca79b635fe81a348 + - name: kind + value: task + resolver: bundles + when: + - input: $(tasks.init.results.build) + operator: in + values: + - "true" + - input: $(params.build-source-image) + operator: in + values: + - "true" + workspaces: + - name: workspace + workspace: workspace + - name: deprecated-base-image-check + params: + - name: BASE_IMAGES_DIGESTS + value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) + runAfter: + - build-container + taskRef: + params: + - name: name + value: deprecated-image-check + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.3@sha256:ba55ff56b8718406278d72fd5e3de88da110dd4391aa7581923b8d219a29f841 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + - name: clair-scan + params: + - name: image-digest + value: $(tasks.build-container.results.IMAGE_DIGEST) + - name: image-url + value: $(tasks.build-container.results.IMAGE_URL) + runAfter: + - build-container + taskRef: + params: + - name: name + value: clair-scan + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:1455df3ae446fd2205e6e3457310acbf2eb9754e08f1ee9e43520fd76689c495 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + - name: ecosystem-cert-preflight-checks + params: + - name: image-url + value: $(tasks.build-container.results.IMAGE_URL) + runAfter: + - build-container + taskRef: + params: + - name: name + value: ecosystem-cert-preflight-checks + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:4bcabe436ddbef6af8f8108ee234d83e116e63e91f64a77191e1492db11bf56b + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + - name: sast-snyk-check + runAfter: + - clone-repository + taskRef: + params: + - name: name + value: sast-snyk-check + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:422177f6fffa55284a30ddc4a26dca1462aee34a479529b9e2b52a5bb39606a4 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + workspaces: + - name: workspace + workspace: workspace + - name: clamav-scan + params: + - name: image-digest + value: $(tasks.build-container.results.IMAGE_DIGEST) + - name: image-url + value: $(tasks.build-container.results.IMAGE_URL) + runAfter: + - build-container + taskRef: + params: + - name: name + value: clamav-scan + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fbdd8b4ca9235f73d630d5a71c71d1042bbe7971eefba081dea827b6ee489c19 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + - name: sbom-json-check + params: + - name: IMAGE_URL + value: $(tasks.build-container.results.IMAGE_URL) + - name: IMAGE_DIGEST + value: $(tasks.build-container.results.IMAGE_DIGEST) + runAfter: + - build-container + taskRef: + params: + - name: name + value: sbom-json-check + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:83441b9688d6921c832e7424c446fdfd4e62ee844dfe4000b97fa2f1726ecd42 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + workspaces: + - name: workspace + - name: git-auth + optional: true + taskRunTemplate: {} + workspaces: + - name: workspace + volumeClaimTemplate: + metadata: + creationTimestamp: null + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + status: {} + - name: git-auth + secret: + secretName: '{{ git_auth_secret }}' +status: {} diff --git a/.tekton/maestro-main-push.yaml b/.tekton/maestro-main-push.yaml new file mode 100644 index 00000000..5a03c159 --- /dev/null +++ b/.tekton/maestro-main-push.yaml @@ -0,0 +1,419 @@ +apiVersion: tekton.dev/v1 +kind: PipelineRun +metadata: + annotations: + build.appstudio.openshift.io/repo: https://github.com/stolostron/maestro?rev={{revision}} + build.appstudio.redhat.com/commit_sha: '{{revision}}' + build.appstudio.redhat.com/target_branch: '{{target_branch}}' + pipelinesascode.tekton.dev/max-keep-runs: "3" + pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch + == "main" + creationTimestamp: null + labels: + appstudio.openshift.io/application: maestro-main + appstudio.openshift.io/component: maestro-main + pipelines.appstudio.openshift.io/type: build + name: maestro-main-on-push + namespace: crt-redhat-acm-tenant +spec: + params: + - name: dockerfile + value: Containerfile.rhtap + - name: git-url + value: '{{source_url}}' + - name: output-image + value: quay.io/redhat-user-workloads/crt-redhat-acm-tenant/maestro-main/maestro-main:{{revision}} + - name: path-context + value: . + - name: revision + value: '{{revision}}' + pipelineSpec: + finally: + - name: show-sbom + params: + - name: IMAGE_URL + value: $(tasks.build-container.results.IMAGE_URL) + taskRef: + params: + - name: name + value: show-sbom + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:1f90faefa39c2e4965793c1d8321e7d5d99a6c941276a9094a4e0d483a598fca + - name: kind + value: task + resolver: bundles + - name: show-summary + params: + - name: pipelinerun-name + value: $(context.pipelineRun.name) + - name: git-url + value: $(tasks.clone-repository.results.url)?rev=$(tasks.clone-repository.results.commit) + - name: image-url + value: $(params.output-image) + - name: build-task-status + value: $(tasks.build-container.status) + taskRef: + params: + - name: name + value: summary + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:535fd85afc42c856364653177edeb05cad9f6b9fa51cc893b7a29b099a6c8555 + - name: kind + value: task + resolver: bundles + workspaces: + - name: workspace + workspace: workspace + params: + - description: Source Repository URL + name: git-url + type: string + - default: "" + description: Revision of the Source Repository + name: revision + type: string + - description: Fully Qualified Output Image + name: output-image + type: string + - default: . + description: Path to the source code of an application's component from where + to build image. + name: path-context + type: string + - default: Dockerfile + description: Path to the Dockerfile inside the context specified by parameter + path-context + name: dockerfile + type: string + - default: "false" + description: Force rebuild image + name: rebuild + type: string + - default: "false" + description: Skip checks against built image + name: skip-checks + type: string + - default: "false" + description: Execute the build with network isolation + name: hermetic + type: string + - default: "" + description: Build dependencies to be prefetched by Cachi2 + name: prefetch-input + type: string + - default: "false" + description: Java build + name: java + type: string + - default: "" + description: Image tag expiration time, time values could be something like + 1h, 2d, 3w for hours, days, and weeks, respectively. + name: image-expires-after + - default: "false" + description: Build a source image. + name: build-source-image + type: string + - default: "" + description: Path to a file with build arguments which will be passed to podman + during build + name: build-args-file + type: string + results: + - description: "" + name: IMAGE_URL + value: $(tasks.build-container.results.IMAGE_URL) + - description: "" + name: IMAGE_DIGEST + value: $(tasks.build-container.results.IMAGE_DIGEST) + - description: "" + name: CHAINS-GIT_URL + value: $(tasks.clone-repository.results.url) + - description: "" + name: CHAINS-GIT_COMMIT + value: $(tasks.clone-repository.results.commit) + - description: "" + name: JAVA_COMMUNITY_DEPENDENCIES + value: $(tasks.build-container.results.JAVA_COMMUNITY_DEPENDENCIES) + tasks: + - name: init + params: + - name: image-url + value: $(params.output-image) + - name: rebuild + value: $(params.rebuild) + - name: skip-checks + value: $(params.skip-checks) + taskRef: + params: + - name: name + value: init + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:3d8f01fa59596a998d30dc700fcf7377f09d60008337290eebaeaf604512ce2b + - name: kind + value: task + resolver: bundles + - name: clone-repository + params: + - name: url + value: $(params.git-url) + - name: revision + value: $(params.revision) + runAfter: + - init + taskRef: + params: + - name: name + value: git-clone + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:fffe6234a4d60c63b97af86642369e4931a404f6dc8be0d12743f7651a4dc802 + - name: kind + value: task + resolver: bundles + when: + - input: $(tasks.init.results.build) + operator: in + values: + - "true" + workspaces: + - name: output + workspace: workspace + - name: basic-auth + workspace: git-auth + - name: prefetch-dependencies + params: + - name: input + value: $(params.prefetch-input) + runAfter: + - clone-repository + taskRef: + params: + - name: name + value: prefetch-dependencies + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:6687b3a54a8cbfbb5c2904d447bbb3d48d5739c5e201f6ddf0c4b471a7e35e27 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.hermetic) + operator: in + values: + - "true" + workspaces: + - name: source + workspace: workspace + - name: git-basic-auth + workspace: git-auth + - name: build-container + params: + - name: IMAGE + value: $(params.output-image) + - name: DOCKERFILE + value: $(params.dockerfile) + - name: CONTEXT + value: $(params.path-context) + - name: HERMETIC + value: $(params.hermetic) + - name: PREFETCH_INPUT + value: $(params.prefetch-input) + - name: IMAGE_EXPIRES_AFTER + value: $(params.image-expires-after) + - name: COMMIT_SHA + value: $(tasks.clone-repository.results.commit) + - name: BUILD_ARGS_FILE + value: $(params.build-args-file) + runAfter: + - prefetch-dependencies + taskRef: + params: + - name: name + value: buildah + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:7e5f19d3aa233b9becf90d1ca01697486dc1acb1f1d6d2a0b8d1a1cc07c66249 + - name: kind + value: task + resolver: bundles + when: + - input: $(tasks.init.results.build) + operator: in + values: + - "true" + workspaces: + - name: source + workspace: workspace + - name: build-source-image + params: + - name: BINARY_IMAGE + value: $(params.output-image) + - name: BASE_IMAGES + value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) + runAfter: + - build-container + taskRef: + params: + - name: name + value: source-build + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:90dc9c66eb0123b5e5ff8a1b8c3891e91f0e952899e427eeca79b635fe81a348 + - name: kind + value: task + resolver: bundles + when: + - input: $(tasks.init.results.build) + operator: in + values: + - "true" + - input: $(params.build-source-image) + operator: in + values: + - "true" + workspaces: + - name: workspace + workspace: workspace + - name: deprecated-base-image-check + params: + - name: BASE_IMAGES_DIGESTS + value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) + runAfter: + - build-container + taskRef: + params: + - name: name + value: deprecated-image-check + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.3@sha256:ba55ff56b8718406278d72fd5e3de88da110dd4391aa7581923b8d219a29f841 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + - name: clair-scan + params: + - name: image-digest + value: $(tasks.build-container.results.IMAGE_DIGEST) + - name: image-url + value: $(tasks.build-container.results.IMAGE_URL) + runAfter: + - build-container + taskRef: + params: + - name: name + value: clair-scan + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:1455df3ae446fd2205e6e3457310acbf2eb9754e08f1ee9e43520fd76689c495 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + - name: ecosystem-cert-preflight-checks + params: + - name: image-url + value: $(tasks.build-container.results.IMAGE_URL) + runAfter: + - build-container + taskRef: + params: + - name: name + value: ecosystem-cert-preflight-checks + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:4bcabe436ddbef6af8f8108ee234d83e116e63e91f64a77191e1492db11bf56b + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + - name: sast-snyk-check + runAfter: + - clone-repository + taskRef: + params: + - name: name + value: sast-snyk-check + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:422177f6fffa55284a30ddc4a26dca1462aee34a479529b9e2b52a5bb39606a4 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + workspaces: + - name: workspace + workspace: workspace + - name: clamav-scan + params: + - name: image-digest + value: $(tasks.build-container.results.IMAGE_DIGEST) + - name: image-url + value: $(tasks.build-container.results.IMAGE_URL) + runAfter: + - build-container + taskRef: + params: + - name: name + value: clamav-scan + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fbdd8b4ca9235f73d630d5a71c71d1042bbe7971eefba081dea827b6ee489c19 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + - name: sbom-json-check + params: + - name: IMAGE_URL + value: $(tasks.build-container.results.IMAGE_URL) + - name: IMAGE_DIGEST + value: $(tasks.build-container.results.IMAGE_DIGEST) + runAfter: + - build-container + taskRef: + params: + - name: name + value: sbom-json-check + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:83441b9688d6921c832e7424c446fdfd4e62ee844dfe4000b97fa2f1726ecd42 + - name: kind + value: task + resolver: bundles + when: + - input: $(params.skip-checks) + operator: in + values: + - "false" + workspaces: + - name: workspace + - name: git-auth + optional: true + taskRunTemplate: {} + workspaces: + - name: workspace + volumeClaimTemplate: + metadata: + creationTimestamp: null + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + status: {} + - name: git-auth + secret: + secretName: '{{ git_auth_secret }}' +status: {} From 8182d82efeef4951c1fe1a94108b15f6e5b54990 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Fri, 17 May 2024 11:08:44 +0800 Subject: [PATCH 58/67] Enable build with kafka Signed-off-by: clyang82 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 87326eb1..cca7740f 100755 --- a/Makefile +++ b/Makefile @@ -178,7 +178,7 @@ lint: # Build binaries # NOTE it may be necessary to use CGO_ENABLED=0 for backwards compatibility with centos7 if not using centos7 binary: check-gopath - ${GO} build ./cmd/maestro + ${GO} build -tags=kafka ./cmd/maestro .PHONY: binary # Install From 6f7b916e91c3d40680de07ff59faf4a7d0fa2931 Mon Sep 17 00:00:00 2001 From: red-hat-konflux <123456+red-hat-konflux[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 12:12:42 +0000 Subject: [PATCH 59/67] Update Konflux references Signed-off-by: red-hat-konflux <123456+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-main-pull-request.yaml | 26 +++++++++++++------------- .tekton/maestro-main-push.yaml | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.tekton/maestro-main-pull-request.yaml b/.tekton/maestro-main-pull-request.yaml index 1672bf4e..b4adf1b3 100644 --- a/.tekton/maestro-main-pull-request.yaml +++ b/.tekton/maestro-main-pull-request.yaml @@ -41,7 +41,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:1f90faefa39c2e4965793c1d8321e7d5d99a6c941276a9094a4e0d483a598fca + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:9cd4bf015b18621834f40ed02c8dccda1f7834c7d989521a8314bdb3a596e96b - name: kind value: task resolver: bundles @@ -60,7 +60,7 @@ spec: - name: name value: summary - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:535fd85afc42c856364653177edeb05cad9f6b9fa51cc893b7a29b099a6c8555 + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:51d5aaa4e13e9fb4303f667e38d07e758820040032ed9fb3ab5f6afaaffc60d8 - name: kind value: task resolver: bundles @@ -151,7 +151,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:3d8f01fa59596a998d30dc700fcf7377f09d60008337290eebaeaf604512ce2b + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:b23c7a924f303a67b3a00b32a6713ae1a4fccbc5327daa76a6edd250501ea7a3 - name: kind value: task resolver: bundles @@ -168,7 +168,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:fffe6234a4d60c63b97af86642369e4931a404f6dc8be0d12743f7651a4dc802 + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:ae1249aa49e82da5f99cc23b256172dce8f7c7951ece68ca0419240c4ecb52e2 - name: kind value: task resolver: bundles @@ -193,7 +193,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:6687b3a54a8cbfbb5c2904d447bbb3d48d5739c5e201f6ddf0c4b471a7e35e27 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:9aec3ae9f0f50a05abdc739faf4cbc82832cff16c77ac74e1d54072a882c0503 - name: kind value: task resolver: bundles @@ -232,7 +232,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:7e5f19d3aa233b9becf90d1ca01697486dc1acb1f1d6d2a0b8d1a1cc07c66249 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:102500165339bc08791775cf2c4dcae3dd4bde557a9009d44dc590ef66dde384 - name: kind value: task resolver: bundles @@ -257,7 +257,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:90dc9c66eb0123b5e5ff8a1b8c3891e91f0e952899e427eeca79b635fe81a348 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:1a976a35adee9163e455d0c5aee5d9bf9cb3c6a770656ae347558f8c54977709 - name: kind value: task resolver: bundles @@ -284,7 +284,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.3@sha256:ba55ff56b8718406278d72fd5e3de88da110dd4391aa7581923b8d219a29f841 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:3793fbf59e7dadff9d1f7e7ea4cc430c69a2de620b20c7fd69d71bdd5f6c4a60 - name: kind value: task resolver: bundles @@ -306,7 +306,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:1455df3ae446fd2205e6e3457310acbf2eb9754e08f1ee9e43520fd76689c495 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:44d0df70080e082e72d2694b14130ff512e5e7f2611190161a9b016b4df9fb22 - name: kind value: task resolver: bundles @@ -326,7 +326,7 @@ spec: - name: name value: ecosystem-cert-preflight-checks - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:4bcabe436ddbef6af8f8108ee234d83e116e63e91f64a77191e1492db11bf56b + value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:d468554fb6bede46f828db315eec8d8213a71cfd5bc37e934830759db7065b65 - name: kind value: task resolver: bundles @@ -343,7 +343,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:422177f6fffa55284a30ddc4a26dca1462aee34a479529b9e2b52a5bb39606a4 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:242acc527a06a11fac9dd6524467f62f3a086c186c5f885973e5780a04d4289c - name: kind value: task resolver: bundles @@ -368,7 +368,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fbdd8b4ca9235f73d630d5a71c71d1042bbe7971eefba081dea827b6ee489c19 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:5dbe6c646c3502ddc7fbe6016b8584bed6ce3ab7028b0c405ebaabc7e6e9e64c - name: kind value: task resolver: bundles @@ -390,7 +390,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:83441b9688d6921c832e7424c446fdfd4e62ee844dfe4000b97fa2f1726ecd42 + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:f9cc253c3a07594bfb51e09c78b46598591cb353e19b16ef514f8312a8b0bada - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-main-push.yaml b/.tekton/maestro-main-push.yaml index 5a03c159..827d66ab 100644 --- a/.tekton/maestro-main-push.yaml +++ b/.tekton/maestro-main-push.yaml @@ -38,7 +38,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:1f90faefa39c2e4965793c1d8321e7d5d99a6c941276a9094a4e0d483a598fca + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:9cd4bf015b18621834f40ed02c8dccda1f7834c7d989521a8314bdb3a596e96b - name: kind value: task resolver: bundles @@ -57,7 +57,7 @@ spec: - name: name value: summary - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:535fd85afc42c856364653177edeb05cad9f6b9fa51cc893b7a29b099a6c8555 + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:51d5aaa4e13e9fb4303f667e38d07e758820040032ed9fb3ab5f6afaaffc60d8 - name: kind value: task resolver: bundles @@ -148,7 +148,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:3d8f01fa59596a998d30dc700fcf7377f09d60008337290eebaeaf604512ce2b + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:b23c7a924f303a67b3a00b32a6713ae1a4fccbc5327daa76a6edd250501ea7a3 - name: kind value: task resolver: bundles @@ -165,7 +165,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:fffe6234a4d60c63b97af86642369e4931a404f6dc8be0d12743f7651a4dc802 + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:ae1249aa49e82da5f99cc23b256172dce8f7c7951ece68ca0419240c4ecb52e2 - name: kind value: task resolver: bundles @@ -190,7 +190,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:6687b3a54a8cbfbb5c2904d447bbb3d48d5739c5e201f6ddf0c4b471a7e35e27 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:9aec3ae9f0f50a05abdc739faf4cbc82832cff16c77ac74e1d54072a882c0503 - name: kind value: task resolver: bundles @@ -229,7 +229,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:7e5f19d3aa233b9becf90d1ca01697486dc1acb1f1d6d2a0b8d1a1cc07c66249 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:102500165339bc08791775cf2c4dcae3dd4bde557a9009d44dc590ef66dde384 - name: kind value: task resolver: bundles @@ -254,7 +254,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:90dc9c66eb0123b5e5ff8a1b8c3891e91f0e952899e427eeca79b635fe81a348 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:1a976a35adee9163e455d0c5aee5d9bf9cb3c6a770656ae347558f8c54977709 - name: kind value: task resolver: bundles @@ -281,7 +281,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.3@sha256:ba55ff56b8718406278d72fd5e3de88da110dd4391aa7581923b8d219a29f841 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:3793fbf59e7dadff9d1f7e7ea4cc430c69a2de620b20c7fd69d71bdd5f6c4a60 - name: kind value: task resolver: bundles @@ -303,7 +303,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:1455df3ae446fd2205e6e3457310acbf2eb9754e08f1ee9e43520fd76689c495 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:44d0df70080e082e72d2694b14130ff512e5e7f2611190161a9b016b4df9fb22 - name: kind value: task resolver: bundles @@ -323,7 +323,7 @@ spec: - name: name value: ecosystem-cert-preflight-checks - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:4bcabe436ddbef6af8f8108ee234d83e116e63e91f64a77191e1492db11bf56b + value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:d468554fb6bede46f828db315eec8d8213a71cfd5bc37e934830759db7065b65 - name: kind value: task resolver: bundles @@ -340,7 +340,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:422177f6fffa55284a30ddc4a26dca1462aee34a479529b9e2b52a5bb39606a4 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:242acc527a06a11fac9dd6524467f62f3a086c186c5f885973e5780a04d4289c - name: kind value: task resolver: bundles @@ -365,7 +365,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fbdd8b4ca9235f73d630d5a71c71d1042bbe7971eefba081dea827b6ee489c19 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:5dbe6c646c3502ddc7fbe6016b8584bed6ce3ab7028b0c405ebaabc7e6e9e64c - name: kind value: task resolver: bundles @@ -387,7 +387,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:83441b9688d6921c832e7424c446fdfd4e62ee844dfe4000b97fa2f1726ecd42 + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:f9cc253c3a07594bfb51e09c78b46598591cb353e19b16ef514f8312a8b0bada - name: kind value: task resolver: bundles From 23af57f9f8f60a4b6d934d136c8ae2c0f41317d6 Mon Sep 17 00:00:00 2001 From: Gurney Buchanan Date: Wed, 12 Jun 2024 15:58:33 -0400 Subject: [PATCH 60/67] Migrate deprecated-base-image-check v0.3->v0.4 --- .tekton/maestro-main-pull-request.yaml | 4 ++++ .tekton/maestro-main-push.yaml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.tekton/maestro-main-pull-request.yaml b/.tekton/maestro-main-pull-request.yaml index b4adf1b3..0ea65c2e 100644 --- a/.tekton/maestro-main-pull-request.yaml +++ b/.tekton/maestro-main-pull-request.yaml @@ -277,6 +277,10 @@ spec: params: - name: BASE_IMAGES_DIGESTS value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) + - name: IMAGE_URL + value: $(tasks.build-container.results.IMAGE_URL) + - name: IMAGE_DIGEST + value: $(tasks.build-container.results.IMAGE_DIGEST) runAfter: - build-container taskRef: diff --git a/.tekton/maestro-main-push.yaml b/.tekton/maestro-main-push.yaml index 827d66ab..87d17599 100644 --- a/.tekton/maestro-main-push.yaml +++ b/.tekton/maestro-main-push.yaml @@ -274,6 +274,10 @@ spec: params: - name: BASE_IMAGES_DIGESTS value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) + - name: IMAGE_URL + value: $(tasks.build-container.results.IMAGE_URL) + - name: IMAGE_DIGEST + value: $(tasks.build-container.results.IMAGE_DIGEST) runAfter: - build-container taskRef: From bda042d9754d92ab0cbd9a96e133afe8d869f6c6 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Thu, 13 Jun 2024 10:04:39 +0800 Subject: [PATCH 61/67] use openshift-golang-builder to fix security issues Signed-off-by: clyang82 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index be014a8d..ac3da395 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22 AS builder +FROM registry.ci.openshift.org/stolostron/builder:go1.21-linux AS builder ENV SOURCE_DIR=/maestro WORKDIR $SOURCE_DIR @@ -26,4 +26,4 @@ LABEL name="maestro" \ description="maestro API" \ io.k8s.description="maestro API" \ io.k8s.display-name="maestro" \ - io.openshift.tags="maestro" \ No newline at end of file + io.openshift.tags="maestro" From da0f007448a9e7c22f84442f8a504265f137f80c Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 22:34:03 +0000 Subject: [PATCH 62/67] Update Konflux references Signed-off-by: red-hat-konflux <123456+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-main-pull-request.yaml | 16 ++++++++-------- .tekton/maestro-main-push.yaml | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.tekton/maestro-main-pull-request.yaml b/.tekton/maestro-main-pull-request.yaml index 0ea65c2e..829fc0b4 100644 --- a/.tekton/maestro-main-pull-request.yaml +++ b/.tekton/maestro-main-pull-request.yaml @@ -168,7 +168,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:ae1249aa49e82da5f99cc23b256172dce8f7c7951ece68ca0419240c4ecb52e2 + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:2be7c9c83159c5247f1f9aab8fa1a2cb29d0df66f6c5bb48a012320bdcb03c7d - name: kind value: task resolver: bundles @@ -232,7 +232,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:102500165339bc08791775cf2c4dcae3dd4bde557a9009d44dc590ef66dde384 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:021f7029d0d8a1834bc45a4cd3cc451c03d0f87a5793eb19e1902f8b00dd3d4c - name: kind value: task resolver: bundles @@ -257,7 +257,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:1a976a35adee9163e455d0c5aee5d9bf9cb3c6a770656ae347558f8c54977709 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:83ee909cb8f7d659fac380a2521fb60f30c309e5ecb91f3aad2433936e690d98 - name: kind value: task resolver: bundles @@ -288,7 +288,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:3793fbf59e7dadff9d1f7e7ea4cc430c69a2de620b20c7fd69d71bdd5f6c4a60 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:aaf998c36c66d2330cf45894f9cca52486fcdd73e030620e7107e28da247ed87 - name: kind value: task resolver: bundles @@ -310,7 +310,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:44d0df70080e082e72d2694b14130ff512e5e7f2611190161a9b016b4df9fb22 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:de7d372d90939db203072a024f1b13869dd11fac9b196e2a485bdf2a20099902 - name: kind value: task resolver: bundles @@ -347,7 +347,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:242acc527a06a11fac9dd6524467f62f3a086c186c5f885973e5780a04d4289c + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:5aa816e7d7f5e03448d658edfeb26e086aa8a2102c4c3c1113651cf5ccfe55b1 - name: kind value: task resolver: bundles @@ -372,7 +372,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:5dbe6c646c3502ddc7fbe6016b8584bed6ce3ab7028b0c405ebaabc7e6e9e64c + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fa168cd63bdebfbefc8392fbf0f5226ff6d12a8692306261a9372ddacb5ccb2c - name: kind value: task resolver: bundles @@ -394,7 +394,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:f9cc253c3a07594bfb51e09c78b46598591cb353e19b16ef514f8312a8b0bada + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:1f7ae5f2660ddfd447727cdc4a8311ce4d991e5fd8f0a23f1b13d6968d8a97e1 - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-main-push.yaml b/.tekton/maestro-main-push.yaml index 87d17599..96ce7a63 100644 --- a/.tekton/maestro-main-push.yaml +++ b/.tekton/maestro-main-push.yaml @@ -165,7 +165,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:ae1249aa49e82da5f99cc23b256172dce8f7c7951ece68ca0419240c4ecb52e2 + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:2be7c9c83159c5247f1f9aab8fa1a2cb29d0df66f6c5bb48a012320bdcb03c7d - name: kind value: task resolver: bundles @@ -229,7 +229,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:102500165339bc08791775cf2c4dcae3dd4bde557a9009d44dc590ef66dde384 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:021f7029d0d8a1834bc45a4cd3cc451c03d0f87a5793eb19e1902f8b00dd3d4c - name: kind value: task resolver: bundles @@ -254,7 +254,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:1a976a35adee9163e455d0c5aee5d9bf9cb3c6a770656ae347558f8c54977709 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:83ee909cb8f7d659fac380a2521fb60f30c309e5ecb91f3aad2433936e690d98 - name: kind value: task resolver: bundles @@ -285,7 +285,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:3793fbf59e7dadff9d1f7e7ea4cc430c69a2de620b20c7fd69d71bdd5f6c4a60 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:aaf998c36c66d2330cf45894f9cca52486fcdd73e030620e7107e28da247ed87 - name: kind value: task resolver: bundles @@ -307,7 +307,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:44d0df70080e082e72d2694b14130ff512e5e7f2611190161a9b016b4df9fb22 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:de7d372d90939db203072a024f1b13869dd11fac9b196e2a485bdf2a20099902 - name: kind value: task resolver: bundles @@ -344,7 +344,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:242acc527a06a11fac9dd6524467f62f3a086c186c5f885973e5780a04d4289c + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:5aa816e7d7f5e03448d658edfeb26e086aa8a2102c4c3c1113651cf5ccfe55b1 - name: kind value: task resolver: bundles @@ -369,7 +369,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:5dbe6c646c3502ddc7fbe6016b8584bed6ce3ab7028b0c405ebaabc7e6e9e64c + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fa168cd63bdebfbefc8392fbf0f5226ff6d12a8692306261a9372ddacb5ccb2c - name: kind value: task resolver: bundles @@ -391,7 +391,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:f9cc253c3a07594bfb51e09c78b46598591cb353e19b16ef514f8312a8b0bada + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:1f7ae5f2660ddfd447727cdc4a8311ce4d991e5fd8f0a23f1b13d6968d8a97e1 - name: kind value: task resolver: bundles From 24219c376f608fbc1b804f3902ffb05cce700dcf Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:35:47 +0000 Subject: [PATCH 63/67] Update Konflux references Signed-off-by: red-hat-konflux <123456+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-main-pull-request.yaml | 10 +++++----- .tekton/maestro-main-push.yaml | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.tekton/maestro-main-pull-request.yaml b/.tekton/maestro-main-pull-request.yaml index 829fc0b4..d224c15d 100644 --- a/.tekton/maestro-main-pull-request.yaml +++ b/.tekton/maestro-main-pull-request.yaml @@ -288,7 +288,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:aaf998c36c66d2330cf45894f9cca52486fcdd73e030620e7107e28da247ed87 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:54bbf968893823622cfbab2dd5a6e08e66ec7649673e21f5a4ebb8944e23535b - name: kind value: task resolver: bundles @@ -310,7 +310,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:de7d372d90939db203072a024f1b13869dd11fac9b196e2a485bdf2a20099902 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:4545291a178d5643d64b51424dffb2a48fe35e9918d7385707d7407522a8a7e0 - name: kind value: task resolver: bundles @@ -347,7 +347,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:5aa816e7d7f5e03448d658edfeb26e086aa8a2102c4c3c1113651cf5ccfe55b1 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:60774c68333a34579d4f5044d395ee8edf87738a7d56205bfb1b83e93dbe0a41 - name: kind value: task resolver: bundles @@ -372,7 +372,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fa168cd63bdebfbefc8392fbf0f5226ff6d12a8692306261a9372ddacb5ccb2c + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3d175c521a65a8c00f509e67e62def03ab28911f70868399619c9804b81e38a0 - name: kind value: task resolver: bundles @@ -394,7 +394,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:1f7ae5f2660ddfd447727cdc4a8311ce4d991e5fd8f0a23f1b13d6968d8a97e1 + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:d34362be8843715b1bcdaf55fcbf1be315094e0dc840562c5cec22716a37a1fe - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-main-push.yaml b/.tekton/maestro-main-push.yaml index 96ce7a63..dc3c92a5 100644 --- a/.tekton/maestro-main-push.yaml +++ b/.tekton/maestro-main-push.yaml @@ -285,7 +285,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:aaf998c36c66d2330cf45894f9cca52486fcdd73e030620e7107e28da247ed87 + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:54bbf968893823622cfbab2dd5a6e08e66ec7649673e21f5a4ebb8944e23535b - name: kind value: task resolver: bundles @@ -307,7 +307,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:de7d372d90939db203072a024f1b13869dd11fac9b196e2a485bdf2a20099902 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:4545291a178d5643d64b51424dffb2a48fe35e9918d7385707d7407522a8a7e0 - name: kind value: task resolver: bundles @@ -344,7 +344,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:5aa816e7d7f5e03448d658edfeb26e086aa8a2102c4c3c1113651cf5ccfe55b1 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:60774c68333a34579d4f5044d395ee8edf87738a7d56205bfb1b83e93dbe0a41 - name: kind value: task resolver: bundles @@ -369,7 +369,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:fa168cd63bdebfbefc8392fbf0f5226ff6d12a8692306261a9372ddacb5ccb2c + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3d175c521a65a8c00f509e67e62def03ab28911f70868399619c9804b81e38a0 - name: kind value: task resolver: bundles @@ -391,7 +391,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:1f7ae5f2660ddfd447727cdc4a8311ce4d991e5fd8f0a23f1b13d6968d8a97e1 + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:d34362be8843715b1bcdaf55fcbf1be315094e0dc840562c5cec22716a37a1fe - name: kind value: task resolver: bundles From b7de4a95e6d2d66a6b5edf346c7814f08fde4c44 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 06:15:00 +0000 Subject: [PATCH 64/67] chore(deps): update konflux references Signed-off-by: red-hat-konflux <123456+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-main-pull-request.yaml | 12 ++++++------ .tekton/maestro-main-push.yaml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.tekton/maestro-main-pull-request.yaml b/.tekton/maestro-main-pull-request.yaml index d224c15d..e54d853d 100644 --- a/.tekton/maestro-main-pull-request.yaml +++ b/.tekton/maestro-main-pull-request.yaml @@ -168,7 +168,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:2be7c9c83159c5247f1f9aab8fa1a2cb29d0df66f6c5bb48a012320bdcb03c7d + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:e1f7a275d722bc3147a65fcd772b16b54ccb6ce81c76939bc1052b2438dd2ccf - name: kind value: task resolver: bundles @@ -193,7 +193,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:9aec3ae9f0f50a05abdc739faf4cbc82832cff16c77ac74e1d54072a882c0503 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:e253dd708ec9520a0286e7abdb4fa1c2ff3f78eba28c22d32f8861fd8a5761d5 - name: kind value: task resolver: bundles @@ -232,7 +232,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:021f7029d0d8a1834bc45a4cd3cc451c03d0f87a5793eb19e1902f8b00dd3d4c + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:c30eb06767b75be1f9030525e2689fc4686f5e33fc00fc81998f4dd6783fa24f - name: kind value: task resolver: bundles @@ -257,7 +257,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:83ee909cb8f7d659fac380a2521fb60f30c309e5ecb91f3aad2433936e690d98 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:f28e922dbd3ee8384728e096042a165010b5ff826c3943ed84022789a0594d69 - name: kind value: task resolver: bundles @@ -347,7 +347,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:60774c68333a34579d4f5044d395ee8edf87738a7d56205bfb1b83e93dbe0a41 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:00508cb0c2599254085dd58045c8560933c066ce415363886d82f6acb9e6857b - name: kind value: task resolver: bundles @@ -372,7 +372,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3d175c521a65a8c00f509e67e62def03ab28911f70868399619c9804b81e38a0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:f026c963ba380d8b0c8d96a075b3b636c047d530b2d12a435966bfc97466a488 - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-main-push.yaml b/.tekton/maestro-main-push.yaml index dc3c92a5..ae4e1965 100644 --- a/.tekton/maestro-main-push.yaml +++ b/.tekton/maestro-main-push.yaml @@ -165,7 +165,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:2be7c9c83159c5247f1f9aab8fa1a2cb29d0df66f6c5bb48a012320bdcb03c7d + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:e1f7a275d722bc3147a65fcd772b16b54ccb6ce81c76939bc1052b2438dd2ccf - name: kind value: task resolver: bundles @@ -190,7 +190,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:9aec3ae9f0f50a05abdc739faf4cbc82832cff16c77ac74e1d54072a882c0503 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:e253dd708ec9520a0286e7abdb4fa1c2ff3f78eba28c22d32f8861fd8a5761d5 - name: kind value: task resolver: bundles @@ -229,7 +229,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:021f7029d0d8a1834bc45a4cd3cc451c03d0f87a5793eb19e1902f8b00dd3d4c + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:c30eb06767b75be1f9030525e2689fc4686f5e33fc00fc81998f4dd6783fa24f - name: kind value: task resolver: bundles @@ -254,7 +254,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:83ee909cb8f7d659fac380a2521fb60f30c309e5ecb91f3aad2433936e690d98 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:f28e922dbd3ee8384728e096042a165010b5ff826c3943ed84022789a0594d69 - name: kind value: task resolver: bundles @@ -344,7 +344,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:60774c68333a34579d4f5044d395ee8edf87738a7d56205bfb1b83e93dbe0a41 + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:00508cb0c2599254085dd58045c8560933c066ce415363886d82f6acb9e6857b - name: kind value: task resolver: bundles @@ -369,7 +369,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3d175c521a65a8c00f509e67e62def03ab28911f70868399619c9804b81e38a0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:f026c963ba380d8b0c8d96a075b3b636c047d530b2d12a435966bfc97466a488 - name: kind value: task resolver: bundles From 5ad74cbc1dbf7a6d9c61b540c91fab14d42e3530 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Sat, 30 Nov 2024 09:01:34 +0000 Subject: [PATCH 65/67] chore(deps): update konflux references Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .tekton/maestro-main-pull-request.yaml | 26 +++++++++++++------------- .tekton/maestro-main-push.yaml | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.tekton/maestro-main-pull-request.yaml b/.tekton/maestro-main-pull-request.yaml index e54d853d..8c8fdb33 100644 --- a/.tekton/maestro-main-pull-request.yaml +++ b/.tekton/maestro-main-pull-request.yaml @@ -41,7 +41,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:9cd4bf015b18621834f40ed02c8dccda1f7834c7d989521a8314bdb3a596e96b + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8062d5b13b5236030407cbd620a75cb7c091f43be178eeefea58d2e3dddcaa74 - name: kind value: task resolver: bundles @@ -60,7 +60,7 @@ spec: - name: name value: summary - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:51d5aaa4e13e9fb4303f667e38d07e758820040032ed9fb3ab5f6afaaffc60d8 + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:ac5b078500566c204eaa23e3aea1e2f7e003ac750514198419cb322a2eaf177a - name: kind value: task resolver: bundles @@ -151,7 +151,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:b23c7a924f303a67b3a00b32a6713ae1a4fccbc5327daa76a6edd250501ea7a3 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:07b8eb6a9533525a397c296246d3eb6ec4771b520a1bfee817ce2b7ede25c43d - name: kind value: task resolver: bundles @@ -168,7 +168,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:e1f7a275d722bc3147a65fcd772b16b54ccb6ce81c76939bc1052b2438dd2ccf + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:a3e22f57fbf8398fbe93fbeeb38e03756cd073182d6d109fe8e8cde57b561603 - name: kind value: task resolver: bundles @@ -193,7 +193,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:e253dd708ec9520a0286e7abdb4fa1c2ff3f78eba28c22d32f8861fd8a5761d5 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:566dfa9cf802e78ee26f8aae57c70cb6aa90f84dfdc929e176db4bc67d596df4 - name: kind value: task resolver: bundles @@ -232,7 +232,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:c30eb06767b75be1f9030525e2689fc4686f5e33fc00fc81998f4dd6783fa24f + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:60c99bd62dbdb0edcd8606639f653adf115433f47f0deb43e7eb3a847c10392f - name: kind value: task resolver: bundles @@ -257,7 +257,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:f28e922dbd3ee8384728e096042a165010b5ff826c3943ed84022789a0594d69 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:a964e3b02902735fe7f6a5398d9a7caddf5c0a7cc9f01792c849ca6d69d5d1a1 - name: kind value: task resolver: bundles @@ -288,7 +288,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:54bbf968893823622cfbab2dd5a6e08e66ec7649673e21f5a4ebb8944e23535b + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:566ae0df80f8447558595a996627bf0b5482dc0eaa9fbc33b8154587aed51a05 - name: kind value: task resolver: bundles @@ -310,7 +310,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:4545291a178d5643d64b51424dffb2a48fe35e9918d7385707d7407522a8a7e0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:bcc01fe4689fbb87ca335d7efea88ec800e05d8796f0828fca984349b7844b09 - name: kind value: task resolver: bundles @@ -330,7 +330,7 @@ spec: - name: name value: ecosystem-cert-preflight-checks - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:d468554fb6bede46f828db315eec8d8213a71cfd5bc37e934830759db7065b65 + value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:13a1013abebdd8dc398c41d2c72da41664086d390ea6ab9912905c1dfee08fbf - name: kind value: task resolver: bundles @@ -347,7 +347,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:00508cb0c2599254085dd58045c8560933c066ce415363886d82f6acb9e6857b + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:4ada9949fd195b50e33605ef06bb52a9bfb523d88529392972ac7a051d5bb549 - name: kind value: task resolver: bundles @@ -372,7 +372,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:f026c963ba380d8b0c8d96a075b3b636c047d530b2d12a435966bfc97466a488 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3e2891c232dc03fb5c7746fc615e1827afbd6931843e42b19cb8a6c04276ed32 - name: kind value: task resolver: bundles @@ -394,7 +394,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:d34362be8843715b1bcdaf55fcbf1be315094e0dc840562c5cec22716a37a1fe + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.2@sha256:a8f1748144a51dbb90d140ae788a95e05d65dcdd0625efceedce2f5ae755c654 - name: kind value: task resolver: bundles diff --git a/.tekton/maestro-main-push.yaml b/.tekton/maestro-main-push.yaml index ae4e1965..5b0fa07e 100644 --- a/.tekton/maestro-main-push.yaml +++ b/.tekton/maestro-main-push.yaml @@ -38,7 +38,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:9cd4bf015b18621834f40ed02c8dccda1f7834c7d989521a8314bdb3a596e96b + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8062d5b13b5236030407cbd620a75cb7c091f43be178eeefea58d2e3dddcaa74 - name: kind value: task resolver: bundles @@ -57,7 +57,7 @@ spec: - name: name value: summary - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:51d5aaa4e13e9fb4303f667e38d07e758820040032ed9fb3ab5f6afaaffc60d8 + value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:ac5b078500566c204eaa23e3aea1e2f7e003ac750514198419cb322a2eaf177a - name: kind value: task resolver: bundles @@ -148,7 +148,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:b23c7a924f303a67b3a00b32a6713ae1a4fccbc5327daa76a6edd250501ea7a3 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:07b8eb6a9533525a397c296246d3eb6ec4771b520a1bfee817ce2b7ede25c43d - name: kind value: task resolver: bundles @@ -165,7 +165,7 @@ spec: - name: name value: git-clone - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:e1f7a275d722bc3147a65fcd772b16b54ccb6ce81c76939bc1052b2438dd2ccf + value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:a3e22f57fbf8398fbe93fbeeb38e03756cd073182d6d109fe8e8cde57b561603 - name: kind value: task resolver: bundles @@ -190,7 +190,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:e253dd708ec9520a0286e7abdb4fa1c2ff3f78eba28c22d32f8861fd8a5761d5 + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:566dfa9cf802e78ee26f8aae57c70cb6aa90f84dfdc929e176db4bc67d596df4 - name: kind value: task resolver: bundles @@ -229,7 +229,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:c30eb06767b75be1f9030525e2689fc4686f5e33fc00fc81998f4dd6783fa24f + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:60c99bd62dbdb0edcd8606639f653adf115433f47f0deb43e7eb3a847c10392f - name: kind value: task resolver: bundles @@ -254,7 +254,7 @@ spec: - name: name value: source-build - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:f28e922dbd3ee8384728e096042a165010b5ff826c3943ed84022789a0594d69 + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:a964e3b02902735fe7f6a5398d9a7caddf5c0a7cc9f01792c849ca6d69d5d1a1 - name: kind value: task resolver: bundles @@ -285,7 +285,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:54bbf968893823622cfbab2dd5a6e08e66ec7649673e21f5a4ebb8944e23535b + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:566ae0df80f8447558595a996627bf0b5482dc0eaa9fbc33b8154587aed51a05 - name: kind value: task resolver: bundles @@ -307,7 +307,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:4545291a178d5643d64b51424dffb2a48fe35e9918d7385707d7407522a8a7e0 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:bcc01fe4689fbb87ca335d7efea88ec800e05d8796f0828fca984349b7844b09 - name: kind value: task resolver: bundles @@ -327,7 +327,7 @@ spec: - name: name value: ecosystem-cert-preflight-checks - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:d468554fb6bede46f828db315eec8d8213a71cfd5bc37e934830759db7065b65 + value: quay.io/redhat-appstudio-tekton-catalog/task-ecosystem-cert-preflight-checks:0.1@sha256:13a1013abebdd8dc398c41d2c72da41664086d390ea6ab9912905c1dfee08fbf - name: kind value: task resolver: bundles @@ -344,7 +344,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:00508cb0c2599254085dd58045c8560933c066ce415363886d82f6acb9e6857b + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:4ada9949fd195b50e33605ef06bb52a9bfb523d88529392972ac7a051d5bb549 - name: kind value: task resolver: bundles @@ -369,7 +369,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:f026c963ba380d8b0c8d96a075b3b636c047d530b2d12a435966bfc97466a488 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3e2891c232dc03fb5c7746fc615e1827afbd6931843e42b19cb8a6c04276ed32 - name: kind value: task resolver: bundles @@ -391,7 +391,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:d34362be8843715b1bcdaf55fcbf1be315094e0dc840562c5cec22716a37a1fe + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.2@sha256:a8f1748144a51dbb90d140ae788a95e05d65dcdd0625efceedce2f5ae755c654 - name: kind value: task resolver: bundles From fd5eb1ba2f7c055610757bce78d7985ab748a932 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Fri, 6 Dec 2024 15:48:29 +0800 Subject: [PATCH 66/67] Manually do migration Signed-off-by: clyang82 --- .tekton/maestro-main-pull-request.yaml | 26 -------------------------- .tekton/maestro-main-push.yaml | 26 -------------------------- 2 files changed, 52 deletions(-) diff --git a/.tekton/maestro-main-pull-request.yaml b/.tekton/maestro-main-pull-request.yaml index 8c8fdb33..2628c97c 100644 --- a/.tekton/maestro-main-pull-request.yaml +++ b/.tekton/maestro-main-pull-request.yaml @@ -248,8 +248,6 @@ spec: params: - name: BINARY_IMAGE value: $(params.output-image) - - name: BASE_IMAGES - value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) runAfter: - build-container taskRef: @@ -275,8 +273,6 @@ spec: workspace: workspace - name: deprecated-base-image-check params: - - name: BASE_IMAGES_DIGESTS - value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) - name: IMAGE_URL value: $(tasks.build-container.results.IMAGE_URL) - name: IMAGE_DIGEST @@ -381,28 +377,6 @@ spec: operator: in values: - "false" - - name: sbom-json-check - params: - - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - - name: IMAGE_DIGEST - value: $(tasks.build-container.results.IMAGE_DIGEST) - runAfter: - - build-container - taskRef: - params: - - name: name - value: sbom-json-check - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.2@sha256:a8f1748144a51dbb90d140ae788a95e05d65dcdd0625efceedce2f5ae755c654 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" workspaces: - name: workspace - name: git-auth diff --git a/.tekton/maestro-main-push.yaml b/.tekton/maestro-main-push.yaml index 5b0fa07e..c8a28eb4 100644 --- a/.tekton/maestro-main-push.yaml +++ b/.tekton/maestro-main-push.yaml @@ -245,8 +245,6 @@ spec: params: - name: BINARY_IMAGE value: $(params.output-image) - - name: BASE_IMAGES - value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) runAfter: - build-container taskRef: @@ -272,8 +270,6 @@ spec: workspace: workspace - name: deprecated-base-image-check params: - - name: BASE_IMAGES_DIGESTS - value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) - name: IMAGE_URL value: $(tasks.build-container.results.IMAGE_URL) - name: IMAGE_DIGEST @@ -378,28 +374,6 @@ spec: operator: in values: - "false" - - name: sbom-json-check - params: - - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - - name: IMAGE_DIGEST - value: $(tasks.build-container.results.IMAGE_DIGEST) - runAfter: - - build-container - taskRef: - params: - - name: name - value: sbom-json-check - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.2@sha256:a8f1748144a51dbb90d140ae788a95e05d65dcdd0625efceedce2f5ae755c654 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" workspaces: - name: workspace - name: git-auth From 4a5a5a179c60271c963573357880caeb7225e8aa Mon Sep 17 00:00:00 2001 From: clyang82 Date: Fri, 6 Dec 2024 16:27:18 +0800 Subject: [PATCH 67/67] fix conflicts Signed-off-by: clyang82 --- .tekton/maestro-pull-request.yaml | 379 ------------------------------ .tekton/maestro-push.yaml | 376 ----------------------------- Dockerfile | 2 +- 3 files changed, 1 insertion(+), 756 deletions(-) delete mode 100644 .tekton/maestro-pull-request.yaml delete mode 100644 .tekton/maestro-push.yaml diff --git a/.tekton/maestro-pull-request.yaml b/.tekton/maestro-pull-request.yaml deleted file mode 100644 index 7fdf2120..00000000 --- a/.tekton/maestro-pull-request.yaml +++ /dev/null @@ -1,379 +0,0 @@ -apiVersion: tekton.dev/v1 -kind: PipelineRun -metadata: - annotations: - build.appstudio.openshift.io/repo: https://github.com/openshift-online/maestro?rev={{revision}} - build.appstudio.redhat.com/commit_sha: '{{revision}}' - build.appstudio.redhat.com/pull_request_number: '{{pull_request_number}}' - build.appstudio.redhat.com/target_branch: '{{target_branch}}' - pipelinesascode.tekton.dev/max-keep-runs: "3" - pipelinesascode.tekton.dev/on-cel-expression: event == "pull_request" && target_branch == "main" - creationTimestamp: null - labels: - appstudio.openshift.io/application: maestro - appstudio.openshift.io/component: maestro - pipelines.appstudio.openshift.io/type: build - name: maestro-on-pull-request - namespace: maestro-rhtap-tenant -spec: - params: - - name: dockerfile - value: Containerfile.rhtap - - name: git-url - value: '{{source_url}}' - - name: image-expires-after - value: 5d - - name: output-image - value: quay.io/redhat-user-workloads/maestro-rhtap-tenant/maestro/maestro:on-pr-{{revision}} - - name: path-context - value: . - - name: revision - value: '{{revision}}' - pipelineSpec: - finally: - - name: show-sbom - params: - - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - taskRef: - params: - - name: name - value: show-sbom - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8062d5b13b5236030407cbd620a75cb7c091f43be178eeefea58d2e3dddcaa74 - - name: kind - value: task - resolver: bundles - - name: show-summary - params: - - name: pipelinerun-name - value: $(context.pipelineRun.name) - - name: git-url - value: $(tasks.clone-repository.results.url)?rev=$(tasks.clone-repository.results.commit) - - name: image-url - value: $(params.output-image) - - name: build-task-status - value: $(tasks.build-container.status) - taskRef: - params: - - name: name - value: summary - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:ac5b078500566c204eaa23e3aea1e2f7e003ac750514198419cb322a2eaf177a - - name: kind - value: task - resolver: bundles - params: - - description: Source Repository URL - name: git-url - type: string - - default: "" - description: Revision of the Source Repository - name: revision - type: string - - description: Fully Qualified Output Image - name: output-image - type: string - - default: . - description: Path to the source code of an application's component from where to build image. - name: path-context - type: string - - default: Dockerfile - description: Path to the Dockerfile inside the context specified by parameter path-context - name: dockerfile - type: string - - default: "false" - description: Force rebuild image - name: rebuild - type: string - - default: "false" - description: Skip checks against built image - name: skip-checks - type: string - - default: "true" - description: Skip optional checks, set false if you want to run optional checks - name: skip-optional - type: string - - default: "false" - description: Execute the build with network isolation - name: hermetic - type: string - - default: "" - description: Build dependencies to be prefetched by Cachi2 - name: prefetch-input - type: string - - default: "false" - description: Java build - name: java - type: string - - default: "" - description: Image tag expiration time, time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively. - name: image-expires-after - - default: "false" - description: Build a source image. - name: build-source-image - type: string - results: - - description: "" - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - - description: "" - name: IMAGE_DIGEST - value: $(tasks.build-container.results.IMAGE_DIGEST) - - description: "" - name: CHAINS-GIT_URL - value: $(tasks.clone-repository.results.url) - - description: "" - name: CHAINS-GIT_COMMIT - value: $(tasks.clone-repository.results.commit) - - description: "" - name: JAVA_COMMUNITY_DEPENDENCIES - value: $(tasks.build-container.results.JAVA_COMMUNITY_DEPENDENCIES) - tasks: - - name: init - params: - - name: image-url - value: $(params.output-image) - - name: rebuild - value: $(params.rebuild) - - name: skip-checks - value: $(params.skip-checks) - - name: skip-optional - value: $(params.skip-optional) - - name: pipelinerun-name - value: $(context.pipelineRun.name) - - name: pipelinerun-uid - value: $(context.pipelineRun.uid) - taskRef: - params: - - name: name - value: init - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:07b8eb6a9533525a397c296246d3eb6ec4771b520a1bfee817ce2b7ede25c43d - - name: kind - value: task - resolver: bundles - - name: clone-repository - params: - - name: url - value: $(params.git-url) - - name: revision - value: $(params.revision) - runAfter: - - init - taskRef: - params: - - name: name - value: git-clone - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:a3e22f57fbf8398fbe93fbeeb38e03756cd073182d6d109fe8e8cde57b561603 - - name: kind - value: task - resolver: bundles - when: - - input: $(tasks.init.results.build) - operator: in - values: - - "true" - workspaces: - - name: output - workspace: workspace - - name: basic-auth - workspace: git-auth - - name: prefetch-dependencies - params: - - name: input - value: $(params.prefetch-input) - runAfter: - - clone-repository - taskRef: - params: - - name: name - value: prefetch-dependencies - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:cdf98845bbed169e488daef426d1cfdde85c586655abcf89c61da6538d93f70c - - name: kind - value: task - resolver: bundles - when: - - input: $(params.hermetic) - operator: in - values: - - "true" - workspaces: - - name: source - workspace: workspace - - name: build-container - params: - - name: IMAGE - value: $(params.output-image) - - name: DOCKERFILE - value: $(params.dockerfile) - - name: CONTEXT - value: $(params.path-context) - - name: HERMETIC - value: $(params.hermetic) - - name: PREFETCH_INPUT - value: $(params.prefetch-input) - - name: IMAGE_EXPIRES_AFTER - value: $(params.image-expires-after) - - name: COMMIT_SHA - value: $(tasks.clone-repository.results.commit) - runAfter: - - prefetch-dependencies - taskRef: - params: - - name: name - value: buildah - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:570831e48df71f3578eb6f083d5fe5ee5c9affa5edbd1c648474ceef4553373e - - name: kind - value: task - resolver: bundles - when: - - input: $(tasks.init.results.build) - operator: in - values: - - "true" - workspaces: - - name: source - workspace: workspace - - name: build-source-image - params: - - name: BINARY_IMAGE - value: $(params.output-image) - runAfter: - - build-container - taskRef: - params: - - name: name - value: source-build - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:c07c3f9813e87832468fc72912c6e8ef995a442a32248cc35d77b8c0f5e516e2 - - name: kind - value: task - resolver: bundles - when: - - input: $(tasks.init.results.build) - operator: in - values: - - "true" - - input: $(params.build-source-image) - operator: in - values: - - "true" - workspaces: - - name: workspace - workspace: workspace - - name: deprecated-base-image-check - params: - - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - - name: IMAGE_DIGEST - value: $(tasks.build-container.results.IMAGE_DIGEST) - runAfter: - - build-container - taskRef: - params: - - name: name - value: deprecated-image-check - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:566ae0df80f8447558595a996627bf0b5482dc0eaa9fbc33b8154587aed51a05 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - - name: clair-scan - params: - - name: image-digest - value: $(tasks.build-container.results.IMAGE_DIGEST) - - name: image-url - value: $(tasks.build-container.results.IMAGE_URL) - runAfter: - - build-container - taskRef: - params: - - name: name - value: clair-scan - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:bcc01fe4689fbb87ca335d7efea88ec800e05d8796f0828fca984349b7844b09 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - - name: sast-snyk-check - runAfter: - - build-container - taskRef: - params: - - name: name - value: sast-snyk-check - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:4ada9949fd195b50e33605ef06bb52a9bfb523d88529392972ac7a051d5bb549 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - workspaces: - - name: workspace - workspace: workspace - params: - - name: image-digest - value: $(tasks.build-container.results.IMAGE_DIGEST) - - name: image-url - value: $(tasks.build-container.results.IMAGE_URL) - - name: clamav-scan - params: - - name: image-digest - value: $(tasks.build-container.results.IMAGE_DIGEST) - - name: image-url - value: $(tasks.build-container.results.IMAGE_URL) - runAfter: - - build-container - taskRef: - params: - - name: name - value: clamav-scan - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3e2891c232dc03fb5c7746fc615e1827afbd6931843e42b19cb8a6c04276ed32 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - workspaces: - - name: workspace - - name: git-auth - optional: true - taskRunTemplate: {} - workspaces: - - name: workspace - volumeClaimTemplate: - metadata: - creationTimestamp: null - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - status: {} - - name: git-auth - secret: - secretName: '{{ git_auth_secret }}' -status: {} diff --git a/.tekton/maestro-push.yaml b/.tekton/maestro-push.yaml deleted file mode 100644 index 21973a16..00000000 --- a/.tekton/maestro-push.yaml +++ /dev/null @@ -1,376 +0,0 @@ -apiVersion: tekton.dev/v1 -kind: PipelineRun -metadata: - annotations: - build.appstudio.openshift.io/repo: https://github.com/openshift-online/maestro?rev={{revision}} - build.appstudio.redhat.com/commit_sha: '{{revision}}' - build.appstudio.redhat.com/target_branch: '{{target_branch}}' - pipelinesascode.tekton.dev/max-keep-runs: "3" - pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch == "main" - creationTimestamp: null - labels: - appstudio.openshift.io/application: maestro - appstudio.openshift.io/component: maestro - pipelines.appstudio.openshift.io/type: build - name: maestro-on-push - namespace: maestro-rhtap-tenant -spec: - params: - - name: dockerfile - value: Containerfile.rhtap - - name: git-url - value: '{{repo_url}}' - - name: output-image - value: quay.io/redhat-user-workloads/maestro-rhtap-tenant/maestro/maestro:{{revision}} - - name: path-context - value: . - - name: revision - value: '{{revision}}' - pipelineSpec: - finally: - - name: show-sbom - params: - - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - taskRef: - params: - - name: name - value: show-sbom - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:8062d5b13b5236030407cbd620a75cb7c091f43be178eeefea58d2e3dddcaa74 - - name: kind - value: task - resolver: bundles - - name: show-summary - params: - - name: pipelinerun-name - value: $(context.pipelineRun.name) - - name: git-url - value: $(tasks.clone-repository.results.url)?rev=$(tasks.clone-repository.results.commit) - - name: image-url - value: $(params.output-image) - - name: build-task-status - value: $(tasks.build-container.status) - taskRef: - params: - - name: name - value: summary - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-summary:0.2@sha256:ac5b078500566c204eaa23e3aea1e2f7e003ac750514198419cb322a2eaf177a - - name: kind - value: task - resolver: bundles - params: - - description: Source Repository URL - name: git-url - type: string - - default: "" - description: Revision of the Source Repository - name: revision - type: string - - description: Fully Qualified Output Image - name: output-image - type: string - - default: . - description: Path to the source code of an application's component from where to build image. - name: path-context - type: string - - default: Dockerfile - description: Path to the Dockerfile inside the context specified by parameter path-context - name: dockerfile - type: string - - default: "false" - description: Force rebuild image - name: rebuild - type: string - - default: "false" - description: Skip checks against built image - name: skip-checks - type: string - - default: "true" - description: Skip optional checks, set false if you want to run optional checks - name: skip-optional - type: string - - default: "false" - description: Execute the build with network isolation - name: hermetic - type: string - - default: "" - description: Build dependencies to be prefetched by Cachi2 - name: prefetch-input - type: string - - default: "false" - description: Java build - name: java - type: string - - default: "" - description: Image tag expiration time, time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively. - name: image-expires-after - - default: "false" - description: Build a source image. - name: build-source-image - type: string - results: - - description: "" - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - - description: "" - name: IMAGE_DIGEST - value: $(tasks.build-container.results.IMAGE_DIGEST) - - description: "" - name: CHAINS-GIT_URL - value: $(tasks.clone-repository.results.url) - - description: "" - name: CHAINS-GIT_COMMIT - value: $(tasks.clone-repository.results.commit) - - description: "" - name: JAVA_COMMUNITY_DEPENDENCIES - value: $(tasks.build-container.results.JAVA_COMMUNITY_DEPENDENCIES) - tasks: - - name: init - params: - - name: image-url - value: $(params.output-image) - - name: rebuild - value: $(params.rebuild) - - name: skip-checks - value: $(params.skip-checks) - - name: skip-optional - value: $(params.skip-optional) - - name: pipelinerun-name - value: $(context.pipelineRun.name) - - name: pipelinerun-uid - value: $(context.pipelineRun.uid) - taskRef: - params: - - name: name - value: init - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:07b8eb6a9533525a397c296246d3eb6ec4771b520a1bfee817ce2b7ede25c43d - - name: kind - value: task - resolver: bundles - - name: clone-repository - params: - - name: url - value: $(params.git-url) - - name: revision - value: $(params.revision) - runAfter: - - init - taskRef: - params: - - name: name - value: git-clone - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-git-clone:0.1@sha256:a3e22f57fbf8398fbe93fbeeb38e03756cd073182d6d109fe8e8cde57b561603 - - name: kind - value: task - resolver: bundles - when: - - input: $(tasks.init.results.build) - operator: in - values: - - "true" - workspaces: - - name: output - workspace: workspace - - name: basic-auth - workspace: git-auth - - name: prefetch-dependencies - params: - - name: input - value: $(params.prefetch-input) - runAfter: - - clone-repository - taskRef: - params: - - name: name - value: prefetch-dependencies - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:cdf98845bbed169e488daef426d1cfdde85c586655abcf89c61da6538d93f70c - - name: kind - value: task - resolver: bundles - when: - - input: $(params.hermetic) - operator: in - values: - - "true" - workspaces: - - name: source - workspace: workspace - - name: build-container - params: - - name: IMAGE - value: $(params.output-image) - - name: DOCKERFILE - value: $(params.dockerfile) - - name: CONTEXT - value: $(params.path-context) - - name: HERMETIC - value: $(params.hermetic) - - name: PREFETCH_INPUT - value: $(params.prefetch-input) - - name: IMAGE_EXPIRES_AFTER - value: $(params.image-expires-after) - - name: COMMIT_SHA - value: $(tasks.clone-repository.results.commit) - runAfter: - - prefetch-dependencies - taskRef: - params: - - name: name - value: buildah - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.2@sha256:570831e48df71f3578eb6f083d5fe5ee5c9affa5edbd1c648474ceef4553373e - - name: kind - value: task - resolver: bundles - when: - - input: $(tasks.init.results.build) - operator: in - values: - - "true" - workspaces: - - name: source - workspace: workspace - - name: build-source-image - params: - - name: BINARY_IMAGE - value: $(params.output-image) - runAfter: - - build-container - taskRef: - params: - - name: name - value: source-build - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:c07c3f9813e87832468fc72912c6e8ef995a442a32248cc35d77b8c0f5e516e2 - - name: kind - value: task - resolver: bundles - when: - - input: $(tasks.init.results.build) - operator: in - values: - - "true" - - input: $(params.build-source-image) - operator: in - values: - - "true" - workspaces: - - name: workspace - workspace: workspace - - name: deprecated-base-image-check - params: - - name: IMAGE_URL - value: $(tasks.build-container.results.IMAGE_URL) - - name: IMAGE_DIGEST - value: $(tasks.build-container.results.IMAGE_DIGEST) - runAfter: - - build-container - taskRef: - params: - - name: name - value: deprecated-image-check - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.4@sha256:566ae0df80f8447558595a996627bf0b5482dc0eaa9fbc33b8154587aed51a05 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - - name: clair-scan - params: - - name: image-digest - value: $(tasks.build-container.results.IMAGE_DIGEST) - - name: image-url - value: $(tasks.build-container.results.IMAGE_URL) - runAfter: - - build-container - taskRef: - params: - - name: name - value: clair-scan - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.2@sha256:bcc01fe4689fbb87ca335d7efea88ec800e05d8796f0828fca984349b7844b09 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - - name: sast-snyk-check - runAfter: - - build-container - taskRef: - params: - - name: name - value: sast-snyk-check - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.3@sha256:4ada9949fd195b50e33605ef06bb52a9bfb523d88529392972ac7a051d5bb549 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - workspaces: - - name: workspace - workspace: workspace - params: - - name: image-digest - value: $(tasks.build-container.results.IMAGE_DIGEST) - - name: image-url - value: $(tasks.build-container.results.IMAGE_URL) - - name: clamav-scan - params: - - name: image-digest - value: $(tasks.build-container.results.IMAGE_DIGEST) - - name: image-url - value: $(tasks.build-container.results.IMAGE_URL) - runAfter: - - build-container - taskRef: - params: - - name: name - value: clamav-scan - - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:3e2891c232dc03fb5c7746fc615e1827afbd6931843e42b19cb8a6c04276ed32 - - name: kind - value: task - resolver: bundles - when: - - input: $(params.skip-checks) - operator: in - values: - - "false" - workspaces: - - name: workspace - - name: git-auth - optional: true - taskRunTemplate: {} - workspaces: - - name: workspace - volumeClaimTemplate: - metadata: - creationTimestamp: null - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - status: {} - - name: git-auth - secret: - secretName: '{{ git_auth_secret }}' -status: {} diff --git a/Dockerfile b/Dockerfile index ac3da395..cd32cb00 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM registry.ci.openshift.org/stolostron/builder:go1.21-linux AS builder +FROM registry.ci.openshift.org/stolostron/builder:go1.22-linux AS builder ENV SOURCE_DIR=/maestro WORKDIR $SOURCE_DIR

^YAn5tybi~WLCG^q}ENAky!S=|P3i?nwX zpAE`Ri#eQ*pE;TxZ5~sM8f@=9O{y>$&HH{(X1_QnLRLv0jeEp!5AX+d>cO}PvenU( zoS^t7-Kj=CQ2tB8KH5Y*JT&Usx&q=~5F1BDZQ7s{J&`VmN(oL5^%xpL#8(vtdo zf>7JWt^<7e%PGU+6X>xAF5kBxzLT|O1v{-E)NV_Gz!-(etC_W@(Ct&5SyMHmQX$SE zsCOY9aYQ7)d68euCy2zj#m#>SG0Brksz3606SNR=z{Q3O?6Klm zpyZC1jR+@*VmX;pXP9G3EWc|L9Ojs64V#9$(KF^Owp`L=7y zHx%Lfqs6btDbZMX;D;L!*}*V<^6KowQNRj4(CIiCZWiK|AhCPrL_@R+?PYme z9mSwFRkHA85h)>0`m6JWX!+Ciy?$KqZq)WuB9~*$<&l~R-C?yZA!p`x!}RA-?zer?~yA51qulPn=c z{!4z}#*C*XB9(CZmd*5y)l?w^-#KH6JAx5{n|kr?H<%81kM8R_j`cCRTa!qqcW;8C z(TnRs$(-=>rs*|B^&ldQpM z#7*Fqo)j}0FY!_^RphjLN8!}K+KEo>^c-Q5yk+!5+v6;c%xTx%nyc`mlj&U(DFMkG znTB->Lg@pharhL1(PPa=f`JG)`9x?QMoyPt>+RoTx0IP%JbT~pY$jX8&ym{|!*5L{ zqE(O&KIGsFz96;L$G;f`b&GozBYgcfP{6O=L72Qe|SK_F5kWCinl{HfmsI8b|qTwc`H*mSA-`m>GJRfZjCWb&%V9I?tZH>uxjQl8y@&ZdrslM$e$$({2%){WfuZX|V&SN# z1)`5ca|d1i=Fz>5X`CYHQM_r=4}^q(Y#Wg}pdsNx_Gs2ts~$Kcj7Vx# z=@B;~{HeT_BcN7&IB4Scg24o_&VRP+VMu)@W0dCKHG7< zG~Cz{MtG>zwDyq9G`<70VA--LZGpgTG=8<(A@oq#g%ya8O5tN_Oe^;I>~c`&eoo!f zIm!DH={_SKI3v4vIi@d8$=*e4TKMAT#ac{nHNh3$pMJET#7MB6t3B%OVLFAPV;_uM zrnwxsULssCP`4BL+Hhm#iFDI>4!)xA)SE|hzy-Im;t?b8E#IdVd-ezMMKJJO(8dadGiOM}`fLTiAC7{4)=b_8X6Jm(Q)5=rciAi1$L*<6W z48X^o0{eF@8QHc~p#`ryT8Y*=E^`NQ<)AI{(aq1^FrVRAmj^UTx7f-}>q;;c(QcEO zAHUCXO0j}e=r<{OEYl6{OKCtX4PuoIp^4`^PWxQQMx`c&$#6`q^rB9%%cT5~l;pq` z!|3M&`z5t2h|&}gjI>g-M&*5JLS9W9u>y@7G-jMrMK2gQS!@^RO3>Yz#_ z3pa_4*7$XE`$ZZRoS@s|ApWd&>Pc+fVs_@kKzz5F#QGFAA64IwW+C7#MU}mHfkRa(Q?N7b9G+sw>Y}lB zxUelUgpRqc0%#7lsn*ZwTNz=8J|q$39^JXXg7BM)kXZ&?Zn^G$MK?Y!nVH+Ul_Q$m zsD5)K2Xe29*IX8pd$YHAX-o9b!1&cD5Be<205*Yf#`}CFR z>@v-|J5a*QKQlvf5gy_fS0@MteK%%k6J#+i&mvjhR@KGHDftZE&=}Hb_)QT2U~;q( zZrin1JDC}+p@b|ubQLYB3wM1^ySvXGQ%TfJ;&2{HH!HVMuRUa{#XMh2633E1p6d>r zb^MA(pjz2XC&z{w=+H+^-MGJDc#&ib_%ZCTrqi>$C&B?0Q5_`Fy5;R6?E8^Ls=MuJ z9C%T5*Iv3WN%0~xh>sS6?IyDrJE8XxWVA&d*OiFvBG3Cn72 z`2tqm%UxLu6jr$6-8k-MkJdeKxF)FT=JZGEgbLLoWO-4w?7pHMwPHa|SGwr{`vE?@ z!0#Ze?>OY^5`}VemG9!UdQQo+p8U(So`^&wP}jgIrc}5{JwS< z)ysy%p;yGPRcDX_Va(dY9MuY+)Z6ZansThuHjuI(ifM&B+LA`7fry`_QtuImNkOvn zwmnoOn3OkN!A|J$NB3v*(XWw3Z{KK_vCQy>Iar^7KFNFiGAkv{C+Z?K?wffxZC!vn+z zq1+t5s-?;gn4U;J1u)^TGzd_*ju-L2B+YcD1F=6$_5qf;8|7rX*P{pf74&oJg4IkC zH+Au$gmn}fayGNpO7(NjRS#;Rfr0E(oe$`px@N`Ur36}b_`YhC$~V`^L15e2D^PLz?{ z)|+;5aC68`F73YmsneouH^0hL>4>wa1jyB-Ql&BGE?oSKAGgu;U+2~|-+1p_wY`VS zw|uAmZ2#-gk(#NByjCGpmbYgtUyGkhqSY`9@dkrid{4(SpMTu4W@wp44s<@8xY(J^ zhUaRkxAA$oN6Q4$t6rA0;Z)0Oi_k9d7HRt*H%ag&iKNfukhiiGNo?)aS}yH>#ICg} z$af{P_#Qb{p^rB|>2;K>u9X@l5^H1!F#9Or~S3HNb( zP#yXhiyD>a-d$*2d$?GguJIHr!jWc_4&>|37otfLD#su+?6XCkEgCJVhS5t zks!l}YEZ}j1?1(*Nw@*+rVSS-&-Vh|_@ueA*Loyz-GK~tu!41Aw&?Frrhw1`>6OrJ z_+d$U#ki&;a_t;UL|b;86k@nN!lzJ!M_D;Ad^uRks)ZXamo>AB#nnxlBJ7UC>u6P- zv#0>gU~Fza-R9Pk37L`9v$|Ms@CK=d5rjRH$t<2uLV6`&XeAoA6i7|Ayu-5_xAzAp#F;h#AHarA@`qzIdqaU1_|oT~%3>_f1T``x>*vxy+gf7#by7 zE!_k!rx!kFSI@|j96n-}WQ&^UooI)J&HI3lRuX}vVV^nRjX0vw2x z*r1@K@?d6Cr2OE6ti_9}{HBa?By>97lySdaW~GsqVl+I-MQ-F{E-g)@-^uMlYnDPO zLW}SCO$1ZaFJ1+P`{PN=CBTM|VPk~?`lus0`%b$lFE1R~ksA>ZCTr}W=}N=s25J|r zh-*H2E6V~tXD9}7q}CC$*3iU3oxOaNc2mZhh0ls1FqRviubL2k4Rsa)h&TePGY+brx9p-gkdjE$YZtZ@o@x2Gy7QqoE z=}vQJAXT-wN(+S*>5V$`cl z;)Quf6EiPcT*l{fo%5XcZcmMf4 z*)Br5Gn66pdLa3qHD}Il>(1mif`!#HLK2PHW0hV5AjjHUmDNtsVs+*UT#(t3yh`Z^ zdAID+vBPIsD4zmzv-HeomuY{ILGu?g;GC&8ZPsJa{CAd)NoR(bHKCt?6$ckf;U|jJ zw)&ZDUr6FU=@KoRx-g5BTGGfjK+C4qe-XQuS^~hktXC#z{W+gEzwXK%Wf!_D-vs>Kl-EKWO_%G>B1+PA5CpmDryx`lJvD}PQ(%jR1 zZZlKkImZ&A6jwV|*j?ToOdIkA^CE3n(LaXTP5}GX$X0z=yON@GU>N2;yf+mxsZ_*$ zB)V-+VUSq3@*U&X3H2JVO~$6kV7@j3^>UbXWgizznzo2RcCm4oF2T{as#)l z4VQn$Stq()_lV_8_sw-S(DIyMDpRQIh+UqNq_@)qdpq7j#qmNixm166Tk`mc?!HQf zI=MSDZ2rFD*Szl7(vPOQOH|kQx zY+2NJdg|Ty2X3*r`7HRJxmh%3&}f`2L&50je$4Z6%KH^~z)S4?>Lru}B(qlPiRun> zvy%?9v%S9%9BsiIFs3_PtPn&8>XfS)zIaRC{vfz4d%&R99$jX(@Cvp?TNGh6pP?JD z+83{ekFa;_Vi<-p(RPe-bzKJ&iX?1#ft1@LI}jRAM;5`Wx9jgm-*(jNJrPIAPxa*-xv!^*7zL7=bV|E;$O151iM(&)4 zijejVx5=T(TsfuLX9F*JmtI3g-{Z2KYz-WoxcM_xJqb42+)2G(Q81?zDgOWtI<}DW zNlCnr{brHsnk3!yd4}0}ni@%jrOcJDnu;3Vy!V^0Y9bi*AH;Z?u(ofZp!GI);rTF< zB;>Vna-mb6W6{M8#-rk$y0YZdqU!FPm&x7>ib(wk=0*{}Be?;?<3!Ri$9(ielUWN# zwIa|*KI;sr@SI(nW2oy88)d2aaPvNQN(S^XFD}h`6CE_f zmt?!SCrE01Hn8k3^QMD83*ooqd54PmU6&^G@OFd^EXZ>o4zz80mr~;C&5l~HrIKf` z%IAJYV2YuR+|Q5;(B5t@RHqnM<$0;`~X97)H_jeyz7cn&*e`vKJxQ}P* zD%0$O(bEdE+sMtn7q!k6&#J#!&3hQ)VL8*L-fA)TZ-N%S!n=M!+?AToF~_802xaum z`Nz6zkxHvIp93PIo!i$h>-nv4S?$LL8zUVb_pxZPsE;S_m8!oKY314`r_o%kJC;;_ z&`8K;@TsByBap4=duzvACevn@X!a85Q!XO&6`ctgY4`LA>)!3(n`h#tC%jG&KnC^V zb9Q*TdH5Awx1&e>y;>`CBM@$Q-QaX`=!h3ptX%pF_~gvM=vqa~Jtu;Ya42U7KJBs< zY>G`Y8#G$%RSCtKEpb3=qC7bnm4AU|;7N7XE-(69@~Kz#nr@&>Sj5%oCce$K?j6)+ z5i_BOJsKAvcjz&syh9ChYBpQ={6Y$L%E5UBF7H`zP{=n-V0RHf#!bUqf)5Er-*zuC zb~4ykU2a*t40Iu*RRYC_R_7~m`taet&l7>>7sx5B~^ z;MN>vs#M&sKeGGf1+KyD@-m87C$Vx!=}v+!azjq&ou!0fO`vv#@pO87xoVGD^69)5%yAYCs{^)1%GZ1d zAoC8`I$uu8eNx-eJcYfyIwik;h2o|5pulMTMfkX;xN;H1?6@GsBC|xI6K$qrI{Vb= z-j17Z!M}Di>^c2H6K`FNl?!@>v2wDr{4mvp%9E*VO$8mo742C(FPd=23^RT-$z;cE z&b>X2r6M~8XU#)3!o+DGGM9%;!{3&I`AM0G2QJe*wWq4I{b!8f#Kg{sHNtLe5mM9Y z<3!tgRl~%*2O=FKhUQ`2Md~eYgRlzrpxd8aEbbeoWLRztHmbc9MBFBbf^XE*jW!y} z1m`#B_79^)6V!EWPF~W9SX~$KDuQ6)IDs;#2Y^(M<-im3BvpU_sEh5 z;Di>N;ByZ18v@FC~!l?B3fn&$&C&a<4)%E8_3A`E=MX z42oQi>k0VCc^Mv_rN8Q4M&Er#y|7u{FZQBs+O(cw&Qv+3&~KW09u`ZbfQjYdM=Tv~ z;5yjQ!$`bF=aLR7D^fyB>rOwp{DwF64ejnAdxN5cds#o?{k05~(Xeo0hi4b+>I2zQ z4KHrz$h7Fn-@IEa-QvktOxu8kb>4iu=x^sQ!RH@A_bp&W=NC|XZSs(7^!CbFur;@6 z(Y9MSF$p}vR~*>jW{V?xpzbrRX$ili{eY2!p&i4B0U~K#)h1%aqIvrc5*jI~m;UcF zd-tXI_Fy#Es7~l}UbSLVhFhGTQdUIhMVk$-&i92qeYabvzYH zkorEjIil`*9>W7o-rjMuxqow{hLrwba~hsQ02M?V5uq7&%+TXUYovX{V8CPcDt^pf zQ6WY3kULi(^4WS4gTcF$6vD_+VVVG}TRm1#z9Z!Zezf`wu_C2dI}(!mjG-H#852Rw zW+#{6=3PUQZ7^L`p`4C*0KfW5g`a z*Jk6vG_RfZk`nUdihYnAIFGLo$!(QG6k|?*2-P1JZ-gQDo?6snj|PFd@ylxfz*zs&1$Sh0R)X;g2YxLup@fj9$?S|(nZ(0Ou49XPfz7fKWZZJ zl?jk@@Hd7452zCv9uOx!v-IF`+i9x*h8vu+UCPGlEBj(uuJHuE1=^e;6-W0w(Uqb6TrAR6)YmNegztZHgvSwENXr{gbg;Ym`IDV2rjMHhA*epJsWj8o zhNfIi-npW0h3vh@*kebsUkhqcka0V>rW4n7pdn7HZ=h@HYypSy06A_|ME4%Ofky87 ztYyw^q4ikZJHaJTxI+a9?(P=couVk@+jRH6-Tl4KxbOY{K4b8MF_1dv z?7i06YpyxxYN4^;^?6&l!TW-@0l&ZF$m{^+OVa4iOHM2BiiVG1w#le+zLvac8QvU?GSKWB0zHm|P1nqn=NTrsYg^NowQb`PR;E-QMBwqLlSsGl>s5*nmH)IG1 z9DlQ~if2oIWv~WpAnzVCL9`lHF|R;YhBTA2PxqW>>}#4{3<~LPp^>?6WL*`u)sO-B zWAO2Heqy7M-eR>fu_91VimhtXAQ9q-wfio(UY+58=n4F~7}5?(kovBM7vYiQXUdv} zX{e6pCk+D_E`B&lX|E2wW%$$HtfeCt<$Gb9jVf^8PCr5{ zX2K;r&{zD)w4|m7ui#oQ^%ED`oI`FKxy;4uyd|(+)~>4d%}czT2GYUF10SOGytfKc z=!{H?pOrNi;KgK)-gP^bUmvwXnU00Cy!fvhpP*VC%Vu8|!miGR%sNgw-dj(VbM=i$ z(2kKcsXRy`m-9-rn2L=@XX|a;OkQUl<7NA+u*1{OH^ zLcd()Dt+*-3&JN`-6K2}a0gQc+eItibuL$34zG0YIK(PsP=Ea71{AWDi!Bmo^YLaW z`Zykete?-LE|{D$ju=?d-fR)VYty}sv`%bE$JIXucxk{0w+;ln5Z>8PfD_^!$^B7R>4mvN|AK~OG>HQXSbhvGlzH^+9?Zl0i zlX?KTB;c#W_>kQh$pk0Yo!CEW(Mf>Mmupv8(CNOW2Z*+aoOeH7 zQ4Wz~3n9WZlp*a+lYaaREuF52knN1!LiU}f;&My27gZGYzwRAuf*$jsA7jG3xpr}Q zphJ{tR3IM3W_R?lKHPJPUXAZOH+$7R|KO|ic@ksD!G zX%|{g`%oB(R3wbD7@vD)OyeRtU5xt&D?L{d)lfV_n_1vsS><4bP?b1$&Y+K{p$z6S zatAb+Djq%4ZWH{uo}!G;BfSCY;1$17h?GUqS7o1IReUoWa=m$+Fn`SBaN;a6eEyz_ zg=$8H747nR9w_)-i2|!}LEtuYANBgH!|`&Ady$TdT!c`8%T`7|nM$5&8lH z!Bc5Nzxi^HoM}pr?R(F@7__|V`i7ZnuXi_bD`C0{Q-hg>kX?5K3bo#JH*w#sacgv; zq?mzBTI$s$ZS*g-qT_h^iFqo^suJIXVoOYMEPhRMzDBuOwr`1FU*Q}FDZz&Gzx{*z_xiH0@k@q*qQp(kmBa z=R)C_55>Vt4=m19BhN~mg=Ah#qqNJ6TMjs=HG1{Vme06&C7S ztE!CK=udHT?Zt-AJeaLB9<_Ep>xzU!e3@Ow1n=fK+`Oo9b0gZS?Tx%{6=lPxEZGv> z+mr1n#HB7O3raqrcBOcol2H99T2h7T&%*2BP?$%_NWFi`_lo-RO_lOJ27sZ`Yggrt z6BhR0l!-)vxdKakE($~C<~A#~hw%(?hc|6OycxCc7en39U#TdCWOvBTIIu=1>2iua zB|{=ch=tU!VaQRPc=u=BY#-a70VK*PRpGGi&MH*LFMYY{;!w+JHU8r6!z@pBumN4? zHfCtW*HY#!HQOTR`8tm>?w}5OM(^bJ$QT=(KT|25^(Y$W_6m#|xn1i1DpZ;Hm$TCK zmGhLj+t$MD^T4Y*(7lt+>$1$aBwSI0r_^HX3})oyMfkgaR}Wi}Ui2zxynWNRY=06= z<&&`|RaAVrr8^t0)YzkNfCtd*%%5`L3>}`+fx|2d{5N>&QLHC&m2^d-$rT@n*XJ{H zK?t+POq8&3h;Mo6Frg72vpL%{AzW$Kp(2Mb;um?1Yq* zal)6!)&|)d@;x*JeK(q9@-nrnD2sh=*Ma7PoZr37?R$!0gceE}K}L9R4%hva%0^~Y z+34L=NNU4QV3C@#kcu~simGp33eRX++hkEm6EI@*EQpJL=@>-!bqqh~RR?rs2pDnf zBoshT6W^06K2VFH7|)O1aFyPS(Lg`J)>bsuh*GUiv-xD4KIUVAE}5@+!_vT~6zG`I z+@vhaMc2@-VL;&|#nu*k#Vp?P^^Du+I%6K1Yq|D3js71En(uaqIM!T$P8c(TRqlaV zT`@ekIB12IjI%t|`@9nxV-QA3guiZEOQoD1MB4vTn2rIUoy*AM_2=Tx=J9mM3Lc9R zVs}cx@$>BvU~>FLdam;EC49~?nvvpC;3QywAc@y)x3j_;Bu-hu(3{`|jiVh>$JM!( zB>UBPR>i|tu)EjP;nM$%uTAud$qdgFe`Ja}l#{>_#bJ^3C2=XNexrP))A2%IGPZ)gcJ%1T2pob!g9KvX&IA5a$u=K1x1zk4gi~ zUn1k--5|14vj@+{Ej9aoz~j+IF1AyurYiU+xts+D0HEx&alv^}8)&FOl1%zF4`Z6a zoLHIjor)0!=Mv{LWr0!r|sO#n~=U8Jr39oCLqCN#~tZC(WsFu65;tLYFSiw z5Vf|geZE@#Gs?BW>=O9>wQXGkI|<$*)F!AS=nAb>qfWWT)9Z@b)O!I=AU%ttaL+-h z1eMnl!}vMCR$BrXT!2c-%6ySN1>3mW8>zK4$IpE(i_PeR=>kw2D}=yN+@ETERSp!5 z{cmN!SJIQM8@=!sT)qfm(d_O{HLFoW!}}nn;dHa$fL+5ds#w zfyc89uVVX7oND{bB^U&FMd1kioB>T_h@Q(7uX`WXFfdeIS~(XGPsJLy6s=B3bvDvy z@7D8^54DVlEDqg5T+)9r}jdLG-Tetu^j&UQ#v;!^EU2zT<)fSC97GoA8J zYv%7ZhFmT^#|xD2_P@g7AYARO?Sc>I%#*Ec6zSD1BXGrkb|QB3o~8y@k#TYCIl?MI z^`uh|nk3%DJ6*8apOxe*YhWCFZEa}mKbssTEZh$ad1H4KzI;O0^wm{8;D4oy*FRQ#44}mR zOizucOa70SF1As}9K8XnQDAMI$zln@m*g&8KZ72#QtdnI8V?{J{YP>=NiS&ii~2(f z);~R3VbM7i)oq-~lv+x%ZA8%PKayX+VnH-A>GnCT5CC8`e-DW`T5ENaLpZE-^$W<> z!gdgX8k@Y-=Xe8x5^>n>fvmmfQTyb&Y*q(|5K>Nd-Q}F&nj!&y!#D9*0q~wK7kuFh zyA&g4XqC{_+1Z}=QSXDpAHz4$qyv#>ifPTRWBQ)sEZGL)1#CHRpV`h}5ghVbJn}d# z$9^HrhR@IJB3-BOOdmkYEJkAwF3jGIblf{|xQr2JoL!4F^UyDoNn=1fgLyvEld6T? zo)Y@euO6?Mzx>AXz)dMNnZejS?BUMS(SnphJzt-s>k}(oMLsTp6^TE*02t3$W__-I z1gNQ*kY8qpPYkmczWi%=D1^s!D$yW^mQ4I*ACz)!g>KA;Zd!PrV!6+?H0D4up7EpSj~5;NK+)d z$WJx&P&PjkxugnT%Nu)!f5fDU&-sN;nOVQ0(do?IOvwSCvoOq-uu4{OyqkhQWwq|E zhD_>KyRPZ3*iO~60!j;~=a3C(459RwQhsETr56TyCa+!}mUp-s$d5tV2BP1~}-xCL~Ne_uXgAv)3b{s4tI<}1)L3ix&2OCeC9gkL@mUnc_${bun@Vk!{RXi(|=hF+x zEH8&)?b=jao&gmOg4N5hQNkQ1r5?E_1+sB=WfTtU-w!sshFQ(#g{RFhbKtW_0YYM% z^!(f3Rmd0=QWxBNocvyTBk$myR_Ql*OosCBzV8NePb;u%n^tyK9znbkrSLg#*smP2 zuXxn!@8%!z7aG}gJDg19rSM17&p1WO#j{W1D`kDpmn2kptGD8@Vp@TzS|Ch^H~xJ- za@Ga9yW4bK3iBicvH;B*;c@S}?ec*$ z8PqK&$sylTaI!DIwrFVH4gp*$p$9PZ%@?AdDJ=wUUq_{h#O)nzeSZ_gER84{YW8u0riWAnvJ_sWDpr7x- z`dEd`OhLZK)?7+9v9qzK!@F?iyt$O_|tZVcfP-wHgONj^vaZ05I6|X zZ7TEpidBz6a_m4L=Dsj-`~10JxQSeWpd58J5Ncja2a5i`kx-Pzjn`L`#06m&aq zGx+RxePgHoT*|xAx&$G~F1x&y2W@1Djh4-e#2MBq4R3sCXP5FdHuKdAvbB5ry8+`M zSAu58=l3tE%JvkGw)UDnL6jbK?;DQeFxDTx-JO)HzDewWMgXg9x355`wTkeYq+Df!Ypu}*Z2+zE@P9X)03vD8J)ooP&i2*#GKuov;XKJxmXL2o!SCe(hLC z+TBZ`jvsq!K-cHZ2Uaq(qE^W9SSatQX5IOwC=b?Woh8Z4r%0j;l7Gpdk40;B#7RXUnt%w}=Ag_~)a)T~kQSLr4Yr7Ad80qSw}HP?uDt z=F6~IzXn2|q|pP)IXh5cc!{EL^1V4c5^(?tVX#4bPk*gl6g43>>G-n1(237QNYF5X ziG$B&mmI$$vUs3@cc)zbbmNPH^$j~x94vROt&3pTFTeP~(?Ph`@zoWE$#fqOd5}jR za`wOx=pzhl1@Abq7ryv!4I`|nIM&%cX4HN&GxCTcKamnxrUYs>EC!Y|ev{dY#sU#QJ_%|gaS z@R>VYsF)@5zo=_!8 zN}EQd7TVu|ZUEV?0-~3%`1709G4^8Vsw-OuUslZ0Ujb-wDbk$9Icph%)eEJD70r4| z5dMoqRLOvX&*_+uut;Wx9Y1%_jmfdEc28)2NHU_xP}%bPSbJ5a{I00NpyQK2#V3z( za@h|n8C9$X)5RI7oK+WxPcti>leU^@akC>n@8-2t>tmS8rc!E{?eWImTtE^GOL>HAV>BT<+} zpLgGnbVRJy7M~zxy}dj4L<|*fTl5}g798V$uv4APm(FI$^F09k(XhEyx0`9Rx+|j$ zjd)Fzl16?cKjJBM009`S&1QJNgKa+-KvH-AF#+-61-#)!h1hZZ0E z8N9gxDV6buCpRDdicy7r%8q+gush!X`)p#t$^l&wybFw`71S17gzQXJaE+XhpVoV@ z4w#DN)#7AY&DMrolh@GjEbVPA`;rzGq@bR-4X!DLyllzr|K0ht$`M9OaUYea84_1S zep5KGrM&*V_Z{FiTcp%*d+A1r0ShV7pCuhx=#kT33>dWm1(``gf3$#Z zXyINt#DiaI_Z(Zi+nRDaQK$yp2Mfq-MxrE+(&0sbvqw;#}J5A95iY#!uU;`1;_o z+L|PKwIH{i(h=d?i3%$qk%5VNdm)Bw97-7~CxKoKI3t1=``6Lj`MSCxA5~4DbBm*O znr;d!^l8}~X(xs{jh;1(Et^f!+-8&CMg*a??`Ap(g8}nIT|J{sy)kjnidVSr_8<5y z0}hIyRc=K}?f&IfKWs)&32(Yft$0mi;(kgb(~HqA>lQrjVm+6_Z=BRWpTrB;$nBv#-6Vdk~MCWv(IHJzJ}C`?j!b6t;D`f8w%Z z$Fd*_XZ*U_g>`fl=!!4{(QB=J?6l*mzwyK6ywc8^(I}?O4`WGSFAfnL~sv9p!ztxxJy{M zCo2qC1`p|VU&L(j9~o)zTqtOS*K8Hlwarg|)JsO~0Ks1m{f?qivCLvc#UepHjppP7 zYo5K{(idwWe2udAF*(QIkmDlLeP!6WRW5&h$mMixw?;hrxx4;gV|5T?(UUDAdc~x9 z=h>ijx8octpVGov#}&Y((^z-$GVC8PzESaHq%2);p}x40E2kh!oQevbYsAEc_>wYg z*cOzR75rlD8lXp@ljp8s&$gHe=XDu%t$vY)Gh`ijD%YC!%yqv? z8+9ynte3fvpf>}TP!-BTR&y1G!GnM{-^+TF!sQXNxE6o(rMjVU&pCz4<@I^dy=hRE zDK8^OmmesH>5-mG&HGv8W*DwZ^KDSV0WHvRg_hHcMDOqla{a?sFFNe$Q@ow3Nt48B zuIVRtJ!0$i-P{cFZd-J9Q++=A4==8?C+GkTmFn#(fy%Je{KE4%%7kg25IZ(wJyj3I zS!24_!Hy#IRqGUE(dmzR5d}?Jjv5BEocz@MZ*KWXGo}q1y$PdSfi^^M;pqu>n|LVO zh8Bj}u6SHqOrO4=SJ9|Ub#xOFMz!cVG6-{&_%9}$8F=9Q_Bc{=&V+69?fLK zQ#RR%5f;V#@&O7O`~8KoxO-G&fAS14RjGj&8q)w(q>SiW3hdmfDD4VoEEvwg2E|Exm3!tcZk3sJGRz1a3oQDzok7k1i%m4OR zVJ8^S93z!3bo=_KsC!bc@C(^j{g%RKn#DhleJQgVFVD3AdtJg7ka_&>KUyf$Y);$0 z`$yP`q|IOhc8<-pQxXrV7M&evmF)lxTji2YRV5$f)J}}p+PI)m*H~sw?;X59!I(5q zYNLaeY#Ps~-DI?e$eCTk021As#M^?;$!WCerQXUJKpR~T?9J$GyD0x)9{=OR{2b`g zq%VN$!iq;9X(S>ua%ze$R^Q^zJvmV*Lxc&tco%O$hO4v4orrXk}~V}%}Y&!7P5>s%|~hu4Yf z`6yD{_209h6t&R#oOwn8+GFH{aHRCkoKbVq7=w|Ghlo^S)nA@YpWeJ!ViRJmPBuq@ z+ky|m@Y_RyvSE4t$tH1&r(SsH$ax*th{8*%*3#NYLIOhdid^C;K3y7&KZAo#B< z{$o-8eP<%)U@vCcw#WRRKl=AC{pWXtir|v40ioef!0NAV;3l4jh=50>7k}k{q`ALb zi(FrDNvc1EnPUIl;`!^l2yX;&xiMWr_jhj^{ULQ)HtLm9&7Vi@zq}%mTYkr2|4Ge< zKKrl8|BE|kN&}ZfxF6OBIkv$otPLNRz!ePN~@3{hMai)ZsfI_q<0M zd^!^QAFla-+HVXhAgOmnC4Tt3asIvzWQNHrqThe}S#_y`l*_)d`u1<-1&~lCSwSkP zy#B}|{C8h|?1Ug8%GU7yYi{`e^@IL*DgG3E{PnZ?-=+9_(fz+s@kg#zR7SnNynL!t zy6J{AJ0Ux5ox->3RY;v?^SM}efprRVmszM)R_)}El}vHoEpDjd9paixla``LxcrMP zDS{3TVcGuIel-Grq=d9|EYF%#F^|QJjngSpd>#2d1M%9MCiVQ?sgerL{Mn|;!djh( zN<+Fo{^Ebgh`IHsgj{K>w#wC^`Ib$p4!q> z@{bcCB9n4_uD_Ve;U=qrx7VaIbP0@n=r$4v>$8KwmgFDjNB1hFU)?;F^ToZ6aMqa_2&a4 zR7jga8(ChCE7V3b6rP>wAdfRRS$*GJ`&gzz&-xy!MjDVpx}_>LE_V)fdOZJpAbu=F zXJ^yg)|q~@7T{@f` zd3I?Fe6Fro?jwQg$XnR;Rh@y$@iXf}n@j7jxp#L9~|12*lCXN~4b^ zP21fU9DPk){~xtTxHxJz3<32*E>Tq)orG9z<&(W1jJN-<@=TEgtyCz@wj*p@QGD#6f`;VJ{AMM-qM)ghU zQYin_n9h+$xS9{S{2g!@$X!4M=$y$C9(O6J&PZ`Dci}s=hdgDSCZ}Vi*JXR&XLAWu z?oKJfpsVC2`9*N4kAJrq3{jgtKix5Xrd`Q$dTRCOu6X}=fB$z0*L8*m`=oe8m9=hN zWX0TC^JA#N4B?I2A9BCNxN`f0am>CoaRHn+H`%y z{I*Jqe`8+2Vb>MnUmr~ZnUSIJkISaYX>a~%OK5|25QQ_t{$mZOzBMratMob(O7|q(rg3~x_}Vke3lNwpFCte? zq0g>XZWF*KP3MFAw?Wxo2Bxx3*U7|a0)oenQ=7U;(2%s+B;;1pu5&JI07EM)ttK(l z8{F{=~|25JqByPZ}kdP0)Dku%LE*$AH*erAG{W$> zzJwQ=4`*!GzAze^!XW!IY&I~>a&unvLu5^dqo%ED4b?2GyYo)ZO~a-VQel!ced2O^ z&knw)>ig_)k_oy;?HSV}((;REfTrGReZWw?TWug42u(AU^CpfSjsQy@m2JQllB^y8 zu=c!mm5tG*-lAdtLTnJF`#@2{Dk&1cO;#BpT%`s+m!lX9x{f=L%63YRC)+Z%<=4(n zt2osv=lQ+fG@_uoalOBTnnexPRRd=f(B~)W-Hr~E)PVBDdcgRDCxL9r$B#V&Yi2-4 zItA23x{BSlSeB`-LsHI&6|wuPjK0RJJtWRcX9rg=iCL|H93iA})8e`Yca4b43+SFI z9af}aQ@szKPBvjs=}yoe9HQeq(oCIexIhA#uoZVO1sM?e8HEX2#NtyXJ!f+-TMQ)A z?v81noLoyX0=%AJlcO&ppD_jMmiay04_us;3MhV@n@k$`)sLVL9@j3>>MRA4@l~I$ zI)6g?tQB&V(%D?4D|nX=-<_Wdopt$ozr^q<;^yo=m0j%Z9z-guVU1H&VLHnABB*%C19p=Q~q%8SUk^%EuugM_2#eRGnB`P3;3J63%0^4!(s zKN(ROW(r_Ad9ZxzUoQYfLv)iy-e!Hh1I5p}^X{zs=QFhQQ$?d>6KpVOMIQ8SahN(= zSJ~bN7rrKW^YB{#7yVrydlb>P<+v}WcWaO~;|aX&aI0bvAk!%xW1J_=`&Sry(_os5 zrKKJl3Yl$viLK!%aA$Knl@^hs{Dv*OlvLJV33ymj+T~^&yG@qU20mBDUt?J+kzgK` zTaMe&DwoBv8rIz|8PlY>NsVfJsux2e-M?OGeE068BSNMnn8W3{(U$|vmp|R(@;JTC z<<|AEzyKy%{mC4yOP4y?6B-%pFAp3epYyM-8+qnmp<|0}@a?tvD+e*Wodti>N~X`VrC}T(K}dzDrwA$JLDLR<)NHe^=jYsf zrIf6c&X{;jpGdtC5xGYv*~j|<^P6Lz79CFRGPRQEx8)zG{*S-?y2Zr1mh@6`e^v!) z5f`5vpRD&tGe%_|V|G|iP47|xZUq_7bDXX;e|9rd*FK9;Ex-I;1r*G08iQW9ep+b{ zy=>;0Zs1XM&0b9Q-RTZA5l;3`*!LdYzmW7rlce6hpO!|y?aggPf)#%2Utjg%XuC6Y zj1B4!)o8j}6nU>pp;a;IB&0l>?)&>G$7ftVY3DTcB#Ns~Ka+O45YtPD3#q%GuG0u# z6n6y-m`&tHfSFlL;c1Iwy@~9K$%KGSXl}8YVS`D?tnQE(?N3TX&h`tVnzSLBHt6*y zf~FNu8fV+F^3V6oo@rJ~KF_sPiS0`^-kC~$-`1l=O1cTD)2emZVscf&AMDYwU9qzY z>h&C^m&*joi6IpVfjG$ptp}K$kT9-sS7@!%06{C*l@MNZ9*!pala2^lWtjKvn`wgG z-nLYfLY@p27GoSV=h87ObhlMqAE^@G@emddqnw@jkjD{_AP1(OMws*_bT!?^$TYY{ zQEv2ft7GoSq6m;o;wkyE-PheL{@uRi7F7aii{a@Hb@pL`2W#c!M3B4`( zAlq+se=w>3VDLhoI!^ZEKiTI&OL>a&GpAd=W5%FgX6wFGmQ=)(FvlqtWE>hp?g8$; zTWzX9YSY&;!n@7}K7yl|CiLSZf6j;iCel2{Y*|7K69RsTNk7vOP6B>R(M zU>7l<)JF-p?x!77?SGD9*63@>bjbSRpn|R~{6pX9wXSnJpn<;^x%M8aQ=rOI%`2V6 zg=cDW&T}JZdh8qLtaw?as9EmqJI`i>*r`f=`*kEzb$RIt{FRM|mf0@(=r9MUU$@9k zy)bIKbN`iler8#q?U~z-w)u2rGKbm3bH$htGA=L!-Wr|N7^DQ;^7-jI%(*v{lkG#j zpl|Rt04Kj{J9GzgB_Ld$poPVtl4Zi5R5d_U823u_XPMc-eTi9Jw?ni(y}GAoaQDM? z(kX%c16EzwQwg@2XpYb6(w@Sv==JI@MdbAxna3gVkG&sC-RCZCcb^S&y6n3>>2qHB z>+3xwWxC*WxPMR^4`D5QL73P3peW6YN50fGWj5~B<69yPgO6b>SVnHn<-Cq72E5sB zb~ZfD1ac6I3ixP2SHW=({}X@p%6y4OpYOG*EpIkFfuG4NG__nW_l$ZtY#ze8;KmJo z=?Pgmhhen22k@z5Ctcg=5l?0L4MB139_yW_UovIL z)zV)(Kv<7QPm%6EdqR-z83P^zc)*@RY@q1Ze8}%A#&-b&MvLA*)(&3&sx_95{RZX} zc9gDk)43f!WXO^NlH4%up<=-nU~gZ*ZH({=$Z_i&Dr*Qh$)> ztHKgGZ!lZ@T}jp1Gff0|y6*PFm=U7Z~yl(&)>3TSapk6SE!6lG3#rgLaKq`QBLen>8W zSKsv$Tak_)ky;1_v}EfCSDhy1x51=9BCg-$b;;dCks^T9k0wuvi3k`_;38xRH&D)z zr!XtNiZvLMYQIYnj3WoyKyuE^3#5EjaSs`lN7S3>umZGD=ZcVNq_}Hw^dV$qO`w4T z#bm0RoKN!>yctD&Z$aeKl0v@bcmF^LpW&|XCli6J3ⅆ7#R%#rPoA|=W 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 literal 0 HcmV?d00001 diff --git a/test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-mem-ws-avg.png b/test/performance/result/aro-hpc/resource-usage/cpu-mem/svc-mem-ws-avg.png new file mode 100644 index 0000000000000000000000000000000000000000..ee504a4fa5d96b8998981cd1b10b73193ce24521 GIT binary patch literal 97885 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