diff --git a/.github/workflows/go.yaml b/.github/workflows/go.yaml index c19eb3f..757eec1 100644 --- a/.github/workflows/go.yaml +++ b/.github/workflows/go.yaml @@ -27,7 +27,7 @@ jobs: run: go vet ./... - name: Run coverage - run: go test -race -coverpkg='./internal/...' -coverprofile=coverage.out -covermode=atomic ./... + run: go test -coverpkg='./internal/...' -coverprofile=coverage.out -covermode=atomic ./... - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 diff --git a/README.md b/README.md index e23711f..0522a4d 100644 --- a/README.md +++ b/README.md @@ -189,12 +189,6 @@ correct version. If not, wait a bit and try again, you landed on an instance tha ![software architecture](docs/architecture-export.png) -### Those aren't Beans, they're Acorns - -Our singleton components implement the -[Acorn interface](https://github.com/StephanHCB/go-autumn-acorn-registry/blob/main/api/interface.go). -All singletons refer to each other by references to their interface. This allows for easy mocking during tests. - ## development ### initial setup diff --git a/go.mod b/go.mod index e05e21e..f87f4b0 100644 --- a/go.mod +++ b/go.mod @@ -52,7 +52,6 @@ exclude ( ) require ( - github.com/StephanHCB/go-autumn-acorn-registry v0.3.1 github.com/StephanHCB/go-autumn-config-api v0.2.1 github.com/StephanHCB/go-autumn-config-env v0.2.2 github.com/StephanHCB/go-autumn-logging v0.3.0 @@ -62,7 +61,7 @@ require ( github.com/StephanHCB/go-autumn-restclient-circuitbreaker v0.4.1 github.com/StephanHCB/go-autumn-restclient-circuitbreaker-prometheus v0.1.0 github.com/StephanHCB/go-autumn-restclient-prometheus v0.1.2 - github.com/StephanHCB/go-backend-service-common v0.5.1 + github.com/StephanHCB/go-backend-service-common v0.6.0 github.com/go-chi/chi/v5 v5.0.10 github.com/go-git/go-billy/v5 v5.5.0 github.com/go-git/go-git/v5 v5.9.0 @@ -81,6 +80,7 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/StephanHCB/go-autumn-acorn-registry v0.3.1 // indirect github.com/StephanHCB/go-autumn-web-swagger-ui v0.2.3 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect github.com/armon/go-radix v1.0.0 // indirect @@ -125,9 +125,9 @@ require ( github.com/tidwall/tinylru v1.2.1 // indirect github.com/twmb/franz-go/pkg/kmsg v1.6.1 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - go.elastic.co/apm/module/apmchiv5/v2 v2.4.3 // indirect - go.elastic.co/apm/module/apmhttp/v2 v2.4.3 // indirect - go.elastic.co/apm/v2 v2.4.3 // indirect + go.elastic.co/apm/module/apmchiv5/v2 v2.4.4 // indirect + go.elastic.co/apm/module/apmhttp/v2 v2.4.4 // indirect + go.elastic.co/apm/v2 v2.4.4 // indirect go.elastic.co/fastjson v1.1.0 // indirect golang.org/x/crypto v0.13.0 // indirect golang.org/x/mod v0.12.0 // indirect diff --git a/go.sum b/go.sum index 0add86e..f8a32f2 100644 --- a/go.sum +++ b/go.sum @@ -27,8 +27,8 @@ github.com/StephanHCB/go-autumn-restclient-prometheus v0.1.2 h1:xsTZdR9WlSaoeUc3 github.com/StephanHCB/go-autumn-restclient-prometheus v0.1.2/go.mod h1:74X7ghxTOjj6Tl0lvVJXOQHz+3RbKvGirvF5l82XDwk= github.com/StephanHCB/go-autumn-web-swagger-ui v0.2.3 h1:aC/rTlw9pBPCWYH46KGzSB942sTALIcIsZi0piVUuEo= github.com/StephanHCB/go-autumn-web-swagger-ui v0.2.3/go.mod h1:EBtCQXF8JhoADnadezundz2xWEdFPmx2NUTgZYtUE0M= -github.com/StephanHCB/go-backend-service-common v0.5.1 h1:Ailpaq3PjCKsir79YTubz0lMvLOI2kE38hZPj6snx5Y= -github.com/StephanHCB/go-backend-service-common v0.5.1/go.mod h1:UBCrmMypKkucU8Upqlej4sUCI4Bn0Xakgv3yT9kSbno= +github.com/StephanHCB/go-backend-service-common v0.6.0 h1:PWqGdUq7TPqI+rPwgHB+pcXZUWQOCMBMS4wFWoWXvvc= +github.com/StephanHCB/go-backend-service-common v0.6.0/go.mod h1:/S3+UrSczKX6Ypk35G5xz1NRjnH6SifKLlfsFrveAmc= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= @@ -185,12 +185,12 @@ github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.elastic.co/apm/module/apmchiv5/v2 v2.4.3 h1:U1Ju0e8GhgqWQTsWiUKWMxx10qL0JgJwsjH8Xhe0bbw= -go.elastic.co/apm/module/apmchiv5/v2 v2.4.3/go.mod h1:KgKbigCbttUp5X5I5EWm+ch1m5QgEcRaOU+aNLu5Exw= -go.elastic.co/apm/module/apmhttp/v2 v2.4.3 h1:bBqbbtQSEL+uVpH5CS656E9x6pXha8kkZ468/G0T5Eo= -go.elastic.co/apm/module/apmhttp/v2 v2.4.3/go.mod h1:PsafA29/iwRva1ouV+70Lfu6RyAJHh6Zcc+jL6eZ83E= -go.elastic.co/apm/v2 v2.4.3 h1:k6mj63O7IIyqqn3S52C2vBXvaSK9M5FHp0aZHpPH/as= -go.elastic.co/apm/v2 v2.4.3/go.mod h1:+CiBUdrrAGnGCL9TNx7tQz3BrfYV23L8Ljvotoc87so= +go.elastic.co/apm/module/apmchiv5/v2 v2.4.4 h1:jcEDE5wRvR8e6Y1bIF1lTMgegp52A2P5K4m4AED8Hnk= +go.elastic.co/apm/module/apmchiv5/v2 v2.4.4/go.mod h1:VBBWtTlOF23Sj4M+Ad8Zxl+yq5RP4D6NPC8hhDz0xy0= +go.elastic.co/apm/module/apmhttp/v2 v2.4.4 h1:BcJDLFztZByHiJRXXvAHY7bue9+vhzMLn2OBK5N8HDw= +go.elastic.co/apm/module/apmhttp/v2 v2.4.4/go.mod h1:694qsHWRPVkfYqQ224ZSeRx9Dt2FS/xF1igNBGkHi6o= +go.elastic.co/apm/v2 v2.4.4 h1:KGbmUEtLNQ6sCFGpqTMhfRjqDOKP8IliO+efErKY5lU= +go.elastic.co/apm/v2 v2.4.4/go.mod h1:+CiBUdrrAGnGCL9TNx7tQz3BrfYV23L8Ljvotoc87so= go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/internal/acorn/application/appint.go b/internal/acorn/application/appint.go index a882cf2..ffb03f5 100644 --- a/internal/acorn/application/appint.go +++ b/internal/acorn/application/appint.go @@ -7,27 +7,6 @@ const ApplicationName = "metadata" type Application interface { IsApplication() bool - // Register registers all Acorns that make up the application. - // - // after a call to Register you can override the Acorn constructors in the registry, e.g. for mocking. - // - // if not already called, Run will call this for you. - Register() - - // Create instantiates all Acorns, but does not connect them. - // - // after a call to Create you can replace Acorns by name in the registry, e.g. for testing/mocking. - // - // if not already called, Run will call this for you. - Create() - - // Assemble wires up all Acorns. - // - // to avoid a circular dependency with logging, this also parses the configuration, but does not validate it. - // - // if not already called, Run will call this for you. - Assemble() error - // Run runs the application, including setup and teardown phase // // returns the exit code - we do not call os.Exit inside diff --git a/internal/acorn/application/serverint.go b/internal/acorn/application/serverint.go index 6c30be0..3d2d6b2 100644 --- a/internal/acorn/application/serverint.go +++ b/internal/acorn/application/serverint.go @@ -2,11 +2,11 @@ package application import "context" -const ServerAcornName = "server" - type Server interface { IsServer() bool + Setup() error + WireUp(ctx context.Context) Run() error diff --git a/internal/acorn/controller/ownerctlint.go b/internal/acorn/controller/ownerctlint.go index 9bfbba5..c781f50 100644 --- a/internal/acorn/controller/ownerctlint.go +++ b/internal/acorn/controller/ownerctlint.go @@ -5,8 +5,6 @@ import ( "github.com/go-chi/chi/v5" ) -const OwnerControllerAcornName = "ownerctl" - // OwnerController provides endpoints for managing owner information type OwnerController interface { IsOwnerController() bool diff --git a/internal/acorn/controller/repositoryctlint.go b/internal/acorn/controller/repositoryctlint.go index 4cede81..e0f39bb 100644 --- a/internal/acorn/controller/repositoryctlint.go +++ b/internal/acorn/controller/repositoryctlint.go @@ -5,8 +5,6 @@ import ( "github.com/go-chi/chi/v5" ) -const RepositoryControllerAcornName = "repositoryctl" - // RepositoryController provides endpoints for managing repository information type RepositoryController interface { IsRepositoryController() bool diff --git a/internal/acorn/controller/servicectlint.go b/internal/acorn/controller/servicectlint.go index f9212b4..4f391b7 100644 --- a/internal/acorn/controller/servicectlint.go +++ b/internal/acorn/controller/servicectlint.go @@ -5,8 +5,6 @@ import ( "github.com/go-chi/chi/v5" ) -const ServiceControllerAcornName = "servicectl" - // ServiceController provides endpoints for managing service information type ServiceController interface { IsServiceController() bool diff --git a/internal/acorn/controller/webhookctlint.go b/internal/acorn/controller/webhookctlint.go index 1e02a30..3b9acaf 100644 --- a/internal/acorn/controller/webhookctlint.go +++ b/internal/acorn/controller/webhookctlint.go @@ -5,8 +5,6 @@ import ( "github.com/go-chi/chi/v5" ) -const WebhookControllerAcornName = "webhookctl" - // WebhookController provides a simple git webhook endpoint type WebhookController interface { IsWebhookController() bool diff --git a/internal/acorn/repository/bitbucketint.go b/internal/acorn/repository/bitbucketint.go index 16076b6..5780c35 100644 --- a/internal/acorn/repository/bitbucketint.go +++ b/internal/acorn/repository/bitbucketint.go @@ -4,12 +4,12 @@ import ( "context" ) -const BitbucketAcornName = "bitbucket" - type Bitbucket interface { IsBitbucket() bool - Setup(ctx context.Context) error + Setup() error + + SetupClient(ctx context.Context) error GetBitbucketUser(ctx context.Context, username string) (BitbucketUser, error) GetBitbucketUsers(ctx context.Context, usernames []string) ([]BitbucketUser, error) diff --git a/internal/acorn/repository/hostipint.go b/internal/acorn/repository/hostipint.go index 6453b94..0e57476 100644 --- a/internal/acorn/repository/hostipint.go +++ b/internal/acorn/repository/hostipint.go @@ -2,12 +2,12 @@ package repository import "net" -const HostIPAcornName = "hostip" - // HostIP interacts with the local network interfaces. type HostIP interface { IsHostIP() bool + Setup() error + // ObtainLocalIp gets the first non-localhost ipv4 address from your interfaces. // // In a k8s deployment, that'll be the pod ip. diff --git a/internal/acorn/repository/idpint.go b/internal/acorn/repository/idpint.go index 957975b..ab131e1 100644 --- a/internal/acorn/repository/idpint.go +++ b/internal/acorn/repository/idpint.go @@ -2,16 +2,16 @@ package repository import "context" -const IdentityProviderAcornName = "idp" - // IdentityProvider is the central singleton representing an Open ID Connect Identity Provider. // // We use this to obtain a JWT keyset and to check its id endpoint to synchronously validate JWT tokens. type IdentityProvider interface { IsIdentityProvider() bool - // Setup uses the configuration to set up - Setup(ctx context.Context) error + Setup() error + + // SetupConnector uses the configuration to set up the connector + SetupConnector(ctx context.Context) error // ObtainKeySet calls the key set endpoint and converts the keys to PEM for use with the jwt package ObtainKeySet(ctx context.Context) error diff --git a/internal/acorn/repository/kafkaint.go b/internal/acorn/repository/kafkaint.go index b9dcfa1..e4fca53 100644 --- a/internal/acorn/repository/kafkaint.go +++ b/internal/acorn/repository/kafkaint.go @@ -2,12 +2,13 @@ package repository import "context" -const KafkaAcornName = "kafka" - // Kafka is the central singleton representing the kafka messaging bus. type Kafka interface { IsKafka() bool + Setup() error + Teardown() + // SubscribeIncoming allows you to register a callback that is called whenever a message is received from the Kafka bus. // // Note, we currently only allow a single callback, so calling this multiple times will overwrite the callback. diff --git a/internal/acorn/repository/metadataint.go b/internal/acorn/repository/metadataint.go index 37b5c5a..9a8f06d 100644 --- a/internal/acorn/repository/metadataint.go +++ b/internal/acorn/repository/metadataint.go @@ -6,8 +6,6 @@ import ( "time" ) -const MetadataAcornName = "metadata" - // CommitInfo holds information about a commit. type CommitInfo struct { CommitHash string @@ -24,6 +22,9 @@ type CommitInfo struct { type Metadata interface { IsMetadata() bool + Setup() error + Teardown() + // Clone performs an initial in-memory clone of the metadata repository on the mainline Clone(ctx context.Context) error diff --git a/internal/acorn/repository/notifierint.go b/internal/acorn/repository/notifierint.go index a0f159a..581381f 100644 --- a/internal/acorn/repository/notifierint.go +++ b/internal/acorn/repository/notifierint.go @@ -6,12 +6,12 @@ import ( "github.com/Interhyp/metadata-service/internal/types" ) -const NotifierAcornName = "notifier" - type Notifier interface { IsNotifier() bool - Setup(ctx context.Context) error + Setup() error + + SetupNotifier(ctx context.Context) error PublishCreation(ctx context.Context, payloadName string, payload openapi.NotificationPayload) error diff --git a/internal/acorn/repository/sshAuthProviderInt.go b/internal/acorn/repository/sshAuthProviderInt.go index 4a92032..827ee4a 100644 --- a/internal/acorn/repository/sshAuthProviderInt.go +++ b/internal/acorn/repository/sshAuthProviderInt.go @@ -6,13 +6,13 @@ import ( "github.com/go-git/go-git/v5/plumbing/transport/ssh" ) -const SshAuthProviderAcornName = "SshAuthProvider" - // SshAuthProvider is an SshAuthProvider business logic component. type SshAuthProvider interface { IsSshAuthProvider() bool - Setup(ctx context.Context) error + Setup() error + + SetupProvider(ctx context.Context) error ProvideSshAuth(ctx context.Context) (*ssh.PublicKeys, error) } diff --git a/internal/acorn/service/cacheint.go b/internal/acorn/service/cacheint.go index c6e628f..9d06220 100644 --- a/internal/acorn/service/cacheint.go +++ b/internal/acorn/service/cacheint.go @@ -5,12 +5,12 @@ import ( "github.com/Interhyp/metadata-service/api" ) -const CacheAcornName = "cache" - // Cache is the central in-memory metadata cache, present to speed up read access to the current metadata. type Cache interface { IsCache() bool + Setup() error + // --- owner cache --- // SetOwnerListTimestamp lets you set or update the timestamp for the last full scan of the list of aliases. diff --git a/internal/acorn/service/mapperint.go b/internal/acorn/service/mapperint.go index f573e36..0745218 100644 --- a/internal/acorn/service/mapperint.go +++ b/internal/acorn/service/mapperint.go @@ -6,8 +6,6 @@ import ( "github.com/Interhyp/metadata-service/internal/acorn/repository" ) -const MapperAcornName = "mapper" - // Mapper translates between the git repo representation (yaml) and the business entities. // // It also performs commit workflows for the metadata repository. @@ -22,6 +20,8 @@ const MapperAcornName = "mapper" type Mapper interface { IsMapper() bool + Setup() error + RefreshMetadata(ctx context.Context) ([]repository.UpdateEvent, error) ContainsNewInformation(ctx context.Context, event repository.UpdateEvent) bool diff --git a/internal/acorn/service/ownersint.go b/internal/acorn/service/ownersint.go index f7b9847..7dcebf5 100644 --- a/internal/acorn/service/ownersint.go +++ b/internal/acorn/service/ownersint.go @@ -5,12 +5,12 @@ import ( "github.com/Interhyp/metadata-service/api" ) -const OwnersAcornName = "owners" - // Owners provides the business logic for owner metadata. type Owners interface { IsOwners() bool + Setup() error + GetOwners(ctx context.Context) (openapi.OwnerListDto, error) GetOwner(ctx context.Context, ownerAlias string) (openapi.OwnerDto, error) diff --git a/internal/acorn/service/repositoriesint.go b/internal/acorn/service/repositoriesint.go index 1e2899b..7a7f1c3 100644 --- a/internal/acorn/service/repositoriesint.go +++ b/internal/acorn/service/repositoriesint.go @@ -6,11 +6,10 @@ import ( "github.com/StephanHCB/go-backend-service-common/api/apierrors" ) -const RepositoriesAcornName = "repositories" - // Repositories provides the business logic for repository metadata. type Repositories interface { IsRepositories() bool + Setup() error // ValidRepositoryKey checks validity of a repository key and returns an error describing the problem if invalid ValidRepositoryKey(ctx context.Context, repoKey string) apierrors.AnnotatedError diff --git a/internal/acorn/service/servicesint.go b/internal/acorn/service/servicesint.go index 83cb8af..c864645 100644 --- a/internal/acorn/service/servicesint.go +++ b/internal/acorn/service/servicesint.go @@ -5,12 +5,12 @@ import ( "github.com/Interhyp/metadata-service/api" ) -const ServicesAcornName = "services" - // Services provides the business logic for service metadata. type Services interface { IsServices() bool + Setup() error + GetServices(ctx context.Context, ownerAliasFilter string) (openapi.ServiceListDto, error) GetService(ctx context.Context, serviceName string) (openapi.ServiceDto, error) diff --git a/internal/acorn/service/triggerint.go b/internal/acorn/service/triggerint.go index 9729f7e..b7c4e96 100644 --- a/internal/acorn/service/triggerint.go +++ b/internal/acorn/service/triggerint.go @@ -1,10 +1,10 @@ package service -const TriggerAcornName = "trigger" - // Trigger triggers update runs in Updater. // // Trigger events occur on initial app startup (before it becomes healthy), and periodically type Trigger interface { IsTrigger() bool + Setup() error + Teardown() } diff --git a/internal/acorn/service/updaterint.go b/internal/acorn/service/updaterint.go index aecd94f..50be7cd 100644 --- a/internal/acorn/service/updaterint.go +++ b/internal/acorn/service/updaterint.go @@ -5,12 +5,12 @@ import ( "github.com/Interhyp/metadata-service/api" ) -const UpdaterAcornName = "updater" - // Updater is the central orchestrator component that manages information flow. type Updater interface { IsUpdater() bool + Setup() error + // -- Eventing -- // StartReceivingEvents starts receiving events. Called by Trigger after it has initially populated the cache. diff --git a/internal/repository/bitbucket/acorn.go b/internal/repository/bitbucket/acorn.go deleted file mode 100644 index e979224..0000000 --- a/internal/repository/bitbucket/acorn.go +++ /dev/null @@ -1,60 +0,0 @@ -package bitbucket - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/Interhyp/metadata-service/internal/repository/bitbucket/bbclient" - auacornapi "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (r *Impl) IsBitbucket() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.BitbucketAcornName -} - -func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - r.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - r.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - r.Vault = registry.GetAcornByName(librepo.VaultAcornName).(librepo.Vault) - - r.LowLevel = bbclient.New(r.Configuration, r.Logging, r.Vault) - - return nil -} - -func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - if err := registry.SetupAfter(r.Configuration.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(r.Logging.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(r.Vault.(auacornapi.Acorn)); err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := r.Setup(ctx); err != nil { - r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up bitbucket client. BAILING OUT") - return err - } - - r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up bitbucket") - return nil -} - -func (r *Impl) TeardownAcorn(_ auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/repository/bitbucket/repository.go b/internal/repository/bitbucket/repository.go index 92d646b..2b15aa8 100644 --- a/internal/repository/bitbucket/repository.go +++ b/internal/repository/bitbucket/repository.go @@ -5,7 +5,9 @@ import ( "fmt" "github.com/Interhyp/metadata-service/internal/acorn/errors/httperror" "github.com/Interhyp/metadata-service/internal/acorn/repository" + "github.com/Interhyp/metadata-service/internal/repository/bitbucket/bbclient" "github.com/Interhyp/metadata-service/internal/repository/bitbucket/bbclientint" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "net/http" "sort" @@ -19,7 +21,36 @@ type Impl struct { LowLevel bbclientint.BitbucketClient } -func (r *Impl) Setup(ctx context.Context) error { +func New( + configuration librepo.Configuration, + logging librepo.Logging, + vault librepo.Vault, +) repository.Bitbucket { + return &Impl{ + Configuration: configuration, + Logging: logging, + Vault: vault, + LowLevel: bbclient.New(configuration, logging, vault), + } +} + +func (r *Impl) IsBitbucket() bool { + return true +} + +func (r *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := r.SetupClient(ctx); err != nil { + r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up bitbucket client. BAILING OUT") + return err + } + + r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up bitbucket") + return nil +} + +func (r *Impl) SetupClient(ctx context.Context) error { r.Logging.Logger().Ctx(ctx).Info().Print("setting up bitbucket client") return r.LowLevel.Setup() } diff --git a/internal/repository/bitbucket/repository_test.go b/internal/repository/bitbucket/repository_test.go index 63b58fe..eb090f2 100644 --- a/internal/repository/bitbucket/repository_test.go +++ b/internal/repository/bitbucket/repository_test.go @@ -4,8 +4,11 @@ import ( "context" "github.com/Interhyp/metadata-service/internal/acorn/errors/httperror" "github.com/Interhyp/metadata-service/internal/acorn/repository" + "github.com/Interhyp/metadata-service/internal/repository/config" "github.com/Interhyp/metadata-service/test/mock/bbclientmock" "github.com/Interhyp/metadata-service/test/mock/vaultmock" + auconfigenv "github.com/StephanHCB/go-autumn-config-env" + libconfig "github.com/StephanHCB/go-backend-service-common/repository/config" "github.com/StephanHCB/go-backend-service-common/repository/logging" "github.com/stretchr/testify/require" "testing" @@ -22,6 +25,32 @@ func tstSetup() Impl { } } +func TestNewAndSetup(t *testing.T) { + vault := &vaultmock.VaultImpl{} + logger := &logging.LoggingImpl{} + conf := tstConfig(t) + cut := New(conf, logger, vault) + + lowLevel := &bbclientmock.BitbucketClientMock{} + cut.(*Impl).LowLevel = lowLevel + + require.True(t, cut.IsBitbucket()) + + err := cut.Setup() + require.Nil(t, err) +} + +const validConfigurationPath = "../resources/valid-config.yaml" + +func tstConfig(t *testing.T) *libconfig.ConfigImpl { + impl, _ := config.New() + configImpl := impl.(*libconfig.ConfigImpl) + auconfigenv.LocalConfigFileName = validConfigurationPath + err := configImpl.Read() + require.Nil(t, err) + return configImpl +} + func TestGetBitbucketUser_Success(t *testing.T) { cut := tstSetup() diff --git a/internal/repository/config/plumbing.go b/internal/repository/config/plumbing.go index fb97496..6983ba5 100644 --- a/internal/repository/config/plumbing.go +++ b/internal/repository/config/plumbing.go @@ -5,9 +5,9 @@ import ( "fmt" "github.com/Interhyp/metadata-service/internal/acorn/config" openapi "github.com/Interhyp/metadata-service/internal/types" - auacornapi "github.com/StephanHCB/go-autumn-acorn-registry/api" auconfigapi "github.com/StephanHCB/go-autumn-config-api" auconfigenv "github.com/StephanHCB/go-autumn-config-env" + librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" libconfig "github.com/StephanHCB/go-backend-service-common/repository/config" "github.com/StephanHCB/go-backend-service-common/repository/vault" "regexp" @@ -65,12 +65,16 @@ type CustomConfigImpl struct { VNotificationConsumerConfigs map[string]config.NotificationConsumerConfig } -func New() auacornapi.Acorn { +func New() (librepo.Configuration, config.CustomConfiguration) { instance := &CustomConfigImpl{} configItems := make([]auconfigapi.ConfigItem, 0) configItems = append(configItems, CustomConfigItems...) configItems = append(configItems, vault.ConfigItems...) - return libconfig.New(instance, configItems) + + libInstance := libconfig.NewNoAcorn(instance, configItems) + + // perform conversion to CustomConfig here + return libInstance, config.Custom(libInstance) } func (c *CustomConfigImpl) Obtain(getter func(key string) string) { diff --git a/internal/repository/config/validation_test.go b/internal/repository/config/validation_test.go index da3a11a..5cf3948 100644 --- a/internal/repository/config/validation_test.go +++ b/internal/repository/config/validation_test.go @@ -18,8 +18,13 @@ import ( const basedir = "../../../test/resources/" +func classUnderTest() *libconfig.ConfigImpl { + instance, _ := New() + return instance.(*libconfig.ConfigImpl) +} + func tstYamlRead(t *testing.T, filename string, expectedMsgPart string) { - cut := New().(*libconfig.ConfigImpl) + cut := classUnderTest() auconfigenv.LocalConfigFileName = basedir + filename err := cut.Read() if expectedMsgPart == "" { @@ -41,7 +46,7 @@ func TestYamlRead_InvalidSyntax(t *testing.T) { } func tstSetupCutAndLogRecorder(t *testing.T, configfile string) (librepo.Configuration, error) { - cut := New().(librepo.Configuration) + cut := classUnderTest() // --- simulate auacornapi.Acorn Assemble phase for just the configuration @@ -56,13 +61,13 @@ func tstSetupCutAndLogRecorder(t *testing.T, configfile string) (librepo.Configu goauzerolog.RecordedLogForTesting = new(bytes.Buffer) logRecorder.(*logging.LoggingImpl).SetupForTesting() - cut.(*libconfig.ConfigImpl).Logging = logRecorder + cut.Logging = logRecorder ctx := log.Logger.WithContext(context.Background()) err = cut.Validate(ctx) - cut.(*libconfig.ConfigImpl).ObtainPredefinedValues() - cut.(*libconfig.ConfigImpl).CustomConfiguration.Obtain(auconfigenv.Get) + cut.ObtainPredefinedValues() + cut.CustomConfiguration.Obtain(auconfigenv.Get) return cut, err } diff --git a/internal/repository/hostip/acorn.go b/internal/repository/hostip/acorn.go deleted file mode 100644 index 3489391..0000000 --- a/internal/repository/hostip/acorn.go +++ /dev/null @@ -1,51 +0,0 @@ -package hostip - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (r *Impl) IsHostIP() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.HostIPAcornName -} - -func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - r.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - return nil -} - -func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(r.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - ip, err := r.ObtainLocalIp() - if err != nil { - r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to obtain local ip address. BAILING OUT") - return err - } - - r.Logging.Logger().Ctx(ctx).Info().Printf("non-trivial ipv4 address is %s", ip.String()) - - return nil -} - -func (r *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/repository/hostip/hostip.go b/internal/repository/hostip/hostip.go index 746f000..6924dbd 100644 --- a/internal/repository/hostip/hostip.go +++ b/internal/repository/hostip/hostip.go @@ -1,7 +1,10 @@ package hostip import ( + "context" "errors" + "github.com/Interhyp/metadata-service/internal/acorn/repository" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "net" ) @@ -10,6 +13,32 @@ type Impl struct { Logging librepo.Logging } +func New( + logging librepo.Logging, +) repository.HostIP { + return &Impl{ + Logging: logging, + } +} + +func (r *Impl) IsHostIP() bool { + return true +} + +func (r *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + ip, err := r.ObtainLocalIp() + if err != nil { + r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to obtain local ip address. BAILING OUT") + return err + } + + r.Logging.Logger().Ctx(ctx).Info().Printf("non-trivial ipv4 address is %s", ip.String()) + + return nil +} + func (r *Impl) ObtainLocalIp() (net.IP, error) { ifaces, err := net.Interfaces() if err != nil { diff --git a/internal/repository/idp/acorn.go b/internal/repository/idp/acorn.go deleted file mode 100644 index 71e7253..0000000 --- a/internal/repository/idp/acorn.go +++ /dev/null @@ -1,63 +0,0 @@ -package idp - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (r *Impl) IsIdentityProvider() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.IdentityProviderAcornName -} - -func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - r.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - r.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - - r.CustomConfiguration = config.Custom(r.Configuration) - - return nil -} - -func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(r.Configuration.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(r.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := r.Setup(ctx); err != nil { - r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up idp connector. BAILING OUT") - return err - } - - if err := r.ObtainKeySet(ctx); err != nil { - r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to obtain key set from identity provider. BAILING OUT") - return err - } - - r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up idp connector") - return nil -} - -func (r *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/repository/idp/idp.go b/internal/repository/idp/idp.go index 227a7c5..858402a 100644 --- a/internal/repository/idp/idp.go +++ b/internal/repository/idp/idp.go @@ -10,6 +10,8 @@ import ( "errors" "fmt" "github.com/Interhyp/metadata-service/internal/acorn/config" + "github.com/Interhyp/metadata-service/internal/acorn/repository" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" aurestclientprometheus "github.com/StephanHCB/go-autumn-restclient-prometheus" aurestclientapi "github.com/StephanHCB/go-autumn-restclient/api" auresthttpclient "github.com/StephanHCB/go-autumn-restclient/implementation/httpclient" @@ -30,7 +32,40 @@ type Impl struct { PEMKeySet []string } -func (r *Impl) Setup(ctx context.Context) error { +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, +) repository.IdentityProvider { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + } +} + +func (r *Impl) IsIdentityProvider() bool { + return true +} + +func (r *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := r.SetupConnector(ctx); err != nil { + r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up idp connector. BAILING OUT") + return err + } + + if err := r.ObtainKeySet(ctx); err != nil { + r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to obtain key set from identity provider. BAILING OUT") + return err + } + + r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up idp connector") + return nil +} + +func (r *Impl) SetupConnector(ctx context.Context) error { r.Logging.Logger().Ctx(ctx).Info().Print("setting up idp connector") client, err := auresthttpclient.New(10*time.Second, nil, nil) diff --git a/internal/repository/kafka/acorn.go b/internal/repository/kafka/acorn.go deleted file mode 100644 index 7347c81..0000000 --- a/internal/repository/kafka/acorn.go +++ /dev/null @@ -1,68 +0,0 @@ -package kafka - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{ - Callback: func(_ repository.UpdateEvent) {}, - } -} - -func (r *Impl) IsKafka() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.KafkaAcornName -} - -func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - r.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - r.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - r.HostIP = registry.GetAcornByName(repository.HostIPAcornName).(repository.HostIP) - - r.CustomConfiguration = config.Custom(r.Configuration) - - return nil -} - -func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - if err := registry.SetupAfter(r.Configuration.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(r.Logging.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(r.HostIP.(auacornapi.Acorn)); err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := r.Connect(ctx); err != nil { - r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up kafka connection. BAILING OUT") - return err - } - - r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up kafka") - return nil -} - -func (r *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := r.Disconnect(ctx); err != nil { - r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to tear down kafka connection. Continuing anyway.") - } - - return nil -} diff --git a/internal/repository/kafka/kafka.go b/internal/repository/kafka/kafka.go index 0f0584c..ab797cf 100644 --- a/internal/repository/kafka/kafka.go +++ b/internal/repository/kafka/kafka.go @@ -30,6 +30,46 @@ type Impl struct { KafkaTopic string } +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + hostIP repository.HostIP, +) repository.Kafka { + return &Impl{ + Callback: func(_ repository.UpdateEvent) {}, + + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + HostIP: hostIP, + } +} + +func (r *Impl) IsKafka() bool { + return true +} + +func (r *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := r.Connect(ctx); err != nil { + r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up kafka connection. BAILING OUT") + return err + } + + r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up kafka") + return nil +} + +func (r *Impl) Teardown() { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := r.Disconnect(ctx); err != nil { + r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to tear down kafka connection. Continuing anyway.") + } +} + func (r *Impl) SubscribeIncoming(ctx context.Context, callback repository.ReceiverCallback) error { r.Logging.Logger().Ctx(ctx).Info().Print("accepted kafka subscription callback") r.Callback = callback diff --git a/internal/repository/metadata/acorn.go b/internal/repository/metadata/acorn.go deleted file mode 100644 index 02d4e17..0000000 --- a/internal/repository/metadata/acorn.go +++ /dev/null @@ -1,69 +0,0 @@ -package metadata - -import ( - "context" - "time" - - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{ - // allow override in tests - Now: time.Now, - CommitCacheByFilePath: make(map[string]repository.CommitInfo), - NewCommits: make([]repository.CommitInfo, 0), - KnownCommits: make(map[string]bool), - } -} - -func (r *Impl) IsMetadata() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.MetadataAcornName -} - -func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - r.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - r.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - r.SshAuthProvider = registry.GetAcornByName(repository.SshAuthProviderAcornName).(repository.SshAuthProvider) - r.CustomConfiguration = config.Custom(r.Configuration) - - return nil -} - -func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - if err := registry.SetupAfter(r.Configuration.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(r.Logging.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(r.SshAuthProvider.(auacornapi.Acorn)); err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := r.Clone(ctx); err != nil { - r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to clone service-metadata. BAILING OUT") - return err - } - - r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up metadata") - return nil -} - -func (r *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - ctx := auzerolog.AddLoggerToCtx(context.Background()) - r.Discard(ctx) - return nil -} diff --git a/internal/repository/metadata/metadata.go b/internal/repository/metadata/metadata.go index c790ee6..0107b2e 100644 --- a/internal/repository/metadata/metadata.go +++ b/internal/repository/metadata/metadata.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" "github.com/StephanHCB/go-backend-service-common/web/middleware/security" "io" "os" @@ -29,6 +30,7 @@ type Impl struct { Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration Logging librepo.Logging + Timestamp librepo.Timestamp SshAuthProvider repository.SshAuthProvider @@ -47,12 +49,52 @@ type Impl struct { AlreadySeenCommit string mu sync.Mutex - Now func() time.Time LastPull time.Time consoleOutput bytes.Buffer } +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + sshAuth repository.SshAuthProvider, +) repository.Metadata { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + SshAuthProvider: sshAuth, + + CommitCacheByFilePath: make(map[string]repository.CommitInfo), + NewCommits: make([]repository.CommitInfo, 0), + KnownCommits: make(map[string]bool), + } +} + +func (r *Impl) IsMetadata() bool { + return true +} + +func (r *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := r.Clone(ctx); err != nil { + r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to clone service-metadata. BAILING OUT") + return err + } + + r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up metadata") + return nil +} + +func (r *Impl) Teardown() { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + r.Discard(ctx) +} + const insecureSkipTLS = false var UseHTTP = true @@ -183,7 +225,7 @@ func (r *Impl) Clone(ctx context.Context) error { r.mu.Lock() defer r.mu.Unlock() - r.LastPull = r.Now() + r.LastPull = r.Timestamp.Now() r.CommitCacheByFilePath = make(map[string]repository.CommitInfo) r.NewCommits = make([]repository.CommitInfo, 0) @@ -242,7 +284,7 @@ func (r *Impl) Pull(ctx context.Context) error { r.mu.Lock() defer r.mu.Unlock() - r.LastPull = r.Now() + r.LastPull = r.Timestamp.Now() tree, err := r.GitRepo.Worktree() if err != nil { @@ -301,7 +343,7 @@ func (r *Impl) Commit(ctx context.Context, message string) (repository.CommitInf commitInfo := repository.CommitInfo{ CommitHash: "", - TimeStamp: r.Now(), + TimeStamp: r.Timestamp.Now(), Message: message, } @@ -326,7 +368,7 @@ func (r *Impl) Commit(ctx context.Context, message string) (repository.CommitInf return commitInfo, nochangeserror.New(ctx) } - commitTimestamp := r.Now() + commitTimestamp := r.Timestamp.Now() commit, err := tree.Commit(message, &git.CommitOptions{ Committer: &object.Signature{ Name: r.CustomConfiguration.GitCommitterName(), @@ -393,7 +435,7 @@ func (r *Impl) Push(ctx context.Context) error { return err } - r.LastPull = r.Now() + r.LastPull = r.Timestamp.Now() r.Logging.Logger().Ctx(ctx).Debug().Print("git push worked - console output was: ", r.sanitizedConsoleOutput()) return nil @@ -476,7 +518,7 @@ func (r *Impl) ReadFile(filename string) ([]byte, repository.CommitInfo, error) errorCommitInfo := repository.CommitInfo{ CommitHash: "", - TimeStamp: r.Now(), + TimeStamp: r.Timestamp.Now(), Message: "", } diff --git a/internal/repository/notifier/acorn.go b/internal/repository/notifier/acorn.go deleted file mode 100644 index 69a4d56..0000000 --- a/internal/repository/notifier/acorn.go +++ /dev/null @@ -1,56 +0,0 @@ -package notifier - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (r *Impl) IsNotifier() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.NotifierAcornName -} - -func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - r.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - r.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - r.CustomConfiguration = config.Custom(r.Configuration) - - return nil -} - -func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - if err := registry.SetupAfter(r.Configuration.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(r.Logging.(auacornapi.Acorn)); err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := r.Setup(ctx); err != nil { - r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up notifier client. BAILING OUT") - return err - } - - r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up notifier") - return nil -} - -func (r *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/repository/notifier/notifier.go b/internal/repository/notifier/notifier.go index 63e3275..884d35c 100644 --- a/internal/repository/notifier/notifier.go +++ b/internal/repository/notifier/notifier.go @@ -8,7 +8,7 @@ import ( "github.com/Interhyp/metadata-service/internal/acorn/repository" notifierclient "github.com/Interhyp/metadata-service/internal/repository/notifier/client/notifier" "github.com/Interhyp/metadata-service/internal/types" - auacornapi "github.com/StephanHCB/go-autumn-acorn-registry/api" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "github.com/StephanHCB/go-backend-service-common/web/util/contexthelper" "time" @@ -23,12 +23,39 @@ type Impl struct { SkipAsync bool // for tests } +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, +) repository.Notifier { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + } +} + +func (r *Impl) IsNotifier() bool { + return true +} + +func (r *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := r.SetupNotifier(ctx); err != nil { + r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up notifier client. BAILING OUT") + return err + } + + r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up notifier") + return nil +} + const ( webhookContextTimeout = 5 * time.Minute ) var ( - _ auacornapi.Acorn = (*Impl)(nil) _ repository.Notifier = (*Impl)(nil) ) @@ -51,7 +78,7 @@ func AsPayload[T openapi.OwnerDto | openapi.ServiceDto | openapi.RepositoryDto]( } } -func (r *Impl) Setup(ctx context.Context) error { +func (r *Impl) SetupNotifier(ctx context.Context) error { r.Logging.Logger().Ctx(ctx).Info().Print("setting up notifier clients") r.Clients = make(map[string]notifierclient.NotifierClient) diff --git a/internal/repository/sshAuthProvider/acorn.go b/internal/repository/sshAuthProvider/acorn.go deleted file mode 100644 index b99c8fc..0000000 --- a/internal/repository/sshAuthProvider/acorn.go +++ /dev/null @@ -1,54 +0,0 @@ -package sshAuthProvider - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &SshAuthProviderImpl{} -} - -func (s *SshAuthProviderImpl) IsSshAuthProvider() bool { - return true -} - -func (s SshAuthProviderImpl) AcornName() string { - return repository.SshAuthProviderAcornName -} - -func (s *SshAuthProviderImpl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - - s.CustomConfiguration = config.Custom(s.Configuration) - - return nil -} - -func (s *SshAuthProviderImpl) SetupAcorn(registry auacornapi.AcornRegistry) error { - if err := registry.SetupAfter(s.Logging.(auacornapi.Acorn)); err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := s.Setup(ctx); err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up business layer SshAuthProvider. BAILING OUT") - return err - } - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up SshAuthProvider service") - return nil -} - -func (s *SshAuthProviderImpl) TeardownAcorn(_ auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/repository/sshAuthProvider/sshAuthProvider.go b/internal/repository/sshAuthProvider/sshAuthProvider.go index a8c5586..711f04c 100644 --- a/internal/repository/sshAuthProvider/sshAuthProvider.go +++ b/internal/repository/sshAuthProvider/sshAuthProvider.go @@ -3,6 +3,8 @@ package sshAuthProvider import ( "context" "github.com/Interhyp/metadata-service/internal/acorn/config" + "github.com/Interhyp/metadata-service/internal/acorn/repository" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" aulogging "github.com/StephanHCB/go-autumn-logging" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" @@ -16,7 +18,35 @@ type SshAuthProviderImpl struct { CustomConfiguration config.CustomConfiguration } -func (s *SshAuthProviderImpl) Setup(ctx context.Context) error { +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, +) repository.SshAuthProvider { + return &SshAuthProviderImpl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + } +} + +func (s *SshAuthProviderImpl) IsSshAuthProvider() bool { + return true +} + +func (s *SshAuthProviderImpl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := s.SetupProvider(ctx); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up business layer SshAuthProvider. BAILING OUT") + return err + } + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up SshAuthProvider service") + return nil +} + +func (s *SshAuthProviderImpl) SetupProvider(ctx context.Context) error { return nil } diff --git a/internal/service/cache/acorn.go b/internal/service/cache/acorn.go deleted file mode 100644 index 30a8b57..0000000 --- a/internal/service/cache/acorn.go +++ /dev/null @@ -1,57 +0,0 @@ -package cache - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (s *Impl) IsCache() bool { - return true -} - -func (s *Impl) AcornName() string { - return service.CacheAcornName -} - -func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - - s.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - - return nil -} - -func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(s.Configuration.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := s.Setup(ctx); err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up business layer cache. BAILING OUT") - return err - } - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up cache") - return nil -} - -func (s *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/service/cache/cache.go b/internal/service/cache/cache.go index 1ce62b3..f0bea90 100644 --- a/internal/service/cache/cache.go +++ b/internal/service/cache/cache.go @@ -2,22 +2,51 @@ package cache import ( "context" + "github.com/Interhyp/metadata-service/internal/acorn/service" "github.com/Interhyp/metadata-service/internal/service/cache/cacheable" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" ) type Impl struct { Configuration librepo.Configuration Logging librepo.Logging + Timestamp librepo.Timestamp OwnerCache cacheable.Cacheable ServiceCache cacheable.Cacheable RepositoryCache cacheable.Cacheable +} + +func New( + configuration librepo.Configuration, + logging librepo.Logging, + timestamp librepo.Timestamp, +) service.Cache { + return &Impl{ + Configuration: configuration, + Logging: logging, + Timestamp: timestamp, + } +} + +func (s *Impl) IsCache() bool { + return true +} + +func (s *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) - Timestamp librepo.Timestamp + if err := s.SetupCache(ctx); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up business layer cache. BAILING OUT") + return err + } + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up cache") + return nil } -func (s *Impl) Setup(_ context.Context) error { +func (s *Impl) SetupCache(_ context.Context) error { // idempotent to allow mocking if s.OwnerCache == nil { s.OwnerCache = cacheable.New() diff --git a/internal/service/mapper/acorn.go b/internal/service/mapper/acorn.go deleted file mode 100644 index 60ff7c0..0000000 --- a/internal/service/mapper/acorn.go +++ /dev/null @@ -1,72 +0,0 @@ -package mapper - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" - "time" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{ - Now: time.Now, - } -} - -func (s *Impl) IsMapper() bool { - return true -} - -func (s *Impl) AcornName() string { - return service.MapperAcornName -} - -func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - s.Metadata = registry.GetAcornByName(repository.MetadataAcornName).(repository.Metadata) - s.Bitbucket = registry.GetAcornByName(repository.BitbucketAcornName).(repository.Bitbucket) - s.CustomConfiguration = config.Custom(s.Configuration) - - return nil -} - -func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(s.Configuration.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Metadata.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Bitbucket.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - err = s.Setup(ctx) - if err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up mapper. BAILING OUT.") - return err - } - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up mapper") - return nil -} - -func (s *Impl) TeardownAcorn(_ auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/service/mapper/mapper.go b/internal/service/mapper/mapper.go index 63e8d16..668ff97 100644 --- a/internal/service/mapper/mapper.go +++ b/internal/service/mapper/mapper.go @@ -4,10 +4,11 @@ import ( "context" "github.com/Interhyp/metadata-service/internal/acorn/config" "github.com/Interhyp/metadata-service/internal/acorn/repository" + "github.com/Interhyp/metadata-service/internal/acorn/service" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "strings" "sync" - "time" ) type Impl struct { @@ -16,15 +17,49 @@ type Impl struct { Logging librepo.Logging Metadata repository.Metadata Bitbucket repository.Bitbucket + Timestamp librepo.Timestamp muOwnerCaches sync.Mutex serviceOwnerCache map[string]string repositoryOwnerCache map[string]string +} + +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + metadata repository.Metadata, + bitbucket repository.Bitbucket, +) service.Mapper { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + Metadata: metadata, + Bitbucket: bitbucket, + } +} + +func (s *Impl) IsMapper() bool { + return true +} - Now func() time.Time +func (s *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + err := s.SetupMapper(ctx) + if err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up mapper. BAILING OUT.") + return err + } + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up mapper") + return nil } -func (s *Impl) Setup(_ context.Context) error { +func (s *Impl) SetupMapper(_ context.Context) error { s.serviceOwnerCache = make(map[string]string) s.repositoryOwnerCache = make(map[string]string) diff --git a/internal/service/mapper/repository.go b/internal/service/mapper/repository.go index c8945b7..6621bb8 100644 --- a/internal/service/mapper/repository.go +++ b/internal/service/mapper/repository.go @@ -64,7 +64,7 @@ func (s *Impl) lookupRepositoryOwnerWithRefresh(ctx context.Context, repoKey str } ownerAlias, ok = s.lookupInRepositoryOwnerCache(repoKey) if !ok { - return "", apierrors.NewNotFoundError(fmt.Sprintf("repository not found %s", repoKey), "repository.notfound", nil, s.Now()) + return "", apierrors.NewNotFoundError(fmt.Sprintf("repository not found %s", repoKey), "repository.notfound", nil, s.Timestamp.Now()) } } return ownerAlias, nil diff --git a/internal/service/mapper/service.go b/internal/service/mapper/service.go index 87bd8da..8cc1938 100644 --- a/internal/service/mapper/service.go +++ b/internal/service/mapper/service.go @@ -63,7 +63,7 @@ func (s *Impl) lookupServiceOwnerWithRefresh(ctx context.Context, serviceName st } ownerAlias, ok = s.lookupInServiceOwnerCache(serviceName) if !ok { - return "", apierrors.NewNotFoundError(fmt.Sprintf("service not found %s", serviceName), "service.notfound", nil, s.Now()) + return "", apierrors.NewNotFoundError(fmt.Sprintf("service not found %s", serviceName), "service.notfound", nil, s.Timestamp.Now()) } } return ownerAlias, nil diff --git a/internal/service/owners/acorn.go b/internal/service/owners/acorn.go deleted file mode 100644 index 5249ab5..0000000 --- a/internal/service/owners/acorn.go +++ /dev/null @@ -1,64 +0,0 @@ -package owners - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (s *Impl) IsOwners() bool { - return true -} - -func (s *Impl) AcornName() string { - return service.OwnersAcornName -} - -func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - s.Cache = registry.GetAcornByName(service.CacheAcornName).(service.Cache) - s.Updater = registry.GetAcornByName(service.UpdaterAcornName).(service.Updater) - - s.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - - return nil -} - -func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(s.Configuration.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Cache.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Updater.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - // nothing to do - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up owners business component") - return nil -} - -func (s *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/service/owners/owners.go b/internal/service/owners/owners.go index 0fe0b1c..4531365 100644 --- a/internal/service/owners/owners.go +++ b/internal/service/owners/owners.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/Interhyp/metadata-service/api" "github.com/Interhyp/metadata-service/internal/acorn/service" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" "strings" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" @@ -14,10 +15,38 @@ import ( type Impl struct { Configuration librepo.Configuration Logging librepo.Logging + Timestamp librepo.Timestamp Cache service.Cache Updater service.Updater +} - Timestamp librepo.Timestamp +func New( + configuration librepo.Configuration, + logging librepo.Logging, + timestamp librepo.Timestamp, + cache service.Cache, + updater service.Updater, +) service.Owners { + return &Impl{ + Configuration: configuration, + Logging: logging, + Timestamp: timestamp, + Cache: cache, + Updater: updater, + } +} + +func (s *Impl) IsOwners() bool { + return true +} + +func (s *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + // nothing to do + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up owners business component") + return nil } func (s *Impl) GetOwners(ctx context.Context) (openapi.OwnerListDto, error) { diff --git a/internal/service/repositories/acorn.go b/internal/service/repositories/acorn.go deleted file mode 100644 index 292aa34..0000000 --- a/internal/service/repositories/acorn.go +++ /dev/null @@ -1,72 +0,0 @@ -package repositories - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (s *Impl) IsRepositories() bool { - return true -} - -func (s *Impl) AcornName() string { - return service.RepositoriesAcornName -} - -func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - s.Cache = registry.GetAcornByName(service.CacheAcornName).(service.Cache) - s.Updater = registry.GetAcornByName(service.UpdaterAcornName).(service.Updater) - s.Owners = registry.GetAcornByName(service.OwnersAcornName).(service.Owners) - - s.CustomConfiguration = config.Custom(s.Configuration) - - s.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - - return nil -} - -func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(s.Configuration.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Cache.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Updater.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Owners.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - // nothing to do - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up repositories business component") - return nil -} - -func (s *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/service/repositories/repositories.go b/internal/service/repositories/repositories.go index 701c6d8..5353730 100644 --- a/internal/service/repositories/repositories.go +++ b/internal/service/repositories/repositories.go @@ -7,6 +7,7 @@ import ( "github.com/Interhyp/metadata-service/internal/acorn/config" "github.com/Interhyp/metadata-service/internal/acorn/service" "github.com/Interhyp/metadata-service/internal/service/util" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "github.com/StephanHCB/go-backend-service-common/api/apierrors" "net/url" @@ -14,14 +15,46 @@ import ( ) type Impl struct { - Configuration librepo.Configuration - Logging librepo.Logging - Cache service.Cache - Updater service.Updater - Owners service.Owners - + Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration + Logging librepo.Logging Timestamp librepo.Timestamp + Cache service.Cache + Updater service.Updater + Owners service.Owners +} + +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + cache service.Cache, + updater service.Updater, + owners service.Owners, +) service.Repositories { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + Cache: cache, + Updater: updater, + Owners: owners, + } +} + +func (s *Impl) IsRepositories() bool { + return true +} + +func (s *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + // nothing to do + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up repositories business component") + return nil } func (s *Impl) ValidRepositoryKey(ctx context.Context, key string) apierrors.AnnotatedError { @@ -321,7 +354,7 @@ func (s *Impl) PatchRepository(ctx context.Context, key string, repositoryPatchD if err != nil { return err } - + result = repositoryWritten return nil }) diff --git a/internal/service/services/acorn.go b/internal/service/services/acorn.go deleted file mode 100644 index c7eb2c4..0000000 --- a/internal/service/services/acorn.go +++ /dev/null @@ -1,77 +0,0 @@ -package services - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (s *Impl) IsServices() bool { - return true -} - -func (s *Impl) AcornName() string { - return service.ServicesAcornName -} - -func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - s.Cache = registry.GetAcornByName(service.CacheAcornName).(service.Cache) - s.Updater = registry.GetAcornByName(service.UpdaterAcornName).(service.Updater) - s.Owner = registry.GetAcornByName(service.OwnersAcornName).(service.Owners) - s.Repositories = registry.GetAcornByName(service.RepositoriesAcornName).(service.Repositories) - - s.CustomConfiguration = config.Custom(s.Configuration) - - s.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - - return nil -} - -func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(s.Configuration.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Cache.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Updater.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Owner.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Repositories.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - // nothing to do - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up services business component") - return nil -} - -func (s *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/service/services/services.go b/internal/service/services/services.go index 0de5c04..e400711 100644 --- a/internal/service/services/services.go +++ b/internal/service/services/services.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" "strings" "github.com/Interhyp/metadata-service/api" @@ -18,12 +19,43 @@ type Impl struct { Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration Logging librepo.Logging + Timestamp librepo.Timestamp Cache service.Cache Updater service.Updater - Owner service.Owners Repositories service.Repositories +} - Timestamp librepo.Timestamp +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + cache service.Cache, + updater service.Updater, + repositories service.Repositories, +) service.Services { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + Cache: cache, + Updater: updater, + Repositories: repositories, + } +} + +func (s *Impl) IsServices() bool { + return true +} + +func (s *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + // nothing to do + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up services business component") + return nil } var initialServiceLifecycle = "experimental" diff --git a/internal/service/trigger/acorn.go b/internal/service/trigger/acorn.go deleted file mode 100644 index ddc6378..0000000 --- a/internal/service/trigger/acorn.go +++ /dev/null @@ -1,100 +0,0 @@ -package trigger - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" - "time" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{ - Now: time.Now, - } -} - -func (s *Impl) IsTrigger() bool { - return true -} - -func (s *Impl) AcornName() string { - return service.TriggerAcornName -} - -func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - s.Updater = registry.GetAcornByName(service.UpdaterAcornName).(service.Updater) - - s.CustomConfiguration = config.Custom(s.Configuration) - - return nil -} - -func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(s.Configuration.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Updater.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := s.Setup(ctx); err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up trigger. BAILING OUT") - return err - } - - s.Logging.Logger().Ctx(ctx).Info().Print("performing initial cache population...") - - if err := s.PerformWithCancel(context.Background()); err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("initial cache population failed. BAILING OUT") - return err - } - - if !s.SkipStart { - s.Logging.Logger().Ctx(ctx).Info().Print("starting event receiver...") - - if err := s.Updater.StartReceivingEvents(ctx); err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to start event receiver. BAILING OUT") - return err - } - - s.Logging.Logger().Ctx(ctx).Info().Print("starting cron job...") - - if err := s.StartCronjob(ctx); err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to start cron job. BAILING OUT") - return err - } - } - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up trigger") - return nil -} - -func (s *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - s.Logging.Logger().Ctx(ctx).Info().Print("stopping cron job...") - - if err := s.StopCronjob(ctx); err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to stop cron job. Continuing with teardown.") - // do NOT abort tear down cycle - return nil - } - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully tore down trigger") - return nil -} diff --git a/internal/service/trigger/trigger.go b/internal/service/trigger/trigger.go index a758bb6..ae4edbb 100644 --- a/internal/service/trigger/trigger.go +++ b/internal/service/trigger/trigger.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/Interhyp/metadata-service/internal/acorn/config" "github.com/Interhyp/metadata-service/internal/acorn/service" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "github.com/StephanHCB/go-backend-service-common/web/middleware/requestid" "github.com/robfig/cron/v3" @@ -16,13 +17,82 @@ type Impl struct { Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration Logging librepo.Logging + Timestamp librepo.Timestamp Updater service.Updater LoggingCtx context.Context Cron *cron.Cron SkipStart bool - Now func() time.Time +} + +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + updater service.Updater, +) service.Trigger { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + Updater: updater, + } +} + +func (s *Impl) IsTrigger() bool { + return true +} + +func (s *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := s.SetupTriggerCronjob(ctx); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up trigger. BAILING OUT") + return err + } + + s.Logging.Logger().Ctx(ctx).Info().Print("performing initial cache population...") + + if err := s.PerformWithCancel(context.Background()); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("initial cache population failed. BAILING OUT") + return err + } + + if !s.SkipStart { + s.Logging.Logger().Ctx(ctx).Info().Print("starting event receiver...") + + if err := s.Updater.StartReceivingEvents(ctx); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to start event receiver. BAILING OUT") + return err + } + + s.Logging.Logger().Ctx(ctx).Info().Print("starting cron job...") + + if err := s.StartCronjob(ctx); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to start cron job. BAILING OUT") + return err + } + } + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up trigger") + return nil +} + +func (s *Impl) Teardown() { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + s.Logging.Logger().Ctx(ctx).Info().Print("stopping cron job...") + + if err := s.StopCronjob(ctx); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to stop cron job. Continuing with teardown.") + // do NOT abort tear down cycle + return + } + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully tore down trigger") } // --- implement cron.Logger --- @@ -54,7 +124,7 @@ func (s *Impl) Error(err error, msg string, keysAndValues ...interface{}) { // --- cron job --- -func (s *Impl) Setup(ctx context.Context) error { +func (s *Impl) SetupTriggerCronjob(ctx context.Context) error { s.LoggingCtx = ctx s.Cron = cron.New( diff --git a/internal/service/updater/acorn.go b/internal/service/updater/acorn.go deleted file mode 100644 index 3df2c26..0000000 --- a/internal/service/updater/acorn.go +++ /dev/null @@ -1,82 +0,0 @@ -package updater - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" - "time" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{ - Now: time.Now, - } -} - -func (s *Impl) IsUpdater() bool { - return true -} - -func (s *Impl) AcornName() string { - return service.UpdaterAcornName -} - -func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - s.Kafka = registry.GetAcornByName(repository.KafkaAcornName).(repository.Kafka) - s.Notifier = registry.GetAcornByName(repository.NotifierAcornName).(repository.Notifier) - s.Mapper = registry.GetAcornByName(service.MapperAcornName).(service.Mapper) - s.Cache = registry.GetAcornByName(service.CacheAcornName).(service.Cache) - - s.CustomConfiguration = config.Custom(s.Configuration) - - return nil -} - -func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(s.Configuration.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Kafka.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Notifier.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Mapper.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(s.Cache.(auacornapi.Acorn)) - if err != nil { - return err - } - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := s.Setup(ctx); err != nil { - s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up updater. BAILING OUT") - return err - } - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up updater") - return nil -} - -func (s *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/service/updater/owners.go b/internal/service/updater/owners.go index dc19467..98ab2ce 100644 --- a/internal/service/updater/owners.go +++ b/internal/service/updater/owners.go @@ -81,7 +81,7 @@ func (s *Impl) ownerKafkaEvent(ownerAlias string, timeStamp string, commitHash s func (s *Impl) updateOwners(ctx context.Context) error { s.Logging.Logger().Ctx(ctx).Info().Print("updating owners") - ts := timeStamp(s.Now()) + ts := timeStamp(s.Timestamp.Now()) ownerAliasesMap, err := s.decideOwnersToAddUpdateOrRemove(ctx) if err != nil { diff --git a/internal/service/updater/repositories.go b/internal/service/updater/repositories.go index 8536b70..c153c5b 100644 --- a/internal/service/updater/repositories.go +++ b/internal/service/updater/repositories.go @@ -22,7 +22,7 @@ func (s *Impl) WriteRepository(ctx context.Context, key string, repository opena allowed := s.CanMoveOrDeleteRepository(subCtx, key) if !allowed { s.Logging.Logger().Ctx(ctx).Info().Printf("tried to move repository %v, which is still referenced by its service", key) - return apierrors.NewConflictError("repository.conflict.referenced", "this repository is being referenced in a service, you cannot change its owner directly - you can change the owner of the service and this will move it along", nil, s.Now()) + return apierrors.NewConflictError("repository.conflict.referenced", "this repository is being referenced in a service, you cannot change its owner directly - you can change the owner of the service and this will move it along", nil, s.Timestamp.Now()) } repositoryWritten, err := s.Mapper.WriteRepositoryWithChangedOwner(subCtx, key, repository) @@ -98,7 +98,7 @@ func (s *Impl) repositoryKafkaEvent(key string, timeStamp string, commitHash str func (s *Impl) updateRepositories(ctx context.Context) error { s.Logging.Logger().Ctx(ctx).Info().Print("updating repositories") - ts := timeStamp(s.Now()) + ts := timeStamp(s.Timestamp.Now()) repositoryKeysMap, err := s.decideRepositoriesToAddUpdateOrRemove(ctx) if err != nil { diff --git a/internal/service/updater/services.go b/internal/service/updater/services.go index 76bd527..c57d573 100644 --- a/internal/service/updater/services.go +++ b/internal/service/updater/services.go @@ -113,7 +113,7 @@ func (s *Impl) serviceAndReposKafkaEvent(serviceName string, repoKeys []string, func (s *Impl) updateServices(ctx context.Context) error { s.Logging.Logger().Ctx(ctx).Info().Print("updating services") - ts := timeStamp(s.Now()) + ts := timeStamp(s.Timestamp.Now()) serviceNamesMap, err := s.decideServicesToAddUpdateOrRemove(ctx) if err != nil { diff --git a/internal/service/updater/updater.go b/internal/service/updater/updater.go index 469c1d8..a4fed2a 100644 --- a/internal/service/updater/updater.go +++ b/internal/service/updater/updater.go @@ -6,26 +6,26 @@ import ( "github.com/Interhyp/metadata-service/internal/acorn/config" "github.com/Interhyp/metadata-service/internal/acorn/repository" "github.com/Interhyp/metadata-service/internal/acorn/service" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "github.com/StephanHCB/go-backend-service-common/web/middleware/requestid" "github.com/prometheus/client_golang/prometheus" "github.com/rs/zerolog/log" "reflect" "sync" - "time" ) type Impl struct { Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration Logging librepo.Logging + Timestamp librepo.Timestamp Kafka repository.Kafka Notifier repository.Notifier Mapper service.Mapper Cache service.Cache - mu sync.Mutex - Now func() time.Time + mu sync.Mutex totalErrorCounter prometheus.Counter metadataErrorCounter prometheus.Counter @@ -34,6 +34,44 @@ type Impl struct { repoErrorCounter *prometheus.CounterVec } +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + kafka repository.Kafka, + notifier repository.Notifier, + mapper service.Mapper, + cache service.Cache, +) service.Updater { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + Kafka: kafka, + Notifier: notifier, + Mapper: mapper, + Cache: cache, + } +} + +func (s *Impl) IsUpdater() bool { + return true +} + +func (s *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := s.SetupUpdater(ctx); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up updater. BAILING OUT") + return err + } + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up updater") + return nil +} + const ( removeExisting = iota updateExisting = iota @@ -50,7 +88,7 @@ var ( // --- metrics --- -func (s *Impl) Setup(ctx context.Context) error { +func (s *Impl) SetupUpdater(ctx context.Context) error { s.totalErrorCounter = prometheus.NewCounter( prometheus.CounterOpts{ Name: TotalErrorCounterName, diff --git a/internal/web/app/app.go b/internal/web/app/app.go index d2a3113..8d83a43 100644 --- a/internal/web/app/app.go +++ b/internal/web/app/app.go @@ -2,6 +2,10 @@ package app import ( "github.com/Interhyp/metadata-service/internal/acorn/application" + configrepo "github.com/Interhyp/metadata-service/internal/acorn/config" + "github.com/Interhyp/metadata-service/internal/acorn/controller" + "github.com/Interhyp/metadata-service/internal/acorn/repository" + "github.com/Interhyp/metadata-service/internal/acorn/service" "github.com/Interhyp/metadata-service/internal/repository/bitbucket" "github.com/Interhyp/metadata-service/internal/repository/config" "github.com/Interhyp/metadata-service/internal/repository/hostip" @@ -22,19 +26,50 @@ import ( "github.com/Interhyp/metadata-service/internal/web/controller/servicectl" "github.com/Interhyp/metadata-service/internal/web/controller/webhookctl" "github.com/Interhyp/metadata-service/internal/web/server" - auacorn "github.com/StephanHCB/go-autumn-acorn-registry" + libcontroller "github.com/StephanHCB/go-backend-service-common/acorns/controller" + librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "github.com/StephanHCB/go-backend-service-common/repository/logging" "github.com/StephanHCB/go-backend-service-common/repository/timestamp" "github.com/StephanHCB/go-backend-service-common/repository/vault" "github.com/StephanHCB/go-backend-service-common/web/controller/healthctl" "github.com/StephanHCB/go-backend-service-common/web/controller/swaggerctl" + "time" ) type ApplicationImpl struct { - Server application.Server + // repositories (outgoing connectors) + Config librepo.Configuration + CustomConfig configrepo.CustomConfiguration + Logging librepo.Logging + Vault librepo.Vault + Metadata repository.Metadata + Kafka repository.Kafka + IdentityProvider repository.IdentityProvider + HostIP repository.HostIP + Bitbucket repository.Bitbucket + Timestamp librepo.Timestamp + SshAuthProvider repository.SshAuthProvider + Notifier repository.Notifier + + // services (business logic) + Mapper service.Mapper + Trigger service.Trigger + Updater service.Updater + Cache service.Cache + Owners service.Owners + Services service.Services + Repositories service.Repositories + + // controllers (incoming connectors) + HealthCtl libcontroller.HealthController + SwaggerCtl libcontroller.SwaggerController + OwnerCtl controller.OwnerController + ServiceCtl controller.ServiceController + RepositoryCtl controller.RepositoryController + WebhookCtl controller.WebhookController - registered bool - created bool + // server/web stack + Server application.Server } func New() application.Application { @@ -45,71 +80,39 @@ func (a *ApplicationImpl) IsApplication() bool { return true } -func (a *ApplicationImpl) Register() { - if !a.registered { - // repositories - auacorn.Registry.Register(config.New) - auacorn.Registry.Register(logging.New) - auacorn.Registry.Register(vault.New) - auacorn.Registry.Register(metadata.New) - auacorn.Registry.Register(kafka.New) - auacorn.Registry.Register(idp.New) - auacorn.Registry.Register(hostip.New) - auacorn.Registry.Register(bitbucket.New) - auacorn.Registry.Register(timestamp.New) - auacorn.Registry.Register(sshAuthProvider.New) - auacorn.Registry.Register(notifier.New) - // services - auacorn.Registry.Register(mapper.New) - auacorn.Registry.Register(trigger.New) - auacorn.Registry.Register(updater.New) - auacorn.Registry.Register(cache.New) - auacorn.Registry.Register(owners.New) - auacorn.Registry.Register(services.New) - auacorn.Registry.Register(repositories.New) - // web layer - auacorn.Registry.Register(healthctl.New) - auacorn.Registry.Register(swaggerctl.New) - auacorn.Registry.Register(ownerctl.New) - auacorn.Registry.Register(servicectl.New) - auacorn.Registry.Register(repositoryctl.New) - auacorn.Registry.Register(webhookctl.New) - auacorn.Registry.Register(server.New) - } - a.registered = true -} +func (a *ApplicationImpl) Create() error { + if err := a.ConstructConfigLoggingVaultTimestamp(); err != nil { + return err + } -func (a *ApplicationImpl) Create() { - if !a.created { - auacorn.Registry.Create() + if err := a.ConstructRepositories(); err != nil { + return err } - a.created = true -} -func (a *ApplicationImpl) Assemble() error { - err := auacorn.Registry.Assemble() - if err != nil { + if err := a.ConstructServices(); err != nil { + return err + } + + if err := a.ConstructControllers(); err != nil { return err } - a.Server = auacorn.Registry.GetAcornByName(application.ServerAcornName).(application.Server) return nil } -func (a *ApplicationImpl) Run() int { - a.Register() - a.Create() +func (a *ApplicationImpl) Teardown() { + // reverse order (must ensure correct order yourself, but most components will not have a teardown method) + a.Trigger.Teardown() + a.Kafka.Teardown() + a.Metadata.Teardown() +} - err := a.Assemble() +func (a *ApplicationImpl) Run() int { + err := a.Create() if err != nil { return 10 } - - err = auacorn.Registry.Setup() - defer auacorn.Registry.Teardown() - if err != nil { - return 20 - } + defer a.Teardown() err = a.Server.Run() if err != nil { @@ -118,3 +121,131 @@ func (a *ApplicationImpl) Run() int { return 0 } + +// not part of interface -- exposed for use by tests only + +func (a *ApplicationImpl) ConstructConfigLoggingVaultTimestamp() error { + a.Config, a.CustomConfig = config.New() + a.Logging = logging.NewNoAcorn(a.Config) + a.Vault = vault.NewNoAcorn(a.Config, a.Logging) + if err := a.Config.Assemble(a.Logging); err != nil { + return err + } + a.Logging.Setup() + if err := vault.Execute(a.Vault); err != nil { + return err + } + if err := a.Config.Setup(); err != nil { + return err + } + a.Timestamp = timestamp.NewNoAcorn(time.Now) + return nil +} + +func (a *ApplicationImpl) ConstructRepositories() error { + // construct the components that talk to the external world (must ensure correct order yourself), allowing for test overrides where needed + a.SshAuthProvider = sshAuthProvider.New(a.Config, a.CustomConfig, a.Logging) + if err := a.SshAuthProvider.Setup(); err != nil { + return err + } + + if a.Metadata == nil { + a.Metadata = metadata.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.SshAuthProvider) + } + if err := a.Metadata.Setup(); err != nil { + return err + } + + a.HostIP = hostip.New(a.Logging) + if err := a.HostIP.Setup(); err != nil { + return err + } + + if a.Kafka == nil { + a.Kafka = kafka.New(a.Config, a.CustomConfig, a.Logging, a.HostIP) + } + if err := a.Kafka.Setup(); err != nil { + return err + } + + if a.IdentityProvider == nil { + a.IdentityProvider = idp.New(a.Config, a.CustomConfig, a.Logging) + } + if err := a.IdentityProvider.Setup(); err != nil { + return err + } + + if a.Bitbucket == nil { + a.Bitbucket = bitbucket.New(a.Config, a.Logging, a.Vault) + } + if err := a.Bitbucket.Setup(); err != nil { + return err + } + + a.Notifier = notifier.New(a.Config, a.CustomConfig, a.Logging) + if err := a.Notifier.Setup(); err != nil { + return err + } + + return nil +} + +func (a *ApplicationImpl) ConstructServices() error { + // construct the business logic components(must ensure correct order yourself) + + a.Mapper = mapper.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.Metadata, a.Bitbucket) + if err := a.Mapper.Setup(); err != nil { + return err + } + + a.Cache = cache.New(a.Config, a.Logging, a.Timestamp) + if err := a.Cache.Setup(); err != nil { + return err + } + + a.Updater = updater.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.Kafka, a.Notifier, a.Mapper, a.Cache) + if err := a.Updater.Setup(); err != nil { + return err + } + + a.Trigger = trigger.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.Updater) + if err := a.Trigger.Setup(); err != nil { + return err + } + + a.Owners = owners.New(a.Config, a.Logging, a.Timestamp, a.Cache, a.Updater) + if err := a.Owners.Setup(); err != nil { + return err + } + + a.Repositories = repositories.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.Cache, a.Updater, a.Owners) + if err := a.Repositories.Setup(); err != nil { + return err + } + + a.Services = services.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.Cache, a.Updater, a.Repositories) + if err := a.Services.Setup(); err != nil { + return err + } + + return nil +} + +func (a *ApplicationImpl) ConstructControllers() error { + // construct the components that handle incoming requests (must ensure correct order yourself) + + a.HealthCtl = healthctl.NewNoAcorn() + a.SwaggerCtl = swaggerctl.NewNoAcorn() + a.OwnerCtl = ownerctl.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.Owners) + a.ServiceCtl = servicectl.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.Services) + a.RepositoryCtl = repositoryctl.New(a.Config, a.CustomConfig, a.Logging, a.Timestamp, a.Repositories) + a.WebhookCtl = webhookctl.New(a.Logging, a.Timestamp, a.Updater) + + a.Server = server.New(a.Config, a.CustomConfig, a.Logging, a.IdentityProvider, + a.HealthCtl, a.SwaggerCtl, a.OwnerCtl, a.ServiceCtl, a.RepositoryCtl, a.WebhookCtl) + if err := a.Server.Setup(); err != nil { + return err + } + + return nil +} diff --git a/internal/web/controller/ownerctl/acorn.go b/internal/web/controller/ownerctl/acorn.go deleted file mode 100644 index c151d1f..0000000 --- a/internal/web/controller/ownerctl/acorn.go +++ /dev/null @@ -1,52 +0,0 @@ -package ownerctl - -import ( - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/controller" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (c *Impl) IsOwnerController() bool { - return true -} - -func (c *Impl) AcornName() string { - return controller.OwnerControllerAcornName -} - -func (c *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - c.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - c.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - c.Owners = registry.GetAcornByName(service.OwnersAcornName).(service.Owners) - - c.CustomConfiguration = config.Custom(c.Configuration) - - c.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - - return nil -} - -func (c *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(c.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(c.Owners.(auacornapi.Acorn)) - if err != nil { - return err - } - - return nil -} - -func (c *Impl) TeardownAcorn(_ auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/web/controller/ownerctl/ownerctl.go b/internal/web/controller/ownerctl/ownerctl.go index c8a5a72..027fd4d 100644 --- a/internal/web/controller/ownerctl/ownerctl.go +++ b/internal/web/controller/ownerctl/ownerctl.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/Interhyp/metadata-service/api" "github.com/Interhyp/metadata-service/internal/acorn/config" + "github.com/Interhyp/metadata-service/internal/acorn/controller" "github.com/Interhyp/metadata-service/internal/acorn/service" "github.com/Interhyp/metadata-service/internal/web/util" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" @@ -20,9 +21,28 @@ type Impl struct { Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration Logging librepo.Logging + Timestamp librepo.Timestamp Owners service.Owners +} + +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + owners service.Owners, +) controller.OwnerController { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + Owners: owners, + } +} - Timestamp librepo.Timestamp +func (c *Impl) IsOwnerController() bool { + return true } func (c *Impl) WireUp(_ context.Context, router chi.Router) { diff --git a/internal/web/controller/repositoryctl/acorn.go b/internal/web/controller/repositoryctl/acorn.go deleted file mode 100644 index 59ba02f..0000000 --- a/internal/web/controller/repositoryctl/acorn.go +++ /dev/null @@ -1,52 +0,0 @@ -package repositoryctl - -import ( - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/controller" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (c *Impl) IsRepositoryController() bool { - return true -} - -func (c *Impl) AcornName() string { - return controller.RepositoryControllerAcornName -} - -func (c *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - c.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - c.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - c.Repositories = registry.GetAcornByName(service.RepositoriesAcornName).(service.Repositories) - - c.CustomConfiguration = config.Custom(c.Configuration) - - c.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - - return nil -} - -func (c *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(c.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(c.Repositories.(auacornapi.Acorn)) - if err != nil { - return err - } - - return nil -} - -func (c *Impl) TeardownAcorn(_ auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/web/controller/repositoryctl/repositoryctl.go b/internal/web/controller/repositoryctl/repositoryctl.go index 2ee231d..2afdf30 100644 --- a/internal/web/controller/repositoryctl/repositoryctl.go +++ b/internal/web/controller/repositoryctl/repositoryctl.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/Interhyp/metadata-service/api" "github.com/Interhyp/metadata-service/internal/acorn/config" + "github.com/Interhyp/metadata-service/internal/acorn/controller" "github.com/Interhyp/metadata-service/internal/acorn/service" "github.com/Interhyp/metadata-service/internal/web/util" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" @@ -24,9 +25,28 @@ type Impl struct { Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration Logging librepo.Logging + Timestamp librepo.Timestamp Repositories service.Repositories +} + +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + repositories service.Repositories, +) controller.RepositoryController { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + Repositories: repositories, + } +} - Timestamp librepo.Timestamp +func (c *Impl) IsRepositoryController() bool { + return true } func (c *Impl) WireUp(_ context.Context, router chi.Router) { diff --git a/internal/web/controller/servicectl/acorn.go b/internal/web/controller/servicectl/acorn.go deleted file mode 100644 index deef6e2..0000000 --- a/internal/web/controller/servicectl/acorn.go +++ /dev/null @@ -1,52 +0,0 @@ -package servicectl - -import ( - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/controller" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (c *Impl) IsServiceController() bool { - return true -} - -func (c *Impl) AcornName() string { - return controller.ServiceControllerAcornName -} - -func (c *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - c.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - c.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - c.Services = registry.GetAcornByName(service.ServicesAcornName).(service.Services) - - c.CustomConfiguration = config.Custom(c.Configuration) - - c.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - - return nil -} - -func (c *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(c.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(c.Services.(auacornapi.Acorn)) - if err != nil { - return err - } - - return nil -} - -func (c *Impl) TeardownAcorn(_ auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/web/controller/servicectl/servicectl.go b/internal/web/controller/servicectl/servicectl.go index 2dbda8f..989b0f1 100644 --- a/internal/web/controller/servicectl/servicectl.go +++ b/internal/web/controller/servicectl/servicectl.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/Interhyp/metadata-service/api" "github.com/Interhyp/metadata-service/internal/acorn/config" + "github.com/Interhyp/metadata-service/internal/acorn/controller" "github.com/Interhyp/metadata-service/internal/acorn/service" "net/http" @@ -22,9 +23,28 @@ type Impl struct { Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration Logging librepo.Logging + Timestamp librepo.Timestamp Services service.Services +} + +func New( + configuration librepo.Configuration, + customConfig config.CustomConfiguration, + logging librepo.Logging, + timestamp librepo.Timestamp, + services service.Services, +) controller.ServiceController { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfig, + Logging: logging, + Timestamp: timestamp, + Services: services, + } +} - Timestamp librepo.Timestamp +func (c *Impl) IsServiceController() bool { + return true } func (c *Impl) WireUp(_ context.Context, router chi.Router) { diff --git a/internal/web/controller/webhookctl/acorn.go b/internal/web/controller/webhookctl/acorn.go deleted file mode 100644 index 9833971..0000000 --- a/internal/web/controller/webhookctl/acorn.go +++ /dev/null @@ -1,48 +0,0 @@ -package webhookctl - -import ( - "github.com/Interhyp/metadata-service/internal/acorn/controller" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (c *Impl) IsWebhookController() bool { - return true -} - -func (c *Impl) AcornName() string { - return controller.WebhookControllerAcornName -} - -func (c *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - c.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - c.Updater = registry.GetAcornByName(service.UpdaterAcornName).(service.Updater) - - c.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - - return nil -} - -func (c *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - err := registry.SetupAfter(c.Logging.(auacornapi.Acorn)) - if err != nil { - return err - } - err = registry.SetupAfter(c.Updater.(auacornapi.Acorn)) - if err != nil { - return err - } - - return nil -} - -func (c *Impl) TeardownAcorn(_ auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/web/controller/webhookctl/webhookctl.go b/internal/web/controller/webhookctl/webhookctl.go index 072926a..a60cc21 100644 --- a/internal/web/controller/webhookctl/webhookctl.go +++ b/internal/web/controller/webhookctl/webhookctl.go @@ -2,6 +2,7 @@ package webhookctl import ( "context" + "github.com/Interhyp/metadata-service/internal/acorn/controller" "github.com/Interhyp/metadata-service/internal/acorn/service" "github.com/StephanHCB/go-backend-service-common/web/util/contexthelper" "net/http" @@ -13,10 +14,25 @@ import ( ) type Impl struct { - Logging librepo.Logging - Updater service.Updater - + Logging librepo.Logging Timestamp librepo.Timestamp + Updater service.Updater +} + +func New( + logging librepo.Logging, + timestamp librepo.Timestamp, + updater service.Updater, +) controller.WebhookController { + return &Impl{ + Logging: logging, + Timestamp: timestamp, + Updater: updater, + } +} + +func (c *Impl) IsWebhookController() bool { + return true } func (c *Impl) WireUp(_ context.Context, router chi.Router) { diff --git a/internal/web/server/acorn.go b/internal/web/server/acorn.go deleted file mode 100644 index 6aa4344..0000000 --- a/internal/web/server/acorn.go +++ /dev/null @@ -1,91 +0,0 @@ -package server - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/application" - "github.com/Interhyp/metadata-service/internal/acorn/config" - "github.com/Interhyp/metadata-service/internal/acorn/controller" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - libcontroller "github.com/StephanHCB/go-backend-service-common/acorns/controller" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{ - RequestTimeoutSeconds: 30, - ServerWriteTimeoutSeconds: 10, - ServerIdleTimeoutSeconds: 10, - ServerReadTimeoutSeconds: 10, - } -} - -func (s *Impl) IsServer() bool { - return true -} - -func (s *Impl) AcornName() string { - return application.ServerAcornName -} - -func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) - s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - s.IdentityProvider = registry.GetAcornByName(repository.IdentityProviderAcornName).(repository.IdentityProvider) - s.HealthCtl = registry.GetAcornByName(libcontroller.HealthControllerAcornName).(libcontroller.HealthController) - s.SwaggerCtl = registry.GetAcornByName(libcontroller.SwaggerControllerAcornName).(libcontroller.SwaggerController) - s.OwnerCtl = registry.GetAcornByName(controller.OwnerControllerAcornName).(controller.OwnerController) - s.ServiceCtl = registry.GetAcornByName(controller.ServiceControllerAcornName).(controller.ServiceController) - s.RepositoryCtl = registry.GetAcornByName(controller.RepositoryControllerAcornName).(controller.RepositoryController) - s.WebhookCtl = registry.GetAcornByName(controller.WebhookControllerAcornName).(controller.WebhookController) - return nil -} - -func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - if err := registry.SetupAfter(s.Configuration.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(s.Logging.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(s.IdentityProvider.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(s.HealthCtl.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(s.SwaggerCtl.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(s.OwnerCtl.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(s.ServiceCtl.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(s.RepositoryCtl.(auacornapi.Acorn)); err != nil { - return err - } - if err := registry.SetupAfter(s.WebhookCtl.(auacornapi.Acorn)); err != nil { - return err - } - s.CustomConfiguration = config.Custom(s.Configuration) - s.RequestTimeoutSeconds = 60 - s.ServerReadTimeoutSeconds = 60 - s.ServerWriteTimeoutSeconds = 60 - s.ServerIdleTimeoutSeconds = 60 - - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - s.WireUp(ctx) - - s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up primary web layer") - return nil -} - -func (s *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/internal/web/server/server.go b/internal/web/server/server.go index e2ba2b6..48f96e7 100644 --- a/internal/web/server/server.go +++ b/internal/web/server/server.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/Interhyp/metadata-service/internal/acorn/application" "github.com/Interhyp/metadata-service/internal/acorn/config" "github.com/Interhyp/metadata-service/internal/acorn/controller" "github.com/Interhyp/metadata-service/internal/acorn/repository" @@ -24,9 +25,9 @@ import ( ) type Impl struct { - Logging librepo.Logging Configuration librepo.Configuration CustomConfiguration config.CustomConfiguration + Logging librepo.Logging IdentityProvider repository.IdentityProvider HealthCtl libcontroller.HealthController SwaggerCtl libcontroller.SwaggerController @@ -43,6 +44,50 @@ type Impl struct { ServerIdleTimeoutSeconds int } +func New( + configuration librepo.Configuration, + customConfiguration config.CustomConfiguration, + logging librepo.Logging, + identityProvider repository.IdentityProvider, + healthCtl libcontroller.HealthController, + swaggerCtl libcontroller.SwaggerController, + ownerCtl controller.OwnerController, + serviceCtl controller.ServiceController, + repositoryCtl controller.RepositoryController, + webhookCtl controller.WebhookController, +) application.Server { + return &Impl{ + Configuration: configuration, + CustomConfiguration: customConfiguration, + Logging: logging, + IdentityProvider: identityProvider, + HealthCtl: healthCtl, + SwaggerCtl: swaggerCtl, + OwnerCtl: ownerCtl, + ServiceCtl: serviceCtl, + RepositoryCtl: repositoryCtl, + WebhookCtl: webhookCtl, + + RequestTimeoutSeconds: 60, + ServerWriteTimeoutSeconds: 60, + ServerIdleTimeoutSeconds: 60, + ServerReadTimeoutSeconds: 60, + } +} + +func (s *Impl) IsServer() bool { + return true +} + +func (s *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + s.WireUp(ctx) + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up primary web layer") + return nil +} + func (s *Impl) WireUp(ctx context.Context) { if s.Router == nil { s.Logging.Logger().Ctx(ctx).Info().Print("creating router and setting up filter chain") diff --git a/test/acceptance/startup_acc_test.go b/test/acceptance/startup_acc_test.go index dd3168f..b26d0b1 100644 --- a/test/acceptance/startup_acc_test.go +++ b/test/acceptance/startup_acc_test.go @@ -1,13 +1,6 @@ package acceptance import ( - "github.com/Interhyp/metadata-service/internal/acorn/controller" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/Interhyp/metadata-service/internal/web/app" - auacorn "github.com/StephanHCB/go-autumn-acorn-registry" - libcontroller "github.com/StephanHCB/go-backend-service-common/acorns/controller" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "github.com/StephanHCB/go-backend-service-common/docs" "github.com/stretchr/testify/require" "net/http" @@ -20,31 +13,30 @@ func TestStartup_ShouldBeHealthy(t *testing.T) { docs.When("When the application is started") docs.Then("Then all components are present and of the correct type") - appImpl := application.(*app.ApplicationImpl) - registry := auacorn.Registry.(*auacorn.AcornRegistryImpl) - require.NotNil(t, registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration)) - require.NotNil(t, registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging)) - require.NotNil(t, registry.GetAcornByName(librepo.VaultAcornName).(librepo.Vault)) - require.NotNil(t, registry.GetAcornByName(repository.KafkaAcornName).(repository.Kafka)) - require.NotNil(t, registry.GetAcornByName(repository.MetadataAcornName).(repository.Metadata)) - require.NotNil(t, registry.GetAcornByName(repository.HostIPAcornName).(repository.HostIP)) - - require.NotNil(t, registry.GetAcornByName(service.CacheAcornName).(service.Cache)) - require.NotNil(t, registry.GetAcornByName(service.MapperAcornName).(service.Mapper)) - require.NotNil(t, registry.GetAcornByName(service.TriggerAcornName).(service.Trigger)) - require.NotNil(t, registry.GetAcornByName(service.UpdaterAcornName).(service.Updater)) - require.NotNil(t, registry.GetAcornByName(service.OwnersAcornName).(service.Owners)) - require.NotNil(t, registry.GetAcornByName(service.ServicesAcornName).(service.Services)) - require.NotNil(t, registry.GetAcornByName(service.RepositoriesAcornName).(service.Repositories)) - - require.NotNil(t, registry.GetAcornByName(libcontroller.HealthControllerAcornName).(libcontroller.HealthController)) - require.NotNil(t, registry.GetAcornByName(libcontroller.SwaggerControllerAcornName).(libcontroller.SwaggerController)) - require.NotNil(t, registry.GetAcornByName(controller.OwnerControllerAcornName).(controller.OwnerController)) - require.NotNil(t, registry.GetAcornByName(controller.ServiceControllerAcornName).(controller.ServiceController)) - require.NotNil(t, registry.GetAcornByName(controller.RepositoryControllerAcornName).(controller.RepositoryController)) - require.NotNil(t, registry.GetAcornByName(controller.WebhookControllerAcornName).(controller.WebhookController)) - - require.NotNil(t, appImpl.Server) + require.NotNil(t, application.Config) + require.NotNil(t, application.CustomConfig) + require.NotNil(t, application.Logging) + require.NotNil(t, application.Vault) + require.NotNil(t, application.Kafka) + require.NotNil(t, application.Metadata) + require.NotNil(t, application.HostIP) + + require.NotNil(t, application.Cache) + require.NotNil(t, application.Mapper) + require.NotNil(t, application.Trigger) + require.NotNil(t, application.Updater) + require.NotNil(t, application.Owners) + require.NotNil(t, application.Services) + require.NotNil(t, application.Repositories) + + require.NotNil(t, application.HealthCtl) + require.NotNil(t, application.SwaggerCtl) + require.NotNil(t, application.OwnerCtl) + require.NotNil(t, application.ServiceCtl) + require.NotNil(t, application.RepositoryCtl) + require.NotNil(t, application.WebhookCtl) + + require.NotNil(t, application.Server) docs.Then("And the application reports as healthy") response, err := tstPerformGet("/management/health", tstUnauthenticated()) diff --git a/test/acceptance/util_setup_test.go b/test/acceptance/util_setup_test.go index a51d618..9da9b34 100644 --- a/test/acceptance/util_setup_test.go +++ b/test/acceptance/util_setup_test.go @@ -3,14 +3,9 @@ package acceptance import ( "context" "github.com/Interhyp/metadata-service/api" - application2 "github.com/Interhyp/metadata-service/internal/acorn/application" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/Interhyp/metadata-service/internal/acorn/service" "github.com/Interhyp/metadata-service/internal/repository/config" "github.com/Interhyp/metadata-service/internal/repository/notifier" - "github.com/Interhyp/metadata-service/internal/service/mapper" "github.com/Interhyp/metadata-service/internal/service/trigger" - "github.com/Interhyp/metadata-service/internal/service/updater" "github.com/Interhyp/metadata-service/internal/web/app" "github.com/Interhyp/metadata-service/internal/web/server" "github.com/Interhyp/metadata-service/test/mock/bitbucketmock" @@ -19,11 +14,10 @@ import ( "github.com/Interhyp/metadata-service/test/mock/metadatamock" "github.com/Interhyp/metadata-service/test/mock/notifiermock" "github.com/Interhyp/metadata-service/test/mock/vaultmock" - auacorn "github.com/StephanHCB/go-autumn-acorn-registry" auconfigenv "github.com/StephanHCB/go-autumn-config-env" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" libconfig "github.com/StephanHCB/go-backend-service-common/repository/config" "github.com/StephanHCB/go-backend-service-common/repository/logging" + "github.com/StephanHCB/go-backend-service-common/repository/timestamp" "github.com/StephanHCB/go-backend-service-common/web/middleware/security" "github.com/rs/zerolog/log" "net/http/httptest" @@ -32,19 +26,24 @@ import ( // placing these here because they are package global +type ApplicationWithMocksImpl struct { + app.ApplicationImpl +} + var ( ts *httptest.Server - configImpl *libconfig.ConfigImpl - loggingImpl *logging.LoggingImpl - vaultImpl *vaultmock.VaultImpl - metadataImpl *metadatamock.Impl - kafkaImpl *kafkamock.Impl - idpImpl *idpmock.Impl - bbImpl *bitbucketmock.BitbucketMock - notifierImpl *notifier.Impl - - application application2.Application + configImpl *libconfig.ConfigImpl + customConfigImpl *config.CustomConfigImpl + loggingImpl *logging.LoggingImpl + vaultImpl *vaultmock.VaultImpl + metadataImpl *metadatamock.Impl + kafkaImpl *kafkamock.Impl + idpImpl *idpmock.Impl + bbImpl *bitbucketmock.BitbucketMock + notifierImpl *notifier.Impl + + application *ApplicationWithMocksImpl appCtx context.Context ) @@ -54,66 +53,74 @@ func fakeNow() time.Time { return time.Date(2022, 11, 6, 18, 14, 10, 0, time.UTC) } +func (a *ApplicationWithMocksImpl) Create() error { + a.ConstructConfigLoggingVaultTimestamp_ForTesting() + + // prefill mocks as overrides + a.Metadata = metadataImpl + a.Kafka = kafkaImpl + a.IdentityProvider = idpImpl + a.Bitbucket = bbImpl + + // now can use normal construct functions, they respect the prefilled mocks + if err := a.ConstructRepositories(); err != nil { + return err + } + if err := a.ConstructServices(); err != nil { + return err + } + if err := a.ConstructControllers(); err != nil { + return err + } + + return nil +} + +func (a *ApplicationWithMocksImpl) ConstructConfigLoggingVaultTimestamp_ForTesting() { + // construct and set up config, logging, vault, timestamp + a.Config = configImpl + a.CustomConfig = customConfigImpl + a.Logging = loggingImpl + a.Vault = vaultImpl + a.Timestamp = timestamp.NewNoAcorn(fakeNow) +} + +func (a *ApplicationWithMocksImpl) Teardown() { + // reverse order (must ensure correct order yourself, but most components will not have a teardown method) + a.Trigger.Teardown() + a.Kafka.Teardown() + a.Metadata.Teardown() +} + // use a special configuration and wire in mocks for most repositories func tstSetup(configPath string) error { - application = app.New() + application = &ApplicationWithMocksImpl{} err := tstSetupConfig(configPath) if err != nil { return err } tstSetupLogging() + vaultImpl = vaultmock.New().(*vaultmock.VaultImpl) metadataImpl = metadatamock.New().(*metadatamock.Impl) kafkaImpl = kafkamock.New().(*kafkamock.Impl) idpImpl = idpmock.New().(*idpmock.Impl) bbImpl = bitbucketmock.New().(*bitbucketmock.BitbucketMock) - application.Register() - - application.Create() - // can now manipulate the registry by inserting custom instances - registry := auacorn.Registry.(*auacorn.AcornRegistryImpl) - registry.CreateOverride(librepo.ConfigurationAcornName, configImpl) - registry.CreateOverride(librepo.LoggingAcornName, loggingImpl) - registry.CreateOverride(librepo.VaultAcornName, vaultImpl) - registry.CreateOverride(repository.MetadataAcornName, metadataImpl) - registry.CreateOverride(repository.KafkaAcornName, kafkaImpl) - registry.CreateOverride(repository.IdentityProviderAcornName, idpImpl) - registry.CreateOverride(repository.BitbucketAcornName, bbImpl) - - registry.SkipAssemble(loggingImpl) // already assembled - registry.SkipAssemble(configImpl) // would attempt to read config - err = application.Assemble() + metadataImpl.Now = fakeNow + + err = application.Create() if err != nil { return err } - // other features that need switching off or changing + application.Trigger.(*trigger.Impl).SkipStart = true // do not start cron job - timestamp := registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp) - timestamp.MockResponse(fakeNow) - - triggerImpl := registry.GetAcornByName(service.TriggerAcornName).(*trigger.Impl) - triggerImpl.SkipStart = true // do not start cron job - triggerImpl.Now = fakeNow - - mapperImpl := registry.GetAcornByName(service.MapperAcornName).(*mapper.Impl) - mapperImpl.Now = fakeNow - - updaterImpl := registry.GetAcornByName(service.UpdaterAcornName).(*updater.Impl) - updaterImpl.Now = fakeNow - - notifierImpl = registry.GetAcornByName(repository.NotifierAcornName).(*notifier.Impl) + notifierImpl = application.Notifier.(*notifier.Impl) notifierImpl.SkipAsync = true - metadataImpl.Now = fakeNow - security.Now = fakeNow - registry.SkipSetup(loggingImpl) - registry.SkipSetup(configImpl) - registry.Setup() - for identifier, _ := range notifierImpl.Clients { notifierImpl.Clients[identifier] = ¬ifiermock.NotifierClientMock{SentNotifications: make([]openapi.Notification, 0)} } @@ -123,7 +130,9 @@ func tstSetup(configPath string) error { } func tstSetupConfig(configPath string) error { - configImpl = config.New().(*libconfig.ConfigImpl) + impl, cImpl := config.New() + configImpl = impl.(*libconfig.ConfigImpl) + customConfigImpl = cImpl.(*config.CustomConfigImpl) auconfigenv.LocalConfigFileName = configPath err := configImpl.Read() if err != nil { @@ -148,8 +157,8 @@ func tstSetupLogging() { } func tstSetupHttpTestServer() { - application.(*app.ApplicationImpl).Server.WireUp(appCtx) - ts = httptest.NewServer(application.(*app.ApplicationImpl).Server.(*server.Impl).Router) + application.Server.WireUp(appCtx) + ts = httptest.NewServer(application.Server.(*server.Impl).Router) } func tstShutdown() { diff --git a/test/mock/bbclientmock/bbclientmock.go b/test/mock/bbclientmock/bbclientmock.go index 6046a25..6640c8d 100644 --- a/test/mock/bbclientmock/bbclientmock.go +++ b/test/mock/bbclientmock/bbclientmock.go @@ -36,5 +36,5 @@ func (m *BitbucketClientMock) GetBitbucketUser(ctx context.Context, username str } func (m *BitbucketClientMock) Setup() error { - panic("implement me") + return nil } diff --git a/test/mock/bitbucketmock/bitbucketmock.go b/test/mock/bitbucketmock/bitbucketmock.go index cc9995a..59304e0 100644 --- a/test/mock/bitbucketmock/bitbucketmock.go +++ b/test/mock/bitbucketmock/bitbucketmock.go @@ -3,7 +3,6 @@ package bitbucketmock import ( "context" "github.com/Interhyp/metadata-service/internal/acorn/repository" - auacornapi "github.com/StephanHCB/go-autumn-acorn-registry/api" "github.com/pkg/errors" ) @@ -12,35 +11,19 @@ const FILTER_FAILED_USERNAME = "filterfailedusername" type BitbucketMock struct { } -func New() auacornapi.Acorn { +func New() repository.Bitbucket { return &BitbucketMock{} } -// implement acorn - -func (b *BitbucketMock) AcornName() string { - return repository.BitbucketAcornName -} - -func (b *BitbucketMock) AssembleAcorn(registry auacornapi.AcornRegistry) error { - return nil -} - -func (b *BitbucketMock) SetupAcorn(registry auacornapi.AcornRegistry) error { - return nil +func (b *BitbucketMock) IsBitbucket() bool { + return true } -func (b *BitbucketMock) TeardownAcorn(registry auacornapi.AcornRegistry) error { +func (b *BitbucketMock) Setup() error { return nil } -// implement bitbucket interface - -func (b *BitbucketMock) IsBitbucket() bool { - return true -} - -func (b *BitbucketMock) Setup(ctx context.Context) error { +func (b *BitbucketMock) SetupClient(ctx context.Context) error { return nil } diff --git a/test/mock/cachemock/cachemock.go b/test/mock/cachemock/cachemock.go index f49cc6d..928d45c 100644 --- a/test/mock/cachemock/cachemock.go +++ b/test/mock/cachemock/cachemock.go @@ -12,6 +12,10 @@ func (s *Mock) IsCache() bool { return true } +func (s *Mock) Setup() error { + return nil +} + func (s *Mock) SetOwnerListTimestamp(ctx context.Context, timestamp string) { } diff --git a/test/mock/idpmock/acorn.go b/test/mock/idpmock/acorn.go deleted file mode 100644 index 80ff57b..0000000 --- a/test/mock/idpmock/acorn.go +++ /dev/null @@ -1,32 +0,0 @@ -package idpmock - -import ( - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/StephanHCB/go-autumn-acorn-registry/api" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{} -} - -func (r *Impl) IsIdentityProvider() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.IdentityProviderAcornName -} - -func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - return nil -} - -func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - return nil -} - -func (r *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/test/mock/idpmock/idp.go b/test/mock/idpmock/idp.go index 6978ab7..ad74214 100644 --- a/test/mock/idpmock/idp.go +++ b/test/mock/idpmock/idp.go @@ -2,11 +2,20 @@ package idpmock import ( "context" + "github.com/Interhyp/metadata-service/internal/acorn/repository" ) import _ "github.com/go-git/go-git/v5" type Impl struct{} +func New() repository.IdentityProvider { + return &Impl{} +} + +func (r *Impl) IsIdentityProvider() bool { + return true +} + // We created a keyset and some tokens using jwt.io. Use this keyset ONLY for automated tests! // public key that can verify our testing tokens @@ -33,7 +42,11 @@ mwIDAQXX -----END PUBLIC KEY----- ` -func (r *Impl) Setup(ctx context.Context) error { +func (r *Impl) Setup() error { + return nil +} + +func (r *Impl) SetupConnector(ctx context.Context) error { return nil } diff --git a/test/mock/kafkamock/acorn.go b/test/mock/kafkamock/acorn.go deleted file mode 100644 index 8c84924..0000000 --- a/test/mock/kafkamock/acorn.go +++ /dev/null @@ -1,35 +0,0 @@ -package kafkamock - -import ( - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/StephanHCB/go-autumn-acorn-registry/api" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{ - Callback: func(_ repository.UpdateEvent) {}, - Recording: make([]repository.UpdateEvent, 0), - } -} - -func (r *Impl) IsKafka() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.KafkaAcornName -} - -func (r *Impl) AssembleAcorn(_ auacornapi.AcornRegistry) error { - return nil -} - -func (r *Impl) SetupAcorn(_ auacornapi.AcornRegistry) error { - return nil -} - -func (r *Impl) TeardownAcorn(_ auacornapi.AcornRegistry) error { - return nil -} diff --git a/test/mock/kafkamock/kafka.go b/test/mock/kafkamock/kafka.go index 490bf12..b0686e7 100644 --- a/test/mock/kafkamock/kafka.go +++ b/test/mock/kafkamock/kafka.go @@ -12,6 +12,24 @@ type Impl struct { Recording []repository.UpdateEvent } +func New() repository.Kafka { + return &Impl{ + Callback: func(_ repository.UpdateEvent) {}, + Recording: make([]repository.UpdateEvent, 0), + } +} + +func (r *Impl) IsKafka() bool { + return true +} + +func (r *Impl) Setup() error { + return nil +} + +func (r *Impl) Teardown() { +} + func (r *Impl) SubscribeIncoming(_ context.Context, callback repository.ReceiverCallback) error { r.Callback = callback return nil diff --git a/test/mock/metadatamock/acorn.go b/test/mock/metadatamock/acorn.go deleted file mode 100644 index a458b3d..0000000 --- a/test/mock/metadatamock/acorn.go +++ /dev/null @@ -1,42 +0,0 @@ -package metadatamock - -import ( - "context" - "github.com/Interhyp/metadata-service/internal/acorn/repository" - "github.com/StephanHCB/go-autumn-acorn-registry/api" - auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" - "time" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &Impl{ - Now: time.Now, - } -} - -func (r *Impl) IsMetadata() bool { - return true -} - -func (r *Impl) AcornName() string { - return repository.MetadataAcornName -} - -func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - return nil -} - -func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { - ctx := auzerolog.AddLoggerToCtx(context.Background()) - - if err := r.Clone(ctx); err != nil { - return err - } - return nil -} - -func (r *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/test/mock/metadatamock/metadata.go b/test/mock/metadatamock/metadata.go index 3a3e4ad..30e83ea 100644 --- a/test/mock/metadatamock/metadata.go +++ b/test/mock/metadatamock/metadata.go @@ -3,6 +3,7 @@ package metadatamock import ( "context" "errors" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" "io" "os" "time" @@ -29,6 +30,28 @@ type Impl struct { SimulateUnchangedFailure bool } +func New() repository.Metadata { + return &Impl{ + Now: time.Now, + } +} + +func (r *Impl) Setup() error { + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := r.Clone(ctx); err != nil { + return err + } + return nil +} + +func (r *Impl) Teardown() { +} + +func (r *Impl) IsMetadata() bool { + return true +} + const ownerInfo = `contact: somebody@some-organisation.com teamsChannelURL: https://teams.microsoft.com/l/channel/somechannel productOwner: kschlangenheldt diff --git a/test/mock/sshauthprovidermock/sshauthprovidermock.go b/test/mock/sshauthprovidermock/sshauthprovidermock.go index 9ffeaae..0d8aef2 100644 --- a/test/mock/sshauthprovidermock/sshauthprovidermock.go +++ b/test/mock/sshauthprovidermock/sshauthprovidermock.go @@ -13,7 +13,11 @@ func (this *SshAuthProviderMock) IsSshAuthProvider() bool { return true } -func (this *SshAuthProviderMock) Setup(_ context.Context) error { +func (this *SshAuthProviderMock) Setup() error { + return nil +} + +func (this *SshAuthProviderMock) SetupProvider(ctx context.Context) error { return nil } diff --git a/test/mock/vaultmock/acorn.go b/test/mock/vaultmock/acorn.go deleted file mode 100644 index 3b6e06c..0000000 --- a/test/mock/vaultmock/acorn.go +++ /dev/null @@ -1,32 +0,0 @@ -package vaultmock - -import ( - "github.com/StephanHCB/go-autumn-acorn-registry/api" - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" -) - -// --- implementing Acorn --- - -func New() auacornapi.Acorn { - return &VaultImpl{} -} - -func (v *VaultImpl) IsVault() bool { - return true -} - -func (v *VaultImpl) AcornName() string { - return librepo.VaultAcornName -} - -func (v *VaultImpl) AssembleAcorn(registry auacornapi.AcornRegistry) error { - return nil -} - -func (v *VaultImpl) SetupAcorn(registry auacornapi.AcornRegistry) error { - return nil -} - -func (v *VaultImpl) TeardownAcorn(registry auacornapi.AcornRegistry) error { - return nil -} diff --git a/test/mock/vaultmock/vault.go b/test/mock/vaultmock/vault.go index 9157bdb..d515abe 100644 --- a/test/mock/vaultmock/vault.go +++ b/test/mock/vaultmock/vault.go @@ -2,11 +2,24 @@ package vaultmock import ( "context" + librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" ) type VaultImpl struct { } +func New() librepo.Vault { + return &VaultImpl{} +} + +func (v *VaultImpl) IsVault() bool { + return true +} + +func (v *VaultImpl) Execute() error { + return nil +} + func (v *VaultImpl) Setup(ctx context.Context) error { return nil }