diff --git a/.golangci.yml b/.golangci.yml index 7a1cce7..0ac347d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,7 @@ --- linters-settings: dupl: - threshold: 100 + threshold: 150 exhaustive: default-signifies-exhaustive: false funlen: @@ -154,4 +154,7 @@ issues: linters: - gomnd - dupl - - goconst \ No newline at end of file + - goconst + - path: provider/gcp/.*\.go + linters: + - dupl \ No newline at end of file diff --git a/README.md b/README.md index 5e428e0..2d65e30 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,13 @@ Zop is a comprehensive tool for managing cloud infrastructure. It consists of th Run the following command to pull and start the Docker image for the zop-api: ```bash - docker run -d -p 8000:8000 --name zop-api zopdev/zop-api:v0.0.2 + docker run -d -p 8000:8000 --name zop-api zopdev/zop-api:v0.0.3 ``` #### zop-ui Run the following command to pull and start the Docker image for the zop-ui: ```bash - docker run -d -p 3000:3000 -e NEXT_PUBLIC_API_BASE_URL='http://localhost:8000' --name zop-ui zopdev/zop-ui:v0.0.2 + docker run -d -p 3000:3000 -e NEXT_PUBLIC_API_BASE_URL='http://localhost:8000' --name zop-ui zopdev/zop-ui:v0.0.3 ``` > **Note:** The environment variable `NEXT_PUBLIC_API_BASE_URL` is used by zop-ui to connect to the zop-api. Ensure that the value matches the API's running base URL. diff --git a/cloudaccounts/service/interface.go b/cloudaccounts/service/interface.go index 577ca6d..d6a39f9 100644 --- a/cloudaccounts/service/interface.go +++ b/cloudaccounts/service/interface.go @@ -12,4 +12,5 @@ type CloudAccountService interface { FetchDeploymentSpace(ctx *gofr.Context, cloudAccountID int) (interface{}, error) ListNamespaces(ctx *gofr.Context, id int, clusterName, clusterRegion string) (interface{}, error) FetchDeploymentSpaceOptions(ctx *gofr.Context, id int) ([]DeploymentSpaceOptions, error) + FetchCredentials(ctx *gofr.Context, cloudAccountID int64) (interface{}, error) } diff --git a/cloudaccounts/service/mock_interface.go b/cloudaccounts/service/mock_interface.go index c757af8..db58f2e 100644 --- a/cloudaccounts/service/mock_interface.go +++ b/cloudaccounts/service/mock_interface.go @@ -8,7 +8,6 @@ import ( reflect "reflect" store "github.com/zopdev/zop-api/cloudaccounts/store" - gomock "go.uber.org/mock/gomock" gofr "gofr.dev/pkg/gofr" ) @@ -17,6 +16,7 @@ import ( type MockCloudAccountService struct { ctrl *gomock.Controller recorder *MockCloudAccountServiceMockRecorder + isgomock struct{} } // MockCloudAccountServiceMockRecorder is the mock recorder for MockCloudAccountService. @@ -46,7 +46,7 @@ func (m *MockCloudAccountService) AddCloudAccount(ctx *gofr.Context, accounts *s } // AddCloudAccount indicates an expected call of AddCloudAccount. -func (mr *MockCloudAccountServiceMockRecorder) AddCloudAccount(ctx, accounts interface{}) *gomock.Call { +func (mr *MockCloudAccountServiceMockRecorder) AddCloudAccount(ctx, accounts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddCloudAccount", reflect.TypeOf((*MockCloudAccountService)(nil).AddCloudAccount), ctx, accounts) } @@ -61,24 +61,39 @@ func (m *MockCloudAccountService) FetchAllCloudAccounts(ctx *gofr.Context) ([]st } // FetchAllCloudAccounts indicates an expected call of FetchAllCloudAccounts. -func (mr *MockCloudAccountServiceMockRecorder) FetchAllCloudAccounts(ctx interface{}) *gomock.Call { +func (mr *MockCloudAccountServiceMockRecorder) FetchAllCloudAccounts(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchAllCloudAccounts", reflect.TypeOf((*MockCloudAccountService)(nil).FetchAllCloudAccounts), ctx) } +// FetchCredentials mocks base method. +func (m *MockCloudAccountService) FetchCredentials(ctx *gofr.Context, cloudAccountID int64) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchCredentials", ctx, cloudAccountID) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchCredentials indicates an expected call of FetchCredentials. +func (mr *MockCloudAccountServiceMockRecorder) FetchCredentials(ctx, cloudAccountID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCredentials", reflect.TypeOf((*MockCloudAccountService)(nil).FetchCredentials), ctx, cloudAccountID) +} + // FetchDeploymentSpace mocks base method. -func (m *MockCloudAccountService) FetchDeploymentSpace(ctx *gofr.Context, cloudAccountID int) (interface{}, error) { +func (m *MockCloudAccountService) FetchDeploymentSpace(ctx *gofr.Context, cloudAccountID int) (any, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Fetch", ctx, cloudAccountID) - ret0, _ := ret[0].(interface{}) + ret := m.ctrl.Call(m, "FetchDeploymentSpace", ctx, cloudAccountID) + ret0, _ := ret[0].(any) ret1, _ := ret[1].(error) return ret0, ret1 } // FetchDeploymentSpace indicates an expected call of FetchDeploymentSpace. -func (mr *MockCloudAccountServiceMockRecorder) FetchDeploymentSpace(ctx, cloudAccountID interface{}) *gomock.Call { +func (mr *MockCloudAccountServiceMockRecorder) FetchDeploymentSpace(ctx, cloudAccountID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fetch", reflect.TypeOf((*MockCloudAccountService)(nil).FetchDeploymentSpace), ctx, cloudAccountID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchDeploymentSpace", reflect.TypeOf((*MockCloudAccountService)(nil).FetchDeploymentSpace), ctx, cloudAccountID) } // FetchDeploymentSpaceOptions mocks base method. @@ -91,22 +106,22 @@ func (m *MockCloudAccountService) FetchDeploymentSpaceOptions(ctx *gofr.Context, } // FetchDeploymentSpaceOptions indicates an expected call of FetchDeploymentSpaceOptions. -func (mr *MockCloudAccountServiceMockRecorder) FetchDeploymentSpaceOptions(ctx, id interface{}) *gomock.Call { +func (mr *MockCloudAccountServiceMockRecorder) FetchDeploymentSpaceOptions(ctx, id any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchDeploymentSpaceOptions", reflect.TypeOf((*MockCloudAccountService)(nil).FetchDeploymentSpaceOptions), ctx, id) } // ListNamespaces mocks base method. -func (m *MockCloudAccountService) ListNamespaces(ctx *gofr.Context, id int, clusterName, clusterRegion string) (interface{}, error) { +func (m *MockCloudAccountService) ListNamespaces(ctx *gofr.Context, id int, clusterName, clusterRegion string) (any, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ListNamespaces", ctx, id, clusterName, clusterRegion) - ret0, _ := ret[0].(interface{}) + ret0, _ := ret[0].(any) ret1, _ := ret[1].(error) return ret0, ret1 } // ListNamespaces indicates an expected call of ListNamespaces. -func (mr *MockCloudAccountServiceMockRecorder) ListNamespaces(ctx, id, clusterName, clusterRegion interface{}) *gomock.Call { +func (mr *MockCloudAccountServiceMockRecorder) ListNamespaces(ctx, id, clusterName, clusterRegion any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListNamespaces", reflect.TypeOf((*MockCloudAccountService)(nil).ListNamespaces), ctx, id, clusterName, clusterRegion) } diff --git a/cloudaccounts/service/service.go b/cloudaccounts/service/service.go index 552816f..8b5c188 100644 --- a/cloudaccounts/service/service.go +++ b/cloudaccounts/service/service.go @@ -150,3 +150,12 @@ func (*Service) FetchDeploymentSpaceOptions(_ *gofr.Context, id int) ([]Deployme return options, nil } + +func (s *Service) FetchCredentials(ctx *gofr.Context, cloudAccountID int64) (interface{}, error) { + credentials, err := s.store.GetCredentials(ctx, cloudAccountID) + if err != nil { + return nil, err + } + + return credentials, nil +} diff --git a/deploymentspace/handler/handler.go b/deploymentspace/handler/handler.go index 5118100..56e8bf7 100644 --- a/deploymentspace/handler/handler.go +++ b/deploymentspace/handler/handler.go @@ -81,3 +81,171 @@ func validate(deploymentSpace *service.DeploymentSpace) error { return nil } + +func (h *Handler) ListServices(ctx *gofr.Context) (interface{}, error) { + id := ctx.PathParam("id") + id = strings.TrimSpace(id) + + environmentID, err := strconv.Atoi(id) + if err != nil { + ctx.Logger.Error(err, "failed to convert environment id to int") + + return nil, http.ErrorInvalidParam{Params: []string{"id"}} + } + + resp, err := h.service.GetServices(ctx, environmentID) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (h *Handler) ListDeployments(ctx *gofr.Context) (any, error) { + id := ctx.PathParam("id") + id = strings.TrimSpace(id) + + environmentID, err := strconv.Atoi(id) + if err != nil { + ctx.Logger.Error(err, "failed to convert environment id to int") + + return nil, http.ErrorInvalidParam{Params: []string{"id"}} + } + + resp, err := h.service.GetDeployments(ctx, environmentID) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (h *Handler) ListPods(ctx *gofr.Context) (any, error) { + id := ctx.PathParam("id") + id = strings.TrimSpace(id) + + environmentID, err := strconv.Atoi(id) + if err != nil { + ctx.Logger.Error(err, "failed to convert environment id to int") + + return nil, http.ErrorInvalidParam{Params: []string{"id"}} + } + + resp, err := h.service.GetPods(ctx, environmentID) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (h *Handler) ListCronJobs(ctx *gofr.Context) (any, error) { + id := ctx.PathParam("id") + id = strings.TrimSpace(id) + + environmentID, err := strconv.Atoi(id) + if err != nil { + ctx.Logger.Error(err, "failed to convert environment id to int") + + return nil, http.ErrorInvalidParam{Params: []string{"id"}} + } + + resp, err := h.service.GetCronJobs(ctx, environmentID) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (h *Handler) GetService(ctx *gofr.Context) (any, error) { + id := ctx.PathParam("id") + name := ctx.PathParam("name") + + envID, err := strconv.Atoi(id) + if err != nil { + ctx.Logger.Error(err, "failed to convert environment id to int") + + return nil, http.ErrorInvalidParam{Params: []string{"id"}} + } + + if name == "" { + return nil, http.ErrorMissingParam{Params: []string{"name"}} + } + + resp, err := h.service.GetServiceByName(ctx, envID, name) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (h *Handler) GetDeployment(ctx *gofr.Context) (any, error) { + id := ctx.PathParam("id") + name := ctx.PathParam("name") + + envID, err := strconv.Atoi(id) + if err != nil { + ctx.Logger.Error(err, "failed to convert environment id to int") + + return nil, http.ErrorInvalidParam{Params: []string{"id"}} + } + + if name == "" { + return nil, http.ErrorMissingParam{Params: []string{"name"}} + } + + resp, err := h.service.GetDeploymentByName(ctx, envID, name) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (h *Handler) GetPod(ctx *gofr.Context) (any, error) { + id := ctx.PathParam("id") + name := ctx.PathParam("name") + + envID, err := strconv.Atoi(id) + if err != nil { + ctx.Logger.Error(err, "failed to convert environment id to int") + + return nil, http.ErrorInvalidParam{Params: []string{"id"}} + } + + if name == "" { + return nil, http.ErrorMissingParam{Params: []string{"name"}} + } + + resp, err := h.service.GetPodByName(ctx, envID, name) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (h *Handler) GetCronJob(ctx *gofr.Context) (any, error) { + id := ctx.PathParam("id") + name := ctx.PathParam("name") + + envID, err := strconv.Atoi(id) + if err != nil { + ctx.Logger.Error(err, "failed to convert environment id to int") + + return nil, http.ErrorInvalidParam{Params: []string{"id"}} + } + + if name == "" { + return nil, http.ErrorMissingParam{Params: []string{"name"}} + } + + resp, err := h.service.GetCronJobByName(ctx, envID, name) + if err != nil { + return nil, err + } + + return resp, nil +} diff --git a/deploymentspace/service/interface.go b/deploymentspace/service/interface.go index 53899ec..572ab6c 100644 --- a/deploymentspace/service/interface.go +++ b/deploymentspace/service/interface.go @@ -32,4 +32,12 @@ type DeploymentSpaceService interface { // *DeploymentSpaceResp - The deployment space response object that includes the deployment space and cluster. // error - Any error encountered during the fetch operation. Fetch(ctx *gofr.Context, environmentID int) (*DeploymentSpaceResp, error) + GetServices(ctx *gofr.Context, environmentID int) (any, error) + GetDeployments(ctx *gofr.Context, environmentID int) (any, error) + GetPods(ctx *gofr.Context, environmentID int) (any, error) + GetCronJobs(ctx *gofr.Context, environmentID int) (any, error) + GetServiceByName(ctx *gofr.Context, envID int, serviceName string) (any, error) + GetDeploymentByName(ctx *gofr.Context, envID int, deploymentName string) (any, error) + GetPodByName(ctx *gofr.Context, environmentID int, deploymentName string) (any, error) + GetCronJobByName(ctx *gofr.Context, environmentID int, deploymentName string) (any, error) } diff --git a/deploymentspace/service/mock_interface.go b/deploymentspace/service/mock_interface.go index 401cd7c..d34f4e3 100644 --- a/deploymentspace/service/mock_interface.go +++ b/deploymentspace/service/mock_interface.go @@ -8,7 +8,6 @@ import ( reflect "reflect" gomock "go.uber.org/mock/gomock" - gofr "gofr.dev/pkg/gofr" ) @@ -64,3 +63,123 @@ func (mr *MockDeploymentSpaceServiceMockRecorder) Fetch(ctx, environmentID inter mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fetch", reflect.TypeOf((*MockDeploymentSpaceService)(nil).Fetch), ctx, environmentID) } + +// GetCronJobByName mocks base method. +func (m *MockDeploymentSpaceService) GetCronJobByName(ctx *gofr.Context, environmentID int, deploymentName string) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCronJobByName", ctx, environmentID, deploymentName) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCronJobByName indicates an expected call of GetCronJobByName. +func (mr *MockDeploymentSpaceServiceMockRecorder) GetCronJobByName(ctx, environmentID, deploymentName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCronJobByName", reflect.TypeOf((*MockDeploymentSpaceService)(nil).GetCronJobByName), ctx, environmentID, deploymentName) +} + +// GetCronJobs mocks base method. +func (m *MockDeploymentSpaceService) GetCronJobs(ctx *gofr.Context, environmentID int) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCronJobs", ctx, environmentID) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCronJobs indicates an expected call of GetCronJobs. +func (mr *MockDeploymentSpaceServiceMockRecorder) GetCronJobs(ctx, environmentID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCronJobs", reflect.TypeOf((*MockDeploymentSpaceService)(nil).GetCronJobs), ctx, environmentID) +} + +// GetDeploymentByName mocks base method. +func (m *MockDeploymentSpaceService) GetDeploymentByName(ctx *gofr.Context, envID int, deploymentName string) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeploymentByName", ctx, envID, deploymentName) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeploymentByName indicates an expected call of GetDeploymentByName. +func (mr *MockDeploymentSpaceServiceMockRecorder) GetDeploymentByName(ctx, envID, deploymentName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeploymentByName", reflect.TypeOf((*MockDeploymentSpaceService)(nil).GetDeploymentByName), ctx, envID, deploymentName) +} + +// GetDeployments mocks base method. +func (m *MockDeploymentSpaceService) GetDeployments(ctx *gofr.Context, environmentID int) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeployments", ctx, environmentID) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeployments indicates an expected call of GetDeployments. +func (mr *MockDeploymentSpaceServiceMockRecorder) GetDeployments(ctx, environmentID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeployments", reflect.TypeOf((*MockDeploymentSpaceService)(nil).GetDeployments), ctx, environmentID) +} + +// GetPodByName mocks base method. +func (m *MockDeploymentSpaceService) GetPodByName(ctx *gofr.Context, environmentID int, deploymentName string) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodByName", ctx, environmentID, deploymentName) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodByName indicates an expected call of GetPodByName. +func (mr *MockDeploymentSpaceServiceMockRecorder) GetPodByName(ctx, environmentID, deploymentName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodByName", reflect.TypeOf((*MockDeploymentSpaceService)(nil).GetPodByName), ctx, environmentID, deploymentName) +} + +// GetPods mocks base method. +func (m *MockDeploymentSpaceService) GetPods(ctx *gofr.Context, environmentID int) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPods", ctx, environmentID) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPods indicates an expected call of GetPods. +func (mr *MockDeploymentSpaceServiceMockRecorder) GetPods(ctx, environmentID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPods", reflect.TypeOf((*MockDeploymentSpaceService)(nil).GetPods), ctx, environmentID) +} + +// GetServiceByName mocks base method. +func (m *MockDeploymentSpaceService) GetServiceByName(ctx *gofr.Context, envID int, serviceName string) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServiceByName", ctx, envID, serviceName) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetServiceByName indicates an expected call of GetServiceByName. +func (mr *MockDeploymentSpaceServiceMockRecorder) GetServiceByName(ctx, envID, serviceName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceByName", reflect.TypeOf((*MockDeploymentSpaceService)(nil).GetServiceByName), ctx, envID, serviceName) +} + +// GetServices mocks base method. +func (m *MockDeploymentSpaceService) GetServices(ctx *gofr.Context, environmentID int) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServices", ctx, environmentID) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetServices indicates an expected call of GetServices. +func (mr *MockDeploymentSpaceServiceMockRecorder) GetServices(ctx, environmentID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServices", reflect.TypeOf((*MockDeploymentSpaceService)(nil).GetServices), ctx, environmentID) +} diff --git a/deploymentspace/service/models.go b/deploymentspace/service/models.go index 19bd6e2..c717c47 100644 --- a/deploymentspace/service/models.go +++ b/deploymentspace/service/models.go @@ -1,6 +1,9 @@ package service -import "github.com/zopdev/zop-api/deploymentspace/store" +import ( + "github.com/zopdev/zop-api/deploymentspace/store" + "github.com/zopdev/zop-api/provider" +) // DeploymentSpaceResp represents the response structure for a deployment space. // It contains the details of the deployment space and the associated cluster. @@ -61,3 +64,11 @@ type CloudAccount struct { // Credentials hold authentication information for access to the provider. Credentials interface{} `json:"credentials,omitempty"` } + +type clusterConfigs struct { + deploymentSpace *store.DeploymentSpace + cluster *provider.Cluster + cloudAccount *provider.CloudAccount + credentials interface{} + Namespace string +} diff --git a/deploymentspace/service/service.go b/deploymentspace/service/service.go index 90a7939..57d6a31 100644 --- a/deploymentspace/service/service.go +++ b/deploymentspace/service/service.go @@ -10,8 +10,12 @@ import ( "encoding/json" "errors" + "gofr.dev/pkg/gofr/http/response" + + "github.com/zopdev/zop-api/cloudaccounts/service" "github.com/zopdev/zop-api/deploymentspace" "github.com/zopdev/zop-api/deploymentspace/store" + "github.com/zopdev/zop-api/provider" clusterStore "github.com/zopdev/zop-api/deploymentspace/cluster/store" @@ -26,8 +30,10 @@ var ( // Service implements the DeploymentSpaceService interface. // It uses a combination of deployment space and cluster stores to manage deployment space operations. type Service struct { - store store.DeploymentSpaceStore - clusterService deploymentspace.DeploymentEntity + store store.DeploymentSpaceStore + clusterService deploymentspace.DeploymentEntity + cloudAccountService service.CloudAccountService + providerService provider.Provider } // New initializes a new instance of Service with the provided deployment space store and cluster service. @@ -40,8 +46,14 @@ type Service struct { // Returns: // // DeploymentSpaceService - An instance of the DeploymentSpaceService interface. -func New(str store.DeploymentSpaceStore, clusterSvc deploymentspace.DeploymentEntity) DeploymentSpaceService { - return &Service{store: str, clusterService: clusterSvc} +func New(str store.DeploymentSpaceStore, clusterSvc deploymentspace.DeploymentEntity, + caService service.CloudAccountService, providerSvc provider.Provider) DeploymentSpaceService { + return &Service{ + store: str, + clusterService: clusterSvc, + cloudAccountService: caService, + providerService: providerSvc, + } } // Add adds a new deployment space along with its associated cluster to the system. @@ -157,3 +169,233 @@ func (s *Service) Fetch(ctx *gofr.Context, environmentID int) (*DeploymentSpaceR Cluster: &cluster, }, nil } + +func (s *Service) GetServices(ctx *gofr.Context, environmentID int) (any, error) { + clusterDetails, err := s.getClusterDetails(ctx, environmentID) + if err != nil { + return nil, err + } + + services, err := s.providerService.ListServices(ctx, clusterDetails.cluster, clusterDetails.cloudAccount, + clusterDetails.credentials, clusterDetails.Namespace) + if err != nil { + return nil, err + } + + return response.Response{ + Data: services, + Metadata: struct { + EnvironmentName string `json:"environmentName"` + }{ + EnvironmentName: clusterDetails.deploymentSpace.EnvironmentName, + }, + }, nil +} + +func (s *Service) GetDeployments(ctx *gofr.Context, environmentID int) (any, error) { + clusterDetails, err := s.getClusterDetails(ctx, environmentID) + if err != nil { + return nil, err + } + + deps, err := s.providerService.ListDeployments(ctx, clusterDetails.cluster, clusterDetails.cloudAccount, + clusterDetails.credentials, clusterDetails.Namespace) + if err != nil { + return nil, err + } + + return response.Response{ + Data: deps, + Metadata: struct { + EnvironmentName string `json:"environmentName"` + }{ + EnvironmentName: clusterDetails.deploymentSpace.EnvironmentName, + }, + }, nil +} + +func (s *Service) GetPods(ctx *gofr.Context, environmentID int) (any, error) { + clusterDetails, err := s.getClusterDetails(ctx, environmentID) + if err != nil { + return nil, err + } + + pods, err := s.providerService.ListPods(ctx, clusterDetails.cluster, clusterDetails.cloudAccount, + clusterDetails.credentials, clusterDetails.Namespace) + if err != nil { + return nil, err + } + + return response.Response{ + Data: pods, + Metadata: struct { + EnvironmentName string `json:"environmentName"` + }{ + EnvironmentName: clusterDetails.deploymentSpace.EnvironmentName, + }, + }, nil +} + +func (s *Service) GetCronJobs(ctx *gofr.Context, environmentID int) (any, error) { + clusterDetails, err := s.getClusterDetails(ctx, environmentID) + if err != nil { + return nil, err + } + + cronJobs, err := s.providerService.ListCronJobs(ctx, clusterDetails.cluster, clusterDetails.cloudAccount, + clusterDetails.credentials, clusterDetails.Namespace) + if err != nil { + return nil, err + } + + return response.Response{ + Data: cronJobs, + Metadata: struct { + EnvironmentName string `json:"environmentName"` + }{ + EnvironmentName: clusterDetails.deploymentSpace.EnvironmentName, + }, + }, nil +} + +func (s *Service) GetServiceByName(ctx *gofr.Context, environmentID int, serviceName string) (any, error) { + clusterDetails, err := s.getClusterDetails(ctx, environmentID) + if err != nil { + return nil, err + } + + svc, err := s.providerService.GetService(ctx, clusterDetails.cluster, clusterDetails.cloudAccount, + clusterDetails.credentials, clusterDetails.Namespace, serviceName) + if err != nil { + return nil, err + } + + return response.Response{ + Data: svc, + Metadata: struct { + EnvironmentName string `json:"environmentName"` + }{ + EnvironmentName: clusterDetails.deploymentSpace.EnvironmentName, + }, + }, nil +} + +func (s *Service) GetDeploymentByName(ctx *gofr.Context, environmentID int, deploymentName string) (any, error) { + clusterDetails, err := s.getClusterDetails(ctx, environmentID) + if err != nil { + return nil, err + } + + deployment, err := s.providerService.GetDeployment(ctx, clusterDetails.cluster, clusterDetails.cloudAccount, + clusterDetails.credentials, clusterDetails.Namespace, deploymentName) + if err != nil { + return nil, err + } + + return response.Response{ + Data: deployment, + Metadata: struct { + EnvironmentName string `json:"environmentName"` + }{ + EnvironmentName: clusterDetails.deploymentSpace.EnvironmentName, + }, + }, nil +} + +func (s *Service) GetPodByName(ctx *gofr.Context, environmentID int, podName string) (any, error) { + clusterDetails, err := s.getClusterDetails(ctx, environmentID) + if err != nil { + return nil, err + } + + pod, err := s.providerService.GetPod(ctx, clusterDetails.cluster, clusterDetails.cloudAccount, + clusterDetails.credentials, clusterDetails.Namespace, podName) + if err != nil { + return nil, err + } + + return response.Response{ + Data: pod, + Metadata: struct { + EnvironmentName string `json:"environmentName"` + }{ + EnvironmentName: clusterDetails.deploymentSpace.EnvironmentName, + }, + }, nil +} + +func (s *Service) GetCronJobByName(ctx *gofr.Context, environmentID int, cronJobName string) (any, error) { + clusterDetails, err := s.getClusterDetails(ctx, environmentID) + if err != nil { + return nil, err + } + + cronJob, err := s.providerService.GetCronJob(ctx, clusterDetails.cluster, clusterDetails.cloudAccount, + clusterDetails.credentials, clusterDetails.Namespace, cronJobName) + if err != nil { + return nil, err + } + + return response.Response{ + Data: cronJob, + Metadata: struct { + EnvironmentName string `json:"environmentName"` + }{ + EnvironmentName: clusterDetails.deploymentSpace.EnvironmentName, + }, + }, nil +} + +func getClusterCloudAccount(cluster *store.Cluster) ( + *provider.Cluster, *provider.CloudAccount) { + cl := provider.Cluster{ + Name: cluster.Name, + Region: cluster.Region, + } + + cloudAccount := provider.CloudAccount{ + Provider: cluster.Provider, + ProviderID: cluster.ProviderID, + } + + return &cl, &cloudAccount +} + +func (s *Service) getClusterDetails(ctx *gofr.Context, environmentID int) (*clusterConfigs, error) { + deploymentSpace, err := s.store.GetByEnvironmentID(ctx, environmentID) + if err != nil { + return nil, err + } + + resp, err := s.clusterService.FetchByDeploymentSpaceID(ctx, int(deploymentSpace.ID)) + if err != nil { + return nil, err + } + + bytes, err := json.Marshal(resp) + if err != nil { + return nil, err + } + + cluster := store.Cluster{} + + err = json.Unmarshal(bytes, &cluster) + if err != nil { + return nil, err + } + + credentials, err := s.cloudAccountService.FetchCredentials(ctx, deploymentSpace.CloudAccountID) + if err != nil { + return nil, err + } + + cl, ca := getClusterCloudAccount(&cluster) + + return &clusterConfigs{ + deploymentSpace: deploymentSpace, + cluster: cl, + cloudAccount: ca, + credentials: credentials, + Namespace: cluster.Namespace.Name, + }, nil +} diff --git a/deploymentspace/service/service_test.go b/deploymentspace/service/service_test.go index 4213dfe..1e3f8f8 100644 --- a/deploymentspace/service/service_test.go +++ b/deploymentspace/service/service_test.go @@ -1,4 +1,4 @@ -package service_test +package service import ( "database/sql" @@ -11,13 +11,20 @@ import ( "gofr.dev/pkg/gofr" "gofr.dev/pkg/gofr/http" + "github.com/zopdev/zop-api/cloudaccounts/service" "github.com/zopdev/zop-api/deploymentspace" clusterStore "github.com/zopdev/zop-api/deploymentspace/cluster/store" - "github.com/zopdev/zop-api/deploymentspace/service" "github.com/zopdev/zop-api/deploymentspace/store" + "github.com/zopdev/zop-api/provider" ) -var errTest = errors.New("service error") +var ( + errTest = errors.New("service error") + errStore = errors.New("store error") + errClusterSvc = errors.New("cluster service error") + errCloudAccSvc = errors.New("cloud account service error") + errProviderSvc = errors.New("provider service error") +) //nolint:funlen // test function func TestService_AddDeploymentSpace(t *testing.T) { @@ -29,13 +36,13 @@ func TestService_AddDeploymentSpace(t *testing.T) { ctx := &gofr.Context{} - deploymentSpace := &service.DeploymentSpace{ - CloudAccount: service.CloudAccount{ + deploymentSpace := &DeploymentSpace{ + CloudAccount: CloudAccount{ ID: 1, Provider: "aws", ProviderID: "provider-123", }, - Type: service.Type{Name: "test-type"}, + Type: Type{Name: "test-type"}, DeploymentSpace: map[string]interface{}{ "key": "value", }, @@ -52,7 +59,7 @@ func TestService_AddDeploymentSpace(t *testing.T) { testCases := []struct { name string mockBehavior func() - input *service.DeploymentSpace + input *DeploymentSpace envID int expectedError error }{ @@ -130,9 +137,9 @@ func TestService_AddDeploymentSpace(t *testing.T) { { name: "invalid request body", mockBehavior: func() {}, - input: &service.DeploymentSpace{ - CloudAccount: service.CloudAccount{}, - Type: service.Type{}, + input: &DeploymentSpace{ + CloudAccount: CloudAccount{}, + Type: Type{}, DeploymentSpace: nil, // Invalid DeploymentEntity }, envID: 1, @@ -144,7 +151,7 @@ func TestService_AddDeploymentSpace(t *testing.T) { t.Run(tc.name, func(t *testing.T) { tc.mockBehavior() - svc := service.New(mockStore, mockClusterService) + svc := New(mockStore, mockClusterService, nil, nil) _, err := svc.Add(ctx, tc.input, tc.envID) if tc.expectedError != nil { @@ -227,7 +234,7 @@ func TestService_FetchDeploymentSpace(t *testing.T) { t.Run(tc.name, func(t *testing.T) { tc.mockBehavior() - svc := service.New(mockStore, mockClusterService) + svc := New(mockStore, mockClusterService, nil, nil) resp, err := svc.Fetch(ctx, tc.envID) if tc.expectedError != nil { @@ -240,3 +247,297 @@ func TestService_FetchDeploymentSpace(t *testing.T) { }) } } + +func TestGetDeploymentSpaceArgs(t *testing.T) { + testCases := []struct { + name string + ctx *gofr.Context + cluster *store.Cluster + credentials interface{} + expectedCl *provider.Cluster + expectedCa *provider.CloudAccount + expectedNs string + }{ + { + name: "valid input", + ctx: &gofr.Context{}, + cluster: &store.Cluster{ + Name: "test-cluster", + Region: "us-west-1", + Provider: "aws", + ProviderID: "provider-123", + Namespace: store.Namespace{Name: "test-namespace"}, + }, + credentials: "test-credentials", + expectedCl: &provider.Cluster{ + Name: "test-cluster", + Region: "us-west-1", + }, + expectedCa: &provider.CloudAccount{ + Provider: "aws", + ProviderID: "provider-123", + }, + expectedNs: "test-namespace", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cl, _ := getClusterCloudAccount(tc.cluster) + + require.Equal(t, tc.expectedCl, cl) + }) + } +} + +//nolint:funlen //test function +func TestService_GetServices(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockStore := store.NewMockDeploymentSpaceStore(ctrl) + mockClusterService := deploymentspace.NewMockDeploymentEntity(ctrl) + mockCloudAccountService := service.NewMockCloudAccountService(ctrl) + mockProviderService := provider.NewMockProvider(ctrl) + + ctx := &gofr.Context{} + + deploymentSpace := &store.DeploymentSpace{ + ID: 1, + CloudAccountID: 1, + EnvironmentID: 1, + Type: "test-type", + } + + cluster := store.Cluster{ + ID: 1, + DeploymentSpaceID: 1, + Name: "test-cluster", + Region: "us-west-1", + Provider: "aws", + ProviderID: "provider-123", + Namespace: store.Namespace{Name: "test-namespace"}, + } + + credentials := "test-credentials" + + testCases := []struct { + name string + mockBehavior func() + envID int + expectedError error + expectedResp any + }{ + { + name: "store layer error", + mockBehavior: func() { + mockStore.EXPECT(). + GetByEnvironmentID(ctx, 1). + Return(nil, errStore) + }, + envID: 1, + expectedError: errStore, + expectedResp: nil, + }, + { + name: "cluster service error", + mockBehavior: func() { + mockStore.EXPECT(). + GetByEnvironmentID(ctx, 1). + Return(deploymentSpace, nil) + mockClusterService.EXPECT(). + FetchByDeploymentSpaceID(ctx, 1). + Return(nil, errClusterSvc) + }, + envID: 1, + expectedError: errClusterSvc, + expectedResp: nil, + }, + { + name: "cloud account service error", + mockBehavior: func() { + mockStore.EXPECT(). + GetByEnvironmentID(ctx, 1). + Return(deploymentSpace, nil) + mockClusterService.EXPECT(). + FetchByDeploymentSpaceID(ctx, 1). + Return(cluster, nil) + mockCloudAccountService.EXPECT(). + FetchCredentials(ctx, int64(1)). + Return(nil, errCloudAccSvc) + }, + envID: 1, + expectedError: errCloudAccSvc, + expectedResp: nil, + }, + { + name: "provider service error", + mockBehavior: func() { + mockStore.EXPECT(). + GetByEnvironmentID(ctx, 1). + Return(deploymentSpace, nil) + mockClusterService.EXPECT(). + FetchByDeploymentSpaceID(ctx, 1). + Return(cluster, nil) + mockCloudAccountService.EXPECT(). + FetchCredentials(ctx, int64(1)). + Return(credentials, nil) + mockProviderService.EXPECT(). + ListServices(ctx, &provider.Cluster{ + Name: "test-cluster", + Region: "us-west-1", + }, &provider.CloudAccount{ + Provider: "aws", + ProviderID: "provider-123", + }, credentials, "test-namespace"). + Return(nil, errProviderSvc) + }, + envID: 1, + expectedError: errProviderSvc, + expectedResp: nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tc.mockBehavior() + + svc := New(mockStore, mockClusterService, mockCloudAccountService, mockProviderService) + resp, err := svc.GetServices(ctx, tc.envID) + + if tc.expectedError != nil { + require.Error(t, err) + require.Equal(t, tc.expectedError, err) + } else { + require.NoError(t, err) + require.Equal(t, tc.expectedResp, resp) + } + }) + } +} + +//nolint:funlen //test function +func TestService_GetDeployments(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockStore := store.NewMockDeploymentSpaceStore(ctrl) + mockClusterService := deploymentspace.NewMockDeploymentEntity(ctrl) + mockCloudAccountService := service.NewMockCloudAccountService(ctrl) + mockProviderService := provider.NewMockProvider(ctrl) + + ctx := &gofr.Context{} + + deploymentSpace := &store.DeploymentSpace{ + ID: 1, + CloudAccountID: 1, + EnvironmentID: 1, + Type: "test-type", + } + + cluster := store.Cluster{ + ID: 1, + DeploymentSpaceID: 1, + Name: "test-cluster", + Region: "us-west-1", + Provider: "aws", + ProviderID: "provider-123", + Namespace: store.Namespace{Name: "test-namespace"}, + } + + credentials := "test-credentials" + + testCases := []struct { + name string + mockBehavior func() + envID int + expectedError error + expectedResp any + }{ + { + name: "store layer error", + mockBehavior: func() { + mockStore.EXPECT(). + GetByEnvironmentID(ctx, 1). + Return(nil, errStore) + }, + envID: 1, + expectedError: errStore, + expectedResp: nil, + }, + { + name: "cluster service error", + mockBehavior: func() { + mockStore.EXPECT(). + GetByEnvironmentID(ctx, 1). + Return(deploymentSpace, nil) + mockClusterService.EXPECT(). + FetchByDeploymentSpaceID(ctx, 1). + Return(nil, errClusterSvc) + }, + envID: 1, + expectedError: errClusterSvc, + expectedResp: nil, + }, + { + name: "cloud account service error", + mockBehavior: func() { + mockStore.EXPECT(). + GetByEnvironmentID(ctx, 1). + Return(deploymentSpace, nil) + mockClusterService.EXPECT(). + FetchByDeploymentSpaceID(ctx, 1). + Return(cluster, nil) + mockCloudAccountService.EXPECT(). + FetchCredentials(ctx, int64(1)). + Return(nil, errCloudAccSvc) + }, + envID: 1, + expectedError: errCloudAccSvc, + expectedResp: nil, + }, + { + name: "provider service error", + mockBehavior: func() { + mockStore.EXPECT(). + GetByEnvironmentID(ctx, 1). + Return(deploymentSpace, nil) + mockClusterService.EXPECT(). + FetchByDeploymentSpaceID(ctx, 1). + Return(cluster, nil) + mockCloudAccountService.EXPECT(). + FetchCredentials(ctx, int64(1)). + Return(credentials, nil) + mockProviderService.EXPECT(). + ListDeployments(ctx, &provider.Cluster{ + Name: "test-cluster", + Region: "us-west-1", + }, &provider.CloudAccount{ + Provider: "aws", + ProviderID: "provider-123", + }, credentials, "test-namespace"). + Return(nil, errProviderSvc) + }, + envID: 1, + expectedError: errProviderSvc, + expectedResp: nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tc.mockBehavior() + + svc := New(mockStore, mockClusterService, mockCloudAccountService, mockProviderService) + resp, err := svc.GetDeployments(ctx, tc.envID) + + if tc.expectedError != nil { + require.Error(t, err) + require.Equal(t, tc.expectedError, err) + } else { + require.NoError(t, err) + require.Equal(t, tc.expectedResp, resp) + } + }) + } +} diff --git a/deploymentspace/store/models.go b/deploymentspace/store/models.go index 456cbb4..be738c5 100644 --- a/deploymentspace/store/models.go +++ b/deploymentspace/store/models.go @@ -13,6 +13,9 @@ type DeploymentSpace struct { // EnvironmentID is the ID of the environment to which the deployment space belongs. EnvironmentID int64 `json:"environmentId"` + // EnvironmentName is the name of the environment to which the deployment space belongs. + EnvironmentName string `json:"environmentName"` + // CloudAccountName is the name of the cloud account associated with the deployment space. CloudAccountName string `json:"cloudAccountName"` diff --git a/deploymentspace/store/query.go b/deploymentspace/store/query.go index 98ca520..accc4e8 100644 --- a/deploymentspace/store/query.go +++ b/deploymentspace/store/query.go @@ -2,9 +2,9 @@ package store const ( INSERTQUERY = "INSERT INTO deployment_space (cloud_account_id, environment_id, type) VALUES ( ?, ?, ?);" - GETQUERYBYENVID = `SELECT ds.id, ds.cloud_account_id, ds.environment_id, ds.type, ds.created_at, - ds.updated_at, ca.Name - FROM deployment_space ds - JOIN cloud_account ca ON ds.cloud_account_id = ca.id - WHERE ds.environment_id = ? AND ds.deleted_at IS NULL;` + GETQUERYBYENVID = `SELECT ds.id, ds.cloud_account_id, ds.environment_id, ds.type, ds.created_at, + ds.updated_at, ca.Name, ev.name as ev_name +FROM deployment_space ds + JOIN cloud_account ca JOIN environment ev ON ds.cloud_account_id = ca.id AND ds.environment_id = ev.id +WHERE ds.environment_id = ? AND ds.deleted_at IS NULL;` ) diff --git a/deploymentspace/store/store.go b/deploymentspace/store/store.go index 01c905c..82ccd1c 100644 --- a/deploymentspace/store/store.go +++ b/deploymentspace/store/store.go @@ -39,7 +39,7 @@ func (*Store) GetByEnvironmentID(ctx *gofr.Context, environmentID int) (*Deploym err := ctx.SQL.QueryRowContext(ctx, GETQUERYBYENVID, environmentID).Scan(&deploymentSpace.ID, &deploymentSpace.CloudAccountID, &deploymentSpace.EnvironmentID, &deploymentSpace.Type, - &deploymentSpace.CreatedAt, &deploymentSpace.UpdatedAt, &deploymentSpace.CloudAccountName) + &deploymentSpace.CreatedAt, &deploymentSpace.UpdatedAt, &deploymentSpace.CloudAccountName, &deploymentSpace.EnvironmentName) if err != nil { return nil, err } diff --git a/deploymentspace/store/store_test.go b/deploymentspace/store/store_test.go index c3e9d89..0037cd9 100644 --- a/deploymentspace/store/store_test.go +++ b/deploymentspace/store/store_test.go @@ -87,6 +87,7 @@ func TestGetDeploymentSpaceByEnvID(t *testing.T) { CloudAccountName: "Test Cloud Account", CreatedAt: "2023-12-11T00:00:00Z", UpdatedAt: "2023-12-11T00:00:00Z", + EnvironmentName: "hello", } testCases := []struct { @@ -102,8 +103,8 @@ func TestGetDeploymentSpaceByEnvID(t *testing.T) { expectedError: false, mockBehavior: func() { mockRow := sqlmock.NewRows([]string{"id", "cloud_account_id", "environment_id", "type", "created_at", "updated_at", - "cloud_account_name"}). - AddRow(1, 1, 1, "test-type", "2023-12-11T00:00:00Z", "2023-12-11T00:00:00Z", "Test Cloud Account") + "cloud_account_name", "ev_name"}). + AddRow(1, 1, 1, "test-type", "2023-12-11T00:00:00Z", "2023-12-11T00:00:00Z", "Test Cloud Account", "hello") mock.SQL.ExpectQuery(GETQUERYBYENVID). WithArgs(1). WillReturnRows(mockRow) diff --git a/go.mod b/go.mod index 015a562..e46d32f 100644 --- a/go.mod +++ b/go.mod @@ -3,25 +3,25 @@ module github.com/zopdev/zop-api go 1.22.8 require ( - cloud.google.com/go/container v1.41.0 + cloud.google.com/go/container v1.42.0 github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/gorilla/mux v1.8.1 github.com/stretchr/testify v1.10.0 go.uber.org/mock v0.5.0 - gofr.dev v1.28.0 + gofr.dev v1.0.3-0.20241220104220-7555317814ec golang.org/x/oauth2 v0.24.0 - google.golang.org/api v0.209.0 + google.golang.org/api v0.214.0 ) require ( - cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.10.2 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.5 // indirect - cloud.google.com/go/compute/metadata v0.5.2 // indirect - cloud.google.com/go/iam v1.2.2 // indirect - cloud.google.com/go/pubsub v1.45.1 // indirect + cloud.google.com/go v0.117.0 // indirect + cloud.google.com/go/auth v0.13.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect + cloud.google.com/go/iam v1.3.0 // indirect + cloud.google.com/go/pubsub v1.45.3 // indirect filippo.io/edwards25519 v1.1.0 // indirect - github.com/XSAM/otelsql v0.34.0 // indirect + github.com/XSAM/otelsql v0.36.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -35,28 +35,28 @@ require ( github.com/go-sql-driver/mysql v1.8.1 // 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/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect - github.com/googleapis/gax-go/v2 v2.14.0 // indirect + github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/joho/godotenv v1.5.1 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/openzipkin/zipkin-go v0.4.3 // indirect - github.com/pierrec/lz4/v4 v4.1.21 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.59.1 // indirect + github.com/prometheus/common v0.61.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0 // indirect github.com/redis/go-redis/extra/redisotel/v9 v9.7.0 // indirect @@ -64,37 +64,39 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/segmentio/kafka-go v0.4.47 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect - go.opentelemetry.io/otel v1.32.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 // indirect - go.opentelemetry.io/otel/exporters/prometheus v0.52.0 // indirect - go.opentelemetry.io/otel/exporters/zipkin v1.32.0 // indirect - go.opentelemetry.io/otel/metric v1.32.0 // indirect - go.opentelemetry.io/otel/sdk v1.32.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect - go.opentelemetry.io/otel/trace v1.32.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect + go.opentelemetry.io/otel v1.33.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.55.0 // indirect + go.opentelemetry.io/otel/exporters/zipkin v1.33.0 // indirect + go.opentelemetry.io/otel/metric v1.33.0 // indirect + go.opentelemetry.io/otel/sdk v1.33.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.33.0 // indirect + go.opentelemetry.io/otel/trace v1.33.0 // indirect + go.opentelemetry.io/proto/otlp v1.4.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.31.0 // indirect + golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect + golang.org/x/net v0.33.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect - google.golang.org/genproto v0.0.0-20241113202542-65e8d215514f // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f // indirect - google.golang.org/grpc v1.67.1 // indirect - google.golang.org/protobuf v1.35.2 // indirect + google.golang.org/genproto v0.0.0-20241219192143-6b3ec007d9bb // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect + google.golang.org/grpc v1.69.2 // indirect + google.golang.org/protobuf v1.36.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect - modernc.org/libc v1.55.3 // indirect + modernc.org/gc/v3 v3.0.0-20241213165251-3bc300f6d0c9 // indirect + modernc.org/libc v1.61.4 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect - modernc.org/sqlite v1.34.1 // indirect + modernc.org/sqlite v1.34.3 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index 109c6dc..f193970 100644 --- a/go.sum +++ b/go.sum @@ -1,29 +1,29 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.10.2 h1:oKF7rgBfSHdp/kuhXtqU/tNDr0mZqhYbEh+6SiqzkKo= -cloud.google.com/go/auth v0.10.2/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= -cloud.google.com/go/auth/oauth2adapt v0.2.5 h1:2p29+dePqsCHPP1bqDJcKj4qxRyYCcbzKpFyKGt3MTk= -cloud.google.com/go/auth/oauth2adapt v0.2.5/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= -cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= -cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= -cloud.google.com/go/container v1.41.0 h1:f20+lv3PBeQKgAL7X3VeuDzvF2iYao2AVBTsuTpPk68= -cloud.google.com/go/container v1.41.0/go.mod h1:YL6lDgCUi3frIWNIFU9qrmF7/6K1EYrtspmFTyyqJ+k= -cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= -cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= -cloud.google.com/go/kms v1.20.1 h1:og29Wv59uf2FVaZlesaiDAqHFzHaoUyHI3HYp9VUHVg= -cloud.google.com/go/kms v1.20.1/go.mod h1:LywpNiVCvzYNJWS9JUcGJSVTNSwPwi0vBAotzDqn2nc= -cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc= -cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= -cloud.google.com/go/pubsub v1.45.1 h1:ZC/UzYcrmK12THWn1P72z+Pnp2vu/zCZRXyhAfP1hJY= -cloud.google.com/go/pubsub v1.45.1/go.mod h1:3bn7fTmzZFwaUjllitv1WlsNMkqBgGUb3UdMhI54eCc= +cloud.google.com/go v0.117.0 h1:Z5TNFfQxj7WG2FgOGX1ekC5RiXrYgms6QscOm32M/4s= +cloud.google.com/go v0.117.0/go.mod h1:ZbwhVTb1DBGt2Iwb3tNO6SEK4q+cplHZmLWH+DelYYc= +cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= +cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= +cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= +cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/container v1.42.0 h1:sH9Hj9SoLeP+uKvLXc/04nWyWDiMo4Q85xfb1Nl5sAg= +cloud.google.com/go/container v1.42.0/go.mod h1:YL6lDgCUi3frIWNIFU9qrmF7/6K1EYrtspmFTyyqJ+k= +cloud.google.com/go/iam v1.3.0 h1:4Wo2qTaGKFtajbLpF6I4mywg900u3TLlHDb6mriLDPU= +cloud.google.com/go/iam v1.3.0/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= +cloud.google.com/go/kms v1.20.2 h1:NGTHOxAyhDVUGVU5KngeyGScrg2D39X76Aphe6NC7S0= +cloud.google.com/go/kms v1.20.2/go.mod h1:LywpNiVCvzYNJWS9JUcGJSVTNSwPwi0vBAotzDqn2nc= +cloud.google.com/go/longrunning v0.6.3 h1:A2q2vuyXysRcwzqDpMMLSI6mb6o39miS52UEG/Rd2ng= +cloud.google.com/go/longrunning v0.6.3/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= +cloud.google.com/go/pubsub v1.45.3 h1:prYj8EEAAAwkp6WNoGTE4ahe0DgHoyJd5Pbop931zow= +cloud.google.com/go/pubsub v1.45.3/go.mod h1:cGyloK/hXC4at7smAtxFnXprKEFTqmMXNNd9w+bd94Q= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= -github.com/XSAM/otelsql v0.34.0 h1:YdCRKy17Xn0MH717LEwqpVL/a+4nexmSCBrgoycYY6E= -github.com/XSAM/otelsql v0.34.0/go.mod h1:xaE+ybu+kJOYvtDyThbe0VoKWngvKHmNlrM1rOn8f94= +github.com/XSAM/otelsql v0.36.0 h1:SvrlOd/Hp0ttvI9Hu0FUWtISTTDNhQYwxe8WB4J5zxo= +github.com/XSAM/otelsql v0.36.0/go.mod h1:fo4M8MU+fCn/jDfu+JwTQ0n6myv4cZ+FU5VxrllIlxY= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA= @@ -73,8 +73,8 @@ github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17w github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 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/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -105,16 +105,16 @@ 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/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= -github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o= -github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= +github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= 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.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -123,8 +123,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -147,8 +147,8 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= -github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 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= @@ -159,8 +159,8 @@ github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/j github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 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.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= -github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= +github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ= +github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= 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/redis/go-redis/extra/rediscmd/v9 v9.7.0 h1:BIx9TNZH/Jsr4l1i7VVxnV0JPiwYj8qyrHyuL0fGZrk= @@ -206,32 +206,34 @@ go.einride.tech/aip v0.68.0 h1:4seM66oLzTpz50u4K1zlJyOXQ3tCzcJN7I22tKkjipw= go.einride.tech/aip v0.68.0/go.mod h1:7y9FF8VtPWqpxuAxl0KQWqaULxW4zFIesD6zF5RIHHg= 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.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0 h1:4BZHA+B1wXEQoGNHxW8mURaLhcdGwvRnmhGbm+odRbc= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0/go.mod h1:3qi2EEwMgB4xnKgPLqsDP3j9qxnHDZeHsnAxfjQqTko= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ= -go.opentelemetry.io/otel/exporters/prometheus v0.52.0 h1:kmU3H0b9ufFSi8IQCcxack+sWUblKkFbqWYs6YiACGQ= -go.opentelemetry.io/otel/exporters/prometheus v0.52.0/go.mod h1:+wsAp2+JhuGXX7YRkjlkx6hyWY3ogFPfNA4x3nyiAh0= -go.opentelemetry.io/otel/exporters/zipkin v1.32.0 h1:6O8HgLHPXtXE9QEKEWkBImL9mEKCGEl+m+OncVO53go= -go.opentelemetry.io/otel/exporters/zipkin v1.32.0/go.mod h1:+MFvorlowjy0iWnsKaNxC1kzczSxe71mw85h4p8yEvg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.30.0 h1:QJLT8Pe11jyHBHfSAgYH7kEmT24eX792jZO1bo4BXkM= -go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= -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.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0 h1:xwH3QJv6zL4u+gkPUu59NeT1Gyw9nScWT8FQpKLUJJI= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0/go.mod h1:uosvgpqTcTXtcPQORTbEkZNDQTCDOgTz1fe6aLSyqrQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= +go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA= +go.opentelemetry.io/otel/exporters/prometheus v0.55.0 h1:sSPw658Lk2NWAv74lkD3B/RSDb+xRFx46GjkrL3VUZo= +go.opentelemetry.io/otel/exporters/prometheus v0.55.0/go.mod h1:nC00vyCmQixoeaxF6KNyP42II/RHa9UdruK02qBmHvI= +go.opentelemetry.io/otel/exporters/zipkin v1.33.0 h1:aFexjEJIw5kVz6vQwnsqCG/nTV/UpsZh7MtQwGmH1eI= +go.opentelemetry.io/otel/exporters/zipkin v1.33.0/go.mod h1:aYsOzr/SZwZXJM6DJmSP/ST2P7MYxuc0R9RewkFVp9s= +go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= +go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= +go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= +go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/sdk/metric v1.33.0 h1:Gs5VK9/WUJhNXZgn8MR6ITatvAmKeIuCtNbsP3JkNqU= +go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt81MjVp3gLkQRwKf/Q= +go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= +go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= +go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= +go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -240,8 +242,10 @@ go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -gofr.dev v1.28.0 h1:bXeUtLnfZlS69+c6+y1MO2SqeXoPPGOzxE92t1yZYj8= -gofr.dev v1.28.0/go.mod h1:cQnVM+j8UFc8dM2VzNdJWU5GJMN5YWNsqPs44SsZxfY= +gofr.dev v1.0.3-0.20241220101654-c61abb2dff3b h1:Yjx22O0ZCv9rGiOsB4TvyfnfvXOjhKv9hBInG4VxP8E= +gofr.dev v1.0.3-0.20241220101654-c61abb2dff3b/go.mod h1:nDuWtp7VZgITb99R7rORsOOGSY3rc/oPuuo+pzUy9lY= +gofr.dev v1.0.3-0.20241220104220-7555317814ec h1:vG7s90Zo9uO+JUKpB7mht1DkCbUJna8P6qRmAMnlKbc= +gofr.dev v1.0.3-0.20241220104220-7555317814ec/go.mod h1:nDuWtp7VZgITb99R7rORsOOGSY3rc/oPuuo+pzUy9lY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -250,6 +254,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -258,8 +264,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -274,8 +280,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -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/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= @@ -333,34 +339,34 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY 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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.209.0 h1:Ja2OXNlyRlWCWu8o+GgI4yUn/wz9h/5ZfFbKz+dQX+w= -google.golang.org/api v0.209.0/go.mod h1:I53S168Yr/PNDNMi5yPnDc0/LGRZO6o7PoEbl/HY3CM= +google.golang.org/api v0.214.0 h1:h2Gkq07OYi6kusGOaT/9rnNljuXmqPnaig7WGPmKbwA= +google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE= 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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20241113202542-65e8d215514f h1:zDoHYmMzMacIdjNe+P2XiTmPsLawi/pCbSPfxt6lTfw= -google.golang.org/genproto v0.0.0-20241113202542-65e8d215514f/go.mod h1:Q5m6g8b5KaFFzsQFIGdJkSJDGeJiybVenoYFMMa3ohI= -google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g= -google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:C1QccEa9kUwvMgEUORqQD9S17QesQijxjZ84sO82mfo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/genproto v0.0.0-20241219192143-6b3ec007d9bb h1:JGs+s1Q6osip3cDY197L1HmkuPn8wPp9Hfy9jl+Uz+U= +google.golang.org/genproto v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:o8GgNarfULyZPNaIY8RDfXM7AZcmcKC/tbMWp/ZOFDw= +google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb h1:B7GIB7sr443wZ/EAEl7VZjmh1V6qzkt5V+RYcUYtS1U= +google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 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.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= +google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= 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= @@ -370,8 +376,8 @@ 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.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= +google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -384,18 +390,18 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= -modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= -modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= +modernc.org/cc/v4 v4.23.1 h1:WqJoPL3x4cUufQVHkXpXX7ThFJ1C4ik80i2eXEXbhD8= +modernc.org/cc/v4 v4.23.1/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.23.1 h1:N49a7JiWGWV7lkPE4yYcvjkBGZQi93/JabRYjdWmJXc= +modernc.org/ccgo/v4 v4.23.1/go.mod h1:JoIUegEIfutvoWV/BBfDFpPpfR2nc3U0jKucGcbmwDU= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= -modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= -modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= -modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= -modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/gc/v2 v2.5.0 h1:bJ9ChznK1L1mUtAQtxi0wi5AtAs5jQuw4PrPHO5pb6M= +modernc.org/gc/v2 v2.5.0/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v3 v3.0.0-20241213165251-3bc300f6d0c9 h1:ovz6yUKX71igz2yvk4NpiCL5fvdjZAI+DhuDEGx1xyU= +modernc.org/gc/v3 v3.0.0-20241213165251-3bc300f6d0c9/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.61.4 h1:wVyqEx6tlltte9lPTjq0kDAdtdM9c4JH8rU6M1ZVawA= +modernc.org/libc v1.61.4/go.mod h1:VfXVuM/Shh5XsMNrh3C6OkfL78G3loa4ZC/Ljv9k7xc= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= @@ -404,8 +410,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.34.1 h1:u3Yi6M0N8t9yKRDwhXcyp1eS5/ErhPTBggxWFuR6Hfk= -modernc.org/sqlite v1.34.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/sqlite v1.34.3 h1:494MIwJKBLd0tErBYkRar2HvEpy04Bl0ykPEm4XLhbo= +modernc.org/sqlite v1.34.3/go.mod h1:dnR723UrTtjKpoHCAMN0Q/gZ9MT4r+iRvIBb9umWFkU= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/main.go b/main.go index 34fca94..40d8e71 100644 --- a/main.go +++ b/main.go @@ -38,11 +38,11 @@ func main() { deploymentStore := deployStore.New() clusterStore := clStore.New() clusterService := clService.New(clusterStore) - deploymentService := deployService.New(deploymentStore, clusterService) + deploymentService := deployService.New(deploymentStore, clusterService, cloudAccountService, gkeSvc) + environmentStore := envStore.New() deploymentHandler := deployHandler.New(deploymentService) - environmentStore := envStore.New() environmentService := envService.New(environmentStore, deploymentService) envrionmentHandler := envHandler.New(environmentService) @@ -65,6 +65,14 @@ func main() { app.GET("/applications/{id}/environments", envrionmentHandler.List) app.POST("/environments/{id}/deploymentspace", deploymentHandler.Add) + app.GET("/environments/{id}/deploymentspace/service/{name}", deploymentHandler.GetService) + app.GET("/environments/{id}/deploymentspace/service", deploymentHandler.ListServices) + app.GET("/environments/{id}/deploymentspace/deployment/{name}", deploymentHandler.GetDeployment) + app.GET("/environments/{id}/deploymentspace/deployment", deploymentHandler.ListDeployments) + app.GET("/environments/{id}/deploymentspace/pod/{name}", deploymentHandler.GetPod) + app.GET("/environments/{id}/deploymentspace/pod", deploymentHandler.ListPods) + app.GET("/environments/{id}/deploymentspace/cronjob/{name}", deploymentHandler.GetCronJob) + app.GET("/environments/{id}/deploymentspace/cronjob", deploymentHandler.ListCronJobs) app.Run() } diff --git a/provider/cronjobsmodels.go b/provider/cronjobsmodels.go new file mode 100644 index 0000000..5cb92a0 --- /dev/null +++ b/provider/cronjobsmodels.go @@ -0,0 +1,58 @@ +package provider + +type CronJobs struct { + CronJobs []CronJobData `json:"cronjobs"` + Metadata *Metadata `json:"metadata"` +} + +type CronJobData struct { + Metadata CronJobMetadata `json:"metadata"` + Spec CronJobSpec `json:"spec"` + Status CronJobStatus `json:"status"` +} + +type CronJobMetadata struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + UID string `json:"uid"` + ResourceVersion string `json:"resourceVersion"` + CreationTimestamp string `json:"creationTimestamp"` + Labels map[string]string `json:"labels"` + Annotations map[string]string `json:"annotations"` +} + +type CronJobSpec struct { + Schedule string `json:"schedule"` + ConcurrencyPolicy string `json:"concurrencyPolicy"` + StartingDeadlineSeconds *int64 `json:"startingDeadlineSeconds"` + Suspend *bool `json:"suspend"` + JobTemplate JobTemplateSpec `json:"jobTemplate"` + SuccessfulJobsHistoryLimit *int32 `json:"successfulJobsHistoryLimit"` + FailedJobsHistoryLimit *int32 `json:"failedJobsHistoryLimit"` +} + +type JobTemplateSpec struct { + Metadata map[string]string `json:"metadata"` + Spec JobSpec `json:"spec"` +} + +type JobSpec struct { + Template PodTemplateSpec `json:"template"` +} + +type PodTemplateSpec struct { + Metadata map[string]any `json:"metadata"` + Spec PodSpec `json:"spec"` +} + +type CronJobStatus struct { + Active []ObjectReference `json:"active"` + LastScheduleTime string `json:"lastScheduleTime"` +} + +type ObjectReference struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Name string `json:"name"` + Namespace string `json:"namespace"` +} diff --git a/provider/deploymentmodels.go b/provider/deploymentmodels.go new file mode 100644 index 0000000..910124b --- /dev/null +++ b/provider/deploymentmodels.go @@ -0,0 +1,157 @@ +package provider + +type Deployments struct { + Deployments []DeploymentData `json:"deployments"` + Metadata *Metadata `json:"metadata"` +} + +type DeploymentData struct { + Metadata ItemMetadata `json:"metadata"` + Spec ItemSpec `json:"spec"` + Status DepStatus `json:"status"` +} + +type ItemMetadata struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + UID string `json:"uid"` + ResourceVersion string `json:"resourceVersion"` + Generation int64 `json:"generation"` + CreationTimestamp string `json:"creationTimestamp"` + Labels map[string]string `json:"labels"` + Annotations map[string]string `json:"annotations"` + ManagedFields []ManagedField `json:"managedFields"` +} + +type ManagedField struct { + Manager string `json:"manager"` + Operation string `json:"operation"` + APIVersion string `json:"apiVersion"` + Time string `json:"time"` + FieldsType string `json:"fieldsType"` + Subresource *string `json:"subresource,omitempty"` +} + +type ItemSpec struct { + Replicas int64 `json:"replicas"` + Selector Selector `json:"selector"` + Template Template `json:"template"` + Strategy Strategy `json:"strategy"` + RevisionHistoryLimit int64 `json:"revisionHistoryLimit"` + ProgressDeadlineSeconds int64 `json:"progressDeadlineSeconds"` +} + +type Selector struct { + MatchLabels MatchLabelsClass `json:"matchLabels"` +} + +type MatchLabelsClass struct { + AppKubernetesIoInstance string `json:"app.kubernetes.io/instance"` + AppKubernetesIoName string `json:"app.kubernetes.io/name"` +} + +type Strategy struct { + Type string `json:"type"` + RollingUpdate RollingUpdate `json:"rollingUpdate"` +} + +type RollingUpdate struct { + MaxUnavailable any `json:"maxUnavailable"` + MaxSurge any `json:"maxSurge"` +} + +type Template struct { + Metadata TemplateMetadata `json:"metadata"` + Spec TemplateSpec `json:"spec"` +} + +type TemplateMetadata struct { + CreationTimestamp interface{} `json:"creationTimestamp"` + Labels MatchLabelsClass `json:"labels"` +} + +type TemplateSpec struct { + Containers []Container `json:"containers"` + RestartPolicy string `json:"restartPolicy"` + TerminationGracePeriodSeconds int64 `json:"terminationGracePeriodSeconds"` + DNSPolicy string `json:"dnsPolicy"` + ServiceAccountName string `json:"serviceAccountName"` + ServiceAccount string `json:"serviceAccount"` + SecurityContext SecurityContext `json:"securityContext"` + SchedulerName string `json:"schedulerName"` +} + +type Container struct { + Name string `json:"name"` + Image string `json:"image"` + Ports []DepPorts `json:"ports"` + Env []Env `json:"env"` + Resources Resources `json:"resources"` + LivenessProbe Probe `json:"livenessProbe"` + ReadinessProbe Probe `json:"readinessProbe"` + StartupProbe *Probe `json:"startupProbe,omitempty"` + TerminationMessagePath string `json:"terminationMessagePath"` + TerminationMessagePolicy string `json:"terminationMessagePolicy"` + ImagePullPolicy string `json:"imagePullPolicy"` + Status string `json:"status"` + Command any `json:"command"` + Args any `json:"args"` + VolumeMounts any `json:"volumeMounts"` +} + +type Env struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type Probe struct { + HTTPGet HTTPGet `json:"httpGet"` + InitialDelaySeconds int64 `json:"initialDelaySeconds"` + TimeoutSeconds int64 `json:"timeoutSeconds"` + PeriodSeconds int64 `json:"periodSeconds"` + SuccessThreshold int64 `json:"successThreshold"` + FailureThreshold int64 `json:"failureThreshold"` +} + +type HTTPGet struct { + Path string `json:"path"` + Port any `json:"port"` + Scheme string `json:"scheme"` +} + +type DepPorts struct { + Name string `json:"name"` + ContainerPort int64 `json:"containerPort"` + Protocol string `json:"protocol"` +} + +type Resources struct { + Limits Limits `json:"limits"` + Requests Limits `json:"requests"` +} + +type Limits struct { + CPU string `json:"cpu"` + Memory string `json:"memory"` +} + +type SecurityContext struct { +} + +type DepStatus struct { + ObservedGeneration int64 `json:"observedGeneration"` + Replicas int64 `json:"replicas"` + UpdatedReplicas int64 `json:"updatedReplicas"` + ReadyReplicas int64 `json:"readyReplicas"` + AvailableReplicas int64 `json:"availableReplicas"` + Conditions []Condition `json:"conditions"` +} + +type Condition struct { + Type string `json:"type"` + Status string `json:"status"` + LastUpdateTime string `json:"lastUpdateTime"` + LastTransitionTime string `json:"lastTransitionTime"` + Reason string `json:"reason"` + Message string `json:"message"` +} diff --git a/provider/gcp/cronjobs.go b/provider/gcp/cronjobs.go new file mode 100644 index 0000000..d596a94 --- /dev/null +++ b/provider/gcp/cronjobs.go @@ -0,0 +1,75 @@ +package gcp + +import ( + "fmt" + + "github.com/zopdev/zop-api/provider" + + "gofr.dev/pkg/gofr" +) + +func (g *GCP) ListCronJobs(ctx *gofr.Context, cluster *provider.Cluster, + cloudAccount *provider.CloudAccount, credentials interface{}, namespace string) (interface{}, error) { + credBody, err := g.getCredGCP(credentials) + if err != nil { + return nil, fmt.Errorf("failed to get credentials: %w", err) + } + + gkeCluster, err := g.getClusterInfo(ctx, cluster, cloudAccount, credBody) + if err != nil { + return nil, fmt.Errorf("failed to get cluster info: %w", err) + } + + client, err := g.createTLSConfiguredClient(gkeCluster.MasterAuth.ClusterCaCertificate) + if err != nil { + return nil, fmt.Errorf("failed to create TLS configured client: %w", err) + } + + apiEndpoint := fmt.Sprintf("https://%s/apis/batch/v1/namespaces/%s/cronjobs", gkeCluster.Endpoint, namespace) + + var cronJobResponse struct { + Items []provider.CronJobData `json:"items"` + } + + err = g.fetchDeployments(ctx, client, credBody, apiEndpoint, &cronJobResponse) + if err != nil { + return nil, fmt.Errorf("failed to fetch cronjobs: %w", err) + } + + return &provider.CronJobs{ + CronJobs: cronJobResponse.Items, + Metadata: &provider.Metadata{ + Name: "cronjobs", + Type: "kubernetes-cluster", + }, + }, nil +} + +func (g *GCP) GetCronJob(ctx *gofr.Context, cluster *provider.Cluster, + cloudAcc *provider.CloudAccount, creds any, namespace, name string) (any, error) { + credBody, err := g.getCredGCP(creds) + if err != nil { + return nil, fmt.Errorf("failed to get credentials: %w", err) + } + + gkeCluster, err := g.getClusterInfo(ctx, cluster, cloudAcc, credBody) + if err != nil { + return nil, fmt.Errorf("failed to get cluster info: %w", err) + } + + client, err := g.createTLSConfiguredClient(gkeCluster.MasterAuth.ClusterCaCertificate) + if err != nil { + return nil, fmt.Errorf("failed to create TLS configured client: %w", err) + } + + apiEndpoint := fmt.Sprintf("https://%s/apis/batch/v1/namespaces/%s/cronjobs/%s", gkeCluster.Endpoint, namespace, name) + + var cronJobResponse provider.CronJobData + + err = g.fetchDeployments(ctx, client, credBody, apiEndpoint, &cronJobResponse) + if err != nil { + return nil, err + } + + return &cronJobResponse, nil +} diff --git a/provider/gcp/deployments.go b/provider/gcp/deployments.go new file mode 100644 index 0000000..3a109c4 --- /dev/null +++ b/provider/gcp/deployments.go @@ -0,0 +1,137 @@ +package gcp + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + "gofr.dev/pkg/gofr" + + "golang.org/x/oauth2/google" + + "github.com/zopdev/zop-api/provider" +) + +func (g *GCP) ListDeployments(ctx *gofr.Context, cluster *provider.Cluster, + cloudAccount *provider.CloudAccount, credentials interface{}, namespace string) (interface{}, error) { + credBody, err := g.getCredGCP(credentials) + if err != nil { + return nil, fmt.Errorf("failed to get credentials: %w", err) + } + + gkeCluster, err := g.getClusterInfo(ctx, cluster, cloudAccount, credBody) + if err != nil { + return nil, fmt.Errorf("failed to get cluster info: %w", err) + } + + client, err := g.createTLSConfiguredClient(gkeCluster.MasterAuth.ClusterCaCertificate) + if err != nil { + return nil, fmt.Errorf("failed to create TLS configured client: %w", err) + } + + apiEndpoint := fmt.Sprintf("https://%s/apis/apps/v1/namespaces/%s/deployments", gkeCluster.Endpoint, namespace) + + // Parse JSON response + var depResponse struct { + Items []provider.DeploymentData `json:"items"` + } + + err = g.fetchDeployments(ctx, client, credBody, apiEndpoint, &depResponse) + if err != nil { + return nil, fmt.Errorf("failed to fetch deployments: %w", err) + } + + return &provider.Deployments{ + Deployments: depResponse.Items, + Metadata: &provider.Metadata{ + Name: "deployments", + Type: "kubernetes-cluster", + }, + }, nil +} + +// fetchDeployments fetches Kubernetes deployments from the specified namespace using the provided HTTP client. +func (*GCP) fetchDeployments(ctx *gofr.Context, client *http.Client, credBody []byte, + apiEndpoint string, depREsp any) error { + // Generate a JWT token from the credentials + config, err := google.JWTConfigFromJSON(credBody, "https://www.googleapis.com/auth/cloud-platform") + if err != nil { + return fmt.Errorf("failed to create JWT config: %w", err) + } + + // Create a TokenSource + tokenSource := config.TokenSource(ctx) + + // Get a token + token, err := tokenSource.Token() + if err != nil { + ctx.Logger.Errorf("failed to get token: %v", err) + return err + } + + // Make a request to the Kubernetes API to list deployments + req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiEndpoint, http.NoBody) + if err != nil { + ctx.Logger.Errorf("failed to create request: %w", err) + return err + } + + req.Header.Set("Authorization", "Bearer "+token.AccessToken) + req.Header.Set("Accept", "application/json") + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("API call failed: %w", err) + } + defer resp.Body.Close() + + // Handle unexpected status codes + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + ctx.Logger.Errorf("API call failed with status code %d: %s", resp.StatusCode, body) + + return errUnexpectedStatusCode{statusCode: resp.StatusCode} + } + + // Read the response body + body, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("failed to read response body: %w", err) + } + + if err := json.Unmarshal(body, depREsp); err != nil { + return fmt.Errorf("failed to parse JSON response: %w", err) + } + + return nil +} + +func (g *GCP) GetDeployment(ctx *gofr.Context, cluster *provider.Cluster, + cloudAcc *provider.CloudAccount, creds any, namespace, name string) (any, error) { + credBody, err := g.getCredGCP(creds) + if err != nil { + return nil, fmt.Errorf("failed to get credentials: %w", err) + } + + gkeCluster, err := g.getClusterInfo(ctx, cluster, cloudAcc, credBody) + if err != nil { + return nil, fmt.Errorf("failed to get cluster info: %w", err) + } + + client, err := g.createTLSConfiguredClient(gkeCluster.MasterAuth.ClusterCaCertificate) + if err != nil { + return nil, fmt.Errorf("failed to create TLS configured client: %w", err) + } + + apiEndpoint := fmt.Sprintf("https://%s/apis/apps/v1/namespaces/%s/deployments/%s", gkeCluster.Endpoint, namespace, name) + + var depResponse provider.DeploymentData + + err = g.fetchDeployments(ctx, client, credBody, apiEndpoint, &depResponse) + if err != nil { + return nil, err + } + + return &depResponse, nil +} diff --git a/provider/gcp/errors.go b/provider/gcp/errors.go new file mode 100644 index 0000000..d6d0fa0 --- /dev/null +++ b/provider/gcp/errors.go @@ -0,0 +1,11 @@ +package gcp + +import "fmt" + +type errUnexpectedStatusCode struct { + statusCode int +} + +func (e errUnexpectedStatusCode) Error() string { + return fmt.Sprintf("unexpected status code: %d", e.statusCode) +} diff --git a/provider/gcp/pods.go b/provider/gcp/pods.go new file mode 100644 index 0000000..f016285 --- /dev/null +++ b/provider/gcp/pods.go @@ -0,0 +1,75 @@ +package gcp + +import ( + "fmt" + + "github.com/zopdev/zop-api/provider" + + "gofr.dev/pkg/gofr" +) + +func (g *GCP) ListPods(ctx *gofr.Context, cluster *provider.Cluster, + cloudAccount *provider.CloudAccount, credentials interface{}, namespace string) (interface{}, error) { + credBody, err := g.getCredGCP(credentials) + if err != nil { + return nil, fmt.Errorf("failed to get credentials: %w", err) + } + + gkeCluster, err := g.getClusterInfo(ctx, cluster, cloudAccount, credBody) + if err != nil { + return nil, fmt.Errorf("failed to get cluster info: %w", err) + } + + client, err := g.createTLSConfiguredClient(gkeCluster.MasterAuth.ClusterCaCertificate) + if err != nil { + return nil, fmt.Errorf("failed to create TLS configured client: %w", err) + } + + apiEndpoint := fmt.Sprintf("https://%s/api/v1/namespaces/%s/pods", gkeCluster.Endpoint, namespace) + + var podResponse struct { + Items []provider.PodData `json:"items"` + } + + err = g.fetchDeployments(ctx, client, credBody, apiEndpoint, &podResponse) + if err != nil { + return nil, fmt.Errorf("failed to fetch pods: %w", err) + } + + return &provider.Pods{ + Pods: podResponse.Items, + Metadata: &provider.Metadata{ + Name: "pods", + Type: "kubernetes-cluster", + }, + }, nil +} + +func (g *GCP) GetPod(ctx *gofr.Context, cluster *provider.Cluster, + cloudAcc *provider.CloudAccount, creds any, namespace, name string) (any, error) { + credBody, err := g.getCredGCP(creds) + if err != nil { + return nil, fmt.Errorf("failed to get credentials: %w", err) + } + + gkeCluster, err := g.getClusterInfo(ctx, cluster, cloudAcc, credBody) + if err != nil { + return nil, fmt.Errorf("failed to get cluster info: %w", err) + } + + client, err := g.createTLSConfiguredClient(gkeCluster.MasterAuth.ClusterCaCertificate) + if err != nil { + return nil, fmt.Errorf("failed to create TLS configured client: %w", err) + } + + apiEndpoint := fmt.Sprintf("https://%s/api/v1/namespaces/%s/pods/%s", gkeCluster.Endpoint, namespace, name) + + var podResponse provider.PodData + + err = g.fetchDeployments(ctx, client, credBody, apiEndpoint, &podResponse) + if err != nil { + return nil, err + } + + return &podResponse, nil +} diff --git a/provider/gcp/services.go b/provider/gcp/services.go new file mode 100644 index 0000000..68df276 --- /dev/null +++ b/provider/gcp/services.go @@ -0,0 +1,142 @@ +package gcp + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/zopdev/zop-api/provider" + "gofr.dev/pkg/gofr" + + "golang.org/x/oauth2/google" +) + +func (g *GCP) ListServices(ctx *gofr.Context, cluster *provider.Cluster, + cloudAccount *provider.CloudAccount, credentials interface{}, namespace string) (interface{}, error) { + // Step 1: Get GCP credentials + credBody, err := g.getCredGCP(credentials) + if err != nil { + return nil, fmt.Errorf("failed to get credentials: %w", err) + } + + // Step 2: Get cluster information + gkeCluster, err := g.getClusterInfo(ctx, cluster, cloudAccount, credBody) + if err != nil { + return nil, fmt.Errorf("failed to get cluster info: %w", err) + } + + // Step 3: Create HTTP client with TLS configured + client, err := g.createTLSConfiguredClient(gkeCluster.MasterAuth.ClusterCaCertificate) + if err != nil { + return nil, fmt.Errorf("failed to create TLS configured client: %w", err) + } + + // Step 4: Fetch services from the Kubernetes API + apiEndpoint := fmt.Sprintf("https://%s/api/v1/namespaces/%s/services", gkeCluster.Endpoint, namespace) + + // Parse JSON response + var serviceResponse struct { + Items []provider.Service `json:"items"` + } + + err = g.fetchServices(ctx, client, credBody, apiEndpoint, &serviceResponse) + if err != nil { + return nil, fmt.Errorf("failed to fetch services: %w", err) + } + + return &provider.ServiceResponse{ + Services: serviceResponse.Items, + Metadata: provider.Metadata{ + Name: "services", + Type: "kubernetes-cluster", + }, + }, nil +} + +// fetchServices fetches Kubernetes services from the specified namespace using the provided HTTP client. +func (*GCP) fetchServices(ctx *gofr.Context, client *http.Client, credBody []byte, + apiEndpoint string, i any) error { + // Generate a JWT token from the credentials + config, err := google.JWTConfigFromJSON(credBody, "https://www.googleapis.com/auth/cloud-platform") + if err != nil { + return fmt.Errorf("failed to create JWT config: %w", err) + } + + // Create a TokenSource + tokenSource := config.TokenSource(ctx) + + // Get a token + token, err := tokenSource.Token() + if err != nil { + ctx.Logger.Errorf("failed to get token: %v", err) + return err + } + + // Make a request to the Kubernetes API to list services + req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiEndpoint, http.NoBody) + if err != nil { + ctx.Logger.Errorf("failed to create request: %w", err) + return err + } + + req.Header.Set("Authorization", "Bearer "+token.AccessToken) + req.Header.Set("Accept", "application/json") + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("API call failed: %w", err) + } + defer resp.Body.Close() + + // Handle unexpected status codes + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + ctx.Logger.Errorf("API call failed with status code %d: %s", resp.StatusCode, body) + + return errUnexpectedStatusCode{statusCode: resp.StatusCode} + } + + // Read the response body + body, err := io.ReadAll(resp.Body) + if err != nil { + return errUnexpectedStatusCode{statusCode: resp.StatusCode} + } + + if err := json.Unmarshal(body, i); err != nil { + return fmt.Errorf("failed to parse JSON response: %w", err) + } + + // Extract service details + + return nil +} + +func (g *GCP) GetService(ctx *gofr.Context, cluster *provider.Cluster, + cloudAccount *provider.CloudAccount, credentials interface{}, namespace, name string) (interface{}, error) { + credBody, err := g.getCredGCP(credentials) + if err != nil { + return nil, fmt.Errorf("failed to get credentials: %w", err) + } + + gkeCluster, err := g.getClusterInfo(ctx, cluster, cloudAccount, credBody) + if err != nil { + return nil, fmt.Errorf("failed to get cluster info: %w", err) + } + + client, err := g.createTLSConfiguredClient(gkeCluster.MasterAuth.ClusterCaCertificate) + if err != nil { + return nil, fmt.Errorf("failed to create TLS configured client: %w", err) + } + + apiEndpoint := fmt.Sprintf("https://%s/api/v1/namespaces/%s/services/%s", gkeCluster.Endpoint, namespace, name) + + var serviceResponse provider.Service + + err = g.fetchServices(ctx, client, credBody, apiEndpoint, &serviceResponse) + if err != nil { + return nil, fmt.Errorf("failed to fetch service %s: %w", name, err) + } + + return serviceResponse, nil +} diff --git a/provider/interface.go b/provider/interface.go index c353a3e..3683250 100644 --- a/provider/interface.go +++ b/provider/interface.go @@ -29,4 +29,21 @@ type Provider interface { // // Returns the namespaces for the specified cluster, or an error if the request fails. ListNamespace(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}) (interface{}, error) + ListServices(ctx *gofr.Context, cluster *Cluster, + cloudAccount *CloudAccount, credentials interface{}, namespace string) (interface{}, error) + ListDeployments(ctx *gofr.Context, cluster *Cluster, + cloudAccount *CloudAccount, credentials interface{}, namespace string) (interface{}, error) + ListPods(ctx *gofr.Context, cluster *Cluster, + cloudAccount *CloudAccount, credentials interface{}, namespace string) (interface{}, error) + ListCronJobs(ctx *gofr.Context, cluster *Cluster, + cloudAccount *CloudAccount, credentials interface{}, namespace string) (interface{}, error) + + GetService(ctx *gofr.Context, cluster *Cluster, + cloudAccount *CloudAccount, credentials interface{}, namespace, name string) (interface{}, error) + GetDeployment(ctx *gofr.Context, cluster *Cluster, + cloudAccount *CloudAccount, credentials interface{}, namespace, name string) (interface{}, error) + GetPod(ctx *gofr.Context, cluster *Cluster, + cloudAccount *CloudAccount, credentials interface{}, namespace, name string) (interface{}, error) + GetCronJob(ctx *gofr.Context, cluster *Cluster, + cloudAcc *CloudAccount, creds any, namespace, name string) (any, error) } diff --git a/provider/mock_interface.go b/provider/mock_interface.go index 18fc1ff..58af0cb 100644 --- a/provider/mock_interface.go +++ b/provider/mock_interface.go @@ -8,7 +8,6 @@ import ( reflect "reflect" gomock "go.uber.org/mock/gomock" - gofr "gofr.dev/pkg/gofr" ) @@ -35,6 +34,66 @@ func (m *MockProvider) EXPECT() *MockProviderMockRecorder { return m.recorder } +// GetCronJob mocks base method. +func (m *MockProvider) GetCronJob(ctx *gofr.Context, cluster *Cluster, cloudAcc *CloudAccount, creds any, namespace, name string) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCronJob", ctx, cluster, cloudAcc, creds, namespace, name) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCronJob indicates an expected call of GetCronJob. +func (mr *MockProviderMockRecorder) GetCronJob(ctx, cluster, cloudAcc, creds, namespace, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCronJob", reflect.TypeOf((*MockProvider)(nil).GetCronJob), ctx, cluster, cloudAcc, creds, namespace, name) +} + +// GetDeployment mocks base method. +func (m *MockProvider) GetDeployment(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}, namespace, name string) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeployment", ctx, cluster, cloudAccount, credentials, namespace, name) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeployment indicates an expected call of GetDeployment. +func (mr *MockProviderMockRecorder) GetDeployment(ctx, cluster, cloudAccount, credentials, namespace, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeployment", reflect.TypeOf((*MockProvider)(nil).GetDeployment), ctx, cluster, cloudAccount, credentials, namespace, name) +} + +// GetPod mocks base method. +func (m *MockProvider) GetPod(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}, namespace, name string) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPod", ctx, cluster, cloudAccount, credentials, namespace, name) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPod indicates an expected call of GetPod. +func (mr *MockProviderMockRecorder) GetPod(ctx, cluster, cloudAccount, credentials, namespace, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPod", reflect.TypeOf((*MockProvider)(nil).GetPod), ctx, cluster, cloudAccount, credentials, namespace, name) +} + +// GetService mocks base method. +func (m *MockProvider) GetService(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}, namespace, name string) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetService", ctx, cluster, cloudAccount, credentials, namespace, name) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetService indicates an expected call of GetService. +func (mr *MockProviderMockRecorder) GetService(ctx, cluster, cloudAccount, credentials, namespace, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*MockProvider)(nil).GetService), ctx, cluster, cloudAccount, credentials, namespace, name) +} + // ListAllClusters mocks base method. func (m *MockProvider) ListAllClusters(ctx *gofr.Context, cloudAccount *CloudAccount, credentials interface{}) (*ClusterResponse, error) { m.ctrl.T.Helper() @@ -50,6 +109,36 @@ func (mr *MockProviderMockRecorder) ListAllClusters(ctx, cloudAccount, credentia return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAllClusters", reflect.TypeOf((*MockProvider)(nil).ListAllClusters), ctx, cloudAccount, credentials) } +// ListCronJobs mocks base method. +func (m *MockProvider) ListCronJobs(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}, namespace string) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListCronJobs", ctx, cluster, cloudAccount, credentials, namespace) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListCronJobs indicates an expected call of ListCronJobs. +func (mr *MockProviderMockRecorder) ListCronJobs(ctx, cluster, cloudAccount, credentials, namespace interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCronJobs", reflect.TypeOf((*MockProvider)(nil).ListCronJobs), ctx, cluster, cloudAccount, credentials, namespace) +} + +// ListDeployments mocks base method. +func (m *MockProvider) ListDeployments(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}, namespace string) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListDeployments", ctx, cluster, cloudAccount, credentials, namespace) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListDeployments indicates an expected call of ListDeployments. +func (mr *MockProviderMockRecorder) ListDeployments(ctx, cluster, cloudAccount, credentials, namespace interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployments", reflect.TypeOf((*MockProvider)(nil).ListDeployments), ctx, cluster, cloudAccount, credentials, namespace) +} + // ListNamespace mocks base method. func (m *MockProvider) ListNamespace(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}) (interface{}, error) { m.ctrl.T.Helper() @@ -64,3 +153,33 @@ func (mr *MockProviderMockRecorder) ListNamespace(ctx, cluster, cloudAccount, cr mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListNamespace", reflect.TypeOf((*MockProvider)(nil).ListNamespace), ctx, cluster, cloudAccount, credentials) } + +// ListPods mocks base method. +func (m *MockProvider) ListPods(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}, namespace string) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListPods", ctx, cluster, cloudAccount, credentials, namespace) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListPods indicates an expected call of ListPods. +func (mr *MockProviderMockRecorder) ListPods(ctx, cluster, cloudAccount, credentials, namespace interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPods", reflect.TypeOf((*MockProvider)(nil).ListPods), ctx, cluster, cloudAccount, credentials, namespace) +} + +// ListServices mocks base method. +func (m *MockProvider) ListServices(ctx *gofr.Context, cluster *Cluster, cloudAccount *CloudAccount, credentials interface{}, namespace string) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListServices", ctx, cluster, cloudAccount, credentials, namespace) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListServices indicates an expected call of ListServices. +func (mr *MockProviderMockRecorder) ListServices(ctx, cluster, cloudAccount, credentials, namespace interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockProvider)(nil).ListServices), ctx, cluster, cloudAccount, credentials, namespace) +} diff --git a/provider/models.go b/provider/models.go index cfed9ba..792561a 100644 --- a/provider/models.go +++ b/provider/models.go @@ -21,6 +21,7 @@ type ClusterResponse struct { type Metadata struct { Name string `json:"name"` + Type string `json:"type"` } // Next provides pagination details for fetching additional data. @@ -117,3 +118,57 @@ type Namespace struct { // to set key for sending response. Type string `json:"type"` } + +type ServiceResponse struct { + Services []Service `json:"services"` + Metadata Metadata `json:"metadata"` +} + +type ServiceList struct { + Items []Service `json:"items"` +} + +type Service struct { + Metadata K8sMetadata `json:"metadata"` + Spec ServiceSpec `json:"spec"` + Status Status `json:"status"` +} + +type K8sMetadata struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + CreationTimestamp string `json:"creationTimestamp"` + Labels map[string]string `json:"labels"` + Annotations map[string]string `json:"annotations"` +} + +type ServiceSpec struct { + Ports []Port `json:"ports"` + Selector map[string]string `json:"selector"` + ClusterIP string `json:"clusterIP"` + Type string `json:"type"` + SessionAffinity string `json:"sessionAffinity"` + ExternalIPs []string `json:"externalIPs"` + LoadBalancerIP string `json:"loadBalancerIP"` + LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges"` +} + +type Port struct { + Protocol string `json:"protocol"` + Port int `json:"port"` + TargetPort any `json:"targetPort"` + NodePort any `json:"nodePort"` +} + +type Status struct { + LoadBalancer LoadBalancer `json:"loadBalancer"` +} + +type LoadBalancer struct { + Ingress []Ingress `json:"ingress"` +} + +type Ingress struct { + IP string `json:"ip"` + Hostname string `json:"hostname"` +} diff --git a/provider/podsmodels.go b/provider/podsmodels.go new file mode 100644 index 0000000..80113fa --- /dev/null +++ b/provider/podsmodels.go @@ -0,0 +1,76 @@ +package provider + +type Pods struct { + Pods []PodData `json:"pods"` + Metadata *Metadata `json:"metadata"` +} + +type PodData struct { + Metadata PodMetadata `json:"metadata"` + Spec PodSpec `json:"spec"` + Status PodStatus `json:"status"` +} + +type PodMetadata struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + UID string `json:"uid"` + ResourceVersion string `json:"resourceVersion"` + CreationTimestamp string `json:"creationTimestamp"` + Labels map[string]string `json:"labels"` + Annotations map[string]string `json:"annotations"` + OwnerReferences []struct { + Name string `json:"name"` + Kind string `json:"kind"` + } `json:"ownerReferences"` +} + +type PodSpec struct { + Containers []Container `json:"containers"` + NodeName string `json:"nodeName"` + RestartPolicy string `json:"restartPolicy"` + ServiceAccountName string `json:"serviceAccountName"` + HostIP string `json:"hostIP"` + SecurityContext SecurityContext `json:"securityContext"` +} + +type PodStatus struct { + Phase string `json:"phase"` + Conditions []PodCondition `json:"conditions"` + HostIP string `json:"hostIP"` + PodIP string `json:"podIP"` + StartTime string `json:"startTime"` + ContainerStatuses []ContainerStatus `json:"containerStatuses"` +} + +type PodCondition struct { + Type string `json:"type"` + Status string `json:"status"` + LastProbeTime string `json:"lastProbeTime"` + LastTransitionTime string `json:"lastTransitionTime"` +} + +type ContainerStatus struct { + Name string `json:"name"` + State State `json:"state"` + LastState State `json:"lastState"` + Ready bool `json:"ready"` + RestartCount int `json:"restartCount"` + Image string `json:"image"` + ImageID string `json:"imageID"` + ContainerID string `json:"containerID"` + Started bool `json:"started"` +} + +type State struct { + Waiting *StateDetails `json:"waiting,omitempty"` + Running *StateDetails `json:"running,omitempty"` + Terminated *StateDetails `json:"terminated,omitempty"` +} + +type StateDetails struct { + Reason string `json:"reason"` + Message string `json:"message"` + ExitCode int `json:"exitCode,omitempty"` + Signal int `json:"signal,omitempty"` +}