orchestrator

package module
v1.7.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 29, 2026 License: EUPL-1.2 Imports: 12 Imported by: 0

README


entur/go-orchestrator

Go-Orchestrator is intended as a simple-to-use SDK for writing Sub-Orchestrators at Entur, as specified by the Platform Orchestrator specification. It is written in Golang, and contains predefined type declarations, jsonschema validation rules, handler versioning, and mockers to make it as easy as possible to safely implement your dream Sub-Orchestrator.

Quickstart

Install

go get github.com/entur/go-orchestrator
go mod tidy

Import

import (
	"github.com/entur/go-logging"
	"github.com/entur/go-orchestrator"
)

Basic Usage

import (
	"os"
	"context"
	"fmt"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/entur/go-logging"
	"github.com/entur/go-orchestrator"
)


// -----------------------
// Initialize Cloud Function
// -----------------------

func init() {
	// Read Config!
	functionEntrypoint := os.Getenv("FUNCTION_ENTRYPOINT")

	// Setup Sub-Orchestrator!
	mh := NewMyMinimalManifestHandler()
	so := NewMyMinimalSubOrch(mh)

	// Start Cloud Function!
	h := orchestrator.NewCloudEventHandler(so)
	functions.CloudEvent(functionEntrypoint, h)
}

// -----------------------
// Sub-Orchestrator
// -----------------------

type MyMinimalSubOrch struct {
	handlers  []orchestrator.ManifestHandler
}

func (so *MyMinimalSubOrch) Handlers() []orchestrator.ManifestHandler {
	return so.handlers
}

func NewMyMinimalSubOrch(handlers ...orchestrator.ManifestHandler) *MyMinimalSubOrch {
	return &MyMinimalSubOrch{
		handlers:  handlers,
	}
}

// -----------------------
// Sub-Orchestrator Manifest Handlers
// -----------------------

// Your Manifest Definition
type MyMinimalManifest struct {
	orchestrator.ManifestHeader
	Metadata MyMinimalManifestMetadata `json:"metadata"`
	Spec     MyMinimalManifestSpec     `json:"spec"`
}

type MyMinimalManifestMetadata = orchestrator.ManifestMetadata // Default metadata definition, but you can use your own

type MyMinimalManifestSpec struct {
	Your   string   `json:"your"`
	Values []string `json:"values"`
	Here   int      `json:"here"`
}

// Your Manifest Handler
type MyMinimalManifestHandler struct{}

func (h *MyMinimalManifestHandler) APIVersion() orchestrator.APIVersion {
	return "orchestrator.entur.io/MyMinimalSubOrch/v1" // Which Manifest version this handler operates on
}

func (h *MyMinimalManifestHandler) Kind() orchestrator.Kind {
	return "MyMinimalManifest" // Which Manifest Kind this handler operates on
}

func (h *MyMinimalManifestHandler) Plan(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	return fmt.Errorf("plan not implemented")
}

func (h *MyMinimalManifestHandler) PlanDestroy(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	return fmt.Errorf("plan_destroy not implemented")
}

func (h *MyMinimalManifestHandler) Apply(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	return fmt.Errorf("apply not implemented")
}

func (h *MyMinimalManifestHandler) Destroy(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	return fmt.Errorf("destroy not implemented")
}

func NewMyMinimalManifestHandler() *MyMinimalManifestHandler {
	return &MyMinimalManifestHandler{}
}

Overview and Architecture

General Interfaces

The two most important types in this SDK are the Orchestrator and ManifestHandler interfaces.

An Orchestrator operates in a set google project, and has a set of ManifestHandlers that can work on manifests with a given pair of apiVersion and kind. This enables your orchestrator to handle v1 and v2 of a given kind, and of course multiple differing kinds.

The Orchestrator interface is as follows:

type Orchestrator interface {
	Handlers() []ManifestHandler // The manifests this orchestrator can handle
}

The ManifestHandler interface is as follows:

type ManifestHandler interface {
	APIVersion() APIVersion // Which APIVersion this handler operates on
	Kind() Kind             // Which Kind this handler operates on
	// Actions
	Plan(context.Context, Request, *Result) error
	PlanDestroy(context.Context, Request, *Result) error
	Apply(context.Context, Request, *Result) error
	Destroy(context.Context, Request, *Result) error
}

Middleware

It is possible to define middlewares that will run before or after Plan/Apply/PlanDestroy/Destroy actions. These can be defined at the Sub-Orchestrator level, or in the ManifestHandler:

The Middleware interface definitions are as follows:

type MiddlewareBefore interface {
	MiddlewareBefore(context.Context, Request, *Result) error
}

type MiddlewareAfter interface {
	MiddlewareAfter(context.Context, Request, *Result) error
}

The order in which middlewares will be run is as follows:

  1. Sub-Orchestrator MiddlewareBefore (if defined)
  2. ManifestHandler MiddlewareBefore (if defined)
  3. ManifestHandler Plan/PlanDestroy/Apply/Destroy
  4. ManifestHandler MiddlewareAfter (if defined)
  5. Sub-Orchestrator MiddlewareAfter (if defined)

Note: Handlers will short-circuit if an internal error occurs at any point in the flow. Note2: The Action Handler (Plan/PlanDestroy/Apply/Destroy) will be skipped if a user failure occurs in one of the previous handlers. The remaining Middleware handlers will still be run.

Handling Internal Errors

During the processing of a Platform Orchestrator Request in a Sub-Orchestrator, unexpected internal errors might occur that should prevent any further processing from taking place. That being later in the function itself, or in a later middleware handler. To handle such errors appropriately, the error should be returned immediately from the handler where it originated, such that the Go-Orchestrator SDK can log the event, and report an "An internal error occurred" to the user.


func ErrorGeneratingFunction() error {
	return fmt.Errorf("this is an internal error")
}

// PR OUTPUT:
// An internal error occurred. Please refer to the documentation for support
func (h *Handler) Plan(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	err := ErrorGeneratingFunction()
	if err != nil {
		return err // The internal error is not shown to the end-user, only logged. The user will instead see a generic "An internal error occurred" message
	}

	// We don't want to reach here

	return nil
}

Note: Returning an error will stop any further processing from occurring in later handlers. Note2: User failures are not to be handled as internal errors, and should not return an error value!

Handling User Errors

During the processing of a Platform Orchestrator Request in a Sub-Orchestrator, all unauthorized or invalid events (e.g. manifests containing invalid values) should result in a understandable failure message that is reported to the end-user. To handle such failures approriately, the end result should be marked as having failed using the r.Fail() method with a informative message. Later processing steps should also be skipped by returning a nil value. Failing to return a nil value, will result in the error being handled as an internal error instead.


// PR OUTPUT:
// Invalid manifest:
// json: cannot unmarshal array into Go struct field
func (h *Handler) Plan(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	var manifest MyManifest
	
	err := json.Unmarshal(req.Manifest.New, &manifest)
	if err != nil {
		r.Fail(fmt.Sprintf("Invalid manifest:\n%s", err.Error())) // The message which the end-user sees in the PR comment.
		return nil
	}

	// We don't want to reach here if the manifest is invalid

	return nil
}

Note: Marking a result as having failed will stop later Plan/Apply/PlanDestroy/Destroy actions from processing, but not Middleware handlers. I.e. marking a plan action's result with Fail in a MiddlewareBefore() handler will stop the Plan() handler from running, but any MiddleWareAfter() handlers. You can check the current state of a result by calling r.Locked() and r.Code()

Handling User Planned and Applied Changes

During the processing of a Platform Orchestrator Request in a Sub-Orchestrator, all planned and/or applied changes made in response the action and manifest contents should be grouped into create, update, or delete changesets. This can be done using the using the r.Create(), r.Update() and r.Delete() methods. Changes can either be represented as basic string types, or objects matching the Stringer/Change interface - i.e. types implementing a String() string method. The context of what a change might represent internally, will vary between Sub-Orchestrators. When all changes have been submitted, the final result should be marked as having succeeded using r.Succeed() with an informative summary. If a result is marked as having succeeded, but no changes have been added to the result, the final result code will be a noop as described in the Platform Orchestrator specification.


type MyManifest struct {
	orchestrator.ManifestHeader
	Metadata MyManifestMetadata `json:"metadata"`
	Spec     MyManifestSpec     `json:"spec"`
}

type MyManifestMetadata = orchestrator.ManifestMetadata // Default metadata definition, but you can use your own

type MyManifestSpec struct {
	Environment   string   `json:"clubName"`
}

type AdvancedChange struct {
	Plan TerraformPlan
}

func (change AdvancedChange) String() string {
	return fmt.Sprintf("%d Terraform resources", change.Plan.NumberOfResources)
}

// PR OUTPUT:
// Applying the following changes to the GCP application 'project-id':
// 
// Create:
// + Grafana dashboards
// + 36 Terraform resources
func (h *Handler) Apply(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	var manifest MyManifest
	
	err := json.Unmarshal(req.Manifest.New, &manifest)
	if err != nil {
		return nil
	}

	// Some terraform logic

	plan := Terraform.Plan(manifest.Spec.Environment)

	// End of terraform logic

	r.Create("Grafana dashboards")
	r.Create(AdvancedChange{
		Plan: plan,
	})

	r.Succeed(fmt.Sprintf("Applying the following changes to the GCP application '%s':", manifest.Metadata.ID)
	return nil
}

Note: If a result containing no changes (I.e.r.Create(), r.Update() and r.Delete() have not been called) is marked as having succeeded r.Succeed(), the final result code will be a noop.

Run tests

This project makes use of Example tests. To run them, simply use use the following command

go test ./...

Examples

Interested in seeing how a Sub-Orchestrator might be implemented in practice? Take a look at the following examples and be inspired:

  • See ./examples/minimal_suborchestrator for a minimal sub-orchestrator implementation with tests.
  • See ./examples/advanced_suborchestrator for an advanced sub-orchestrator implementation with tests.

Documentation

Overview

Example
package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/entur/go-logging"
	"github.com/entur/go-orchestrator"
	"github.com/entur/go-orchestrator/oresources"
)

type ExampleSpecV1 struct {
	Name string `json:"name"`
}

type ExampleMetadataV1 struct {
	ID string `json:"id"`
}

type ExampleManifestV1 struct {
	orchestrator.ManifestHeader
	Metadata ExampleMetadataV1 `json:"metadata"`
	Spec     ExampleSpecV1     `json:"spec"`
}

type ExampleManifestV1Handler struct {
	/* you can have some internal state here */
}

func (h *ExampleManifestV1Handler) APIVersion() orchestrator.APIVersion {
	return "orchestrator.entur.io/example/v1"
}

func (h *ExampleManifestV1Handler) Kind() orchestrator.Kind {
	return "Example"
}

func (h *ExampleManifestV1Handler) MiddlewareBefore(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	logger := logging.Ctx(ctx)

	logger.Info().Msg("After Orchestrator middleware executes, but before manifest handler executes")

	return nil
}

func (h *ExampleManifestV1Handler) Plan(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	var manifest ExampleManifestV1
	err := json.Unmarshal(req.Manifest.New, &manifest)
	if err != nil {
		return err
	}

	r.Create("A thing")
	r.Update("A thing")
	r.Delete("A thing")
	r.Succeed("Plan all the things")
	return nil
}

func (h *ExampleManifestV1Handler) PlanDestroy(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	return fmt.Errorf("plandestroy not implemented")
}

func (h *ExampleManifestV1Handler) Apply(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	var manifest ExampleManifestV1
	err := json.Unmarshal(req.Manifest.New, &manifest)
	if err != nil {
		return err
	}

	r.Create("A thing")
	r.Update("A thing")
	r.Delete("A thing")
	r.Succeed("Plan all the things")
	return nil
}

func (h *ExampleManifestV1Handler) Destroy(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	return fmt.Errorf("destroy not implemented")
}

type ExampleSO struct {
	/* you can have some internal state here */
	projectID string
	handlers  []orchestrator.ManifestHandler
}

func (so *ExampleSO) ProjectID() string {
	return so.projectID
}

func (so *ExampleSO) Handlers() []orchestrator.ManifestHandler {
	return so.handlers
}

func (so *ExampleSO) MiddlewareBefore(ctx context.Context, req orchestrator.Request, r *orchestrator.Result) error {
	logger := logging.Ctx(ctx)

	logger.Info().Msg("Before it begins")
	if req.Origin.Repository.Visibility != orchestrator.RepositoryVisbilityPublic {
		r.Fail("This sub-orchestrator only accepts manifests in public repositories")
		return nil
	}

	if req.Sender.Type == orchestrator.SenderTypeUser {
		logger.Info().Msg("#####")
		client, err := oresources.NewIAMLookupClient(ctx, req.Resources.IAMLookup.URL)
		if err != nil {
			return err
		}

		access, err := client.GCPUserHasRoleInProjects(ctx, req.Sender.Email, "your_so_role", "ent-someproject-dev")
		if err != nil {
			return err
		}

		if !access {
			r.Fail("You don't have access to ent-someproject-dev")
			return nil
		}
	}

	// The cache is shared between middlewares and handlers!
	cache := orchestrator.Ctx(ctx)
	cache.Set("cache_key", "something something!")

	return nil
}

func (so ExampleSO) MiddlewareAfter(ctx context.Context, _ orchestrator.Request, res *orchestrator.Result) error {
	logger := logging.Ctx(ctx)
	logger.Info().Msg("Auditing this thing")

	cache := orchestrator.Ctx(ctx)
	value := cache.Get("cache_key")
	if str, ok := value.(string); ok {
		logger.Info().Msgf("Got value from cache: %s", str)
	}

	logger.Info().Msg("After it's done")
	return nil
}

func NewExampleSO(projectID string) *ExampleSO {
	return &ExampleSO{
		projectID: projectID,
		handlers: []orchestrator.ManifestHandler{
			&ExampleManifestV1Handler{},
		},
	}
}

// -----------------------
// Complex Sub-Orchestrator Example
// -----------------------

func main() {
	logger := logging.New(
		logging.WithNoCaller(),
		logging.WithLevel(logging.DebugLevel),
		logging.WithWriter(
			logging.NewConsoleWriter(
				logging.WithNoColor(),
				logging.WithNoTimestamp(),
			),
		),
	)

	iamServer, _ := oresources.NewMockIAMLookupServer(
		oresources.WithPort(8001),
		oresources.WithUserProjectRoles(
			orchestrator.DefaultMockUserEmail,
			"ent-someproject-dev",
			[]string{"your_so_role"},
		),
	)

	err := iamServer.Start()
	if err != nil {
		logger.Panic().Err(err).Send()
	}
	defer func() {
		err := iamServer.Stop()
		if err != nil {
			logger.Panic().Err(err).Send()
		}
	}()

	so := NewExampleSO("mysoproject")
	handler := orchestrator.NewCloudEventHandler(so,
		orchestrator.WithCustomLogger(logger),
		orchestrator.WithCustomPubSubClient(nil),
	)

	manifest := ExampleManifestV1{
		ManifestHeader: orchestrator.ManifestHeader{
			APIVersion: so.handlers[0].APIVersion(),
			Kind:       so.handlers[0].Kind(),
		},
		Spec: ExampleSpecV1{
			Name: "Test Name",
		},
		Metadata: ExampleMetadataV1{
			ID: "manifestid",
		},
	}
	e, _ := orchestrator.NewMockCloudEvent(manifest, orchestrator.WithIAMEndpoint(iamServer.URL()))

	err = handler(context.Background(), *e)
	if err != nil {
		logger.Error().Err(err).Msg("Encountered error")
	}
	// The following output is expected and verified in tests:

}
Output:
DBG Created a new CloudEventHandler
DBG Processing request gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request={"action":"plan","apiVersion":"orchestrator.entur.io/request/v1","manifest":{"new":{"apiVersion":"orchestrator.entur.io/example/v1","kind":"Example","metadata":{"id":"manifestid"},"spec":{"name":"Test Name"}},"old":null},"metadata":{"contextId":"mockid","requestId":"mockid"},"origin":{"fileChanges":{"bloblUrl":"","contentsUrl":"","rawUrl":""},"fileName":"","pullRequest":{"body":"","htmlUrl":"","id":0,"labels":null,"number":0,"ref":"","state":"open","title":""},"repository":{"defaultBranch":"main","fullName":"entur/mockrepo","htmlUrl":"","id":0,"name":"mockrepo","visibility":"public"}},"resources":{"iamLookup":{"url":"http://localhost:8001"}},"responseTopic":"mocktopic","sender":{"githubEmail":"mockuser@entur.io","githubId":0,"githubLogin":"mockuser","githubRepositoryPermission":"admin","type":"user"}} gorch_request_id=mockid
DBG Found ManifestHandler (orchestrator.entur.io/example/v1, Example) gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
DBG Executing Orchestrator MiddlewareBefore gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
INF Before it begins gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
INF ##### gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
DBG Unable to discover idtoken credentials, defaulting to http.Client for IAMLookup gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
DBG Executing ManifestHandler MiddlewareBefore (orchestrator.entur.io/example/v1, Example, plan) gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
INF After Orchestrator middleware executes, but before manifest handler executes gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
DBG Executing ManifestHandler (orchestrator.entur.io/example/v1, Example, plan) gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
DBG Executing Orchestrator MiddlewareAfter gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
INF Auditing this thing gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
INF Got value from cache: something something! gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
INF After it's done gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid
WRN Pubsub client is set to null, no responses will be sent gorch_action=plan gorch_context_id=mockid gorch_file_name= gorch_github_user_id=0 gorch_request_id=mockid gorch_result_creations=[{}] gorch_result_deletions=[{}] gorch_result_summary="Plan all the things" gorch_result_updates=[{}]

Index

Examples

Constants

View Source
const DefaultMockAction = ActionPlan // Default User action used in PO request mocks.
View Source
const DefaultMockContextID = "mockid" // Default Context ID used in PO request mocks.
View Source
const DefaultMockDefaultBranch = "main" // Default Repository branch used in PO request mocks.
View Source
const DefaultMockPullRequestState = PullRequestStateOpen // Default Pull Request state used in PO request mocks.
View Source
const DefaultMockRepositoryFullName = "entur/mockrepo" // Default Repository full name used in PO request mocks.
View Source
const DefaultMockRepositoryName = "mockrepo" // Default Repository name used in PO request mocks.
View Source
const DefaultMockRepositoryVisibility = RepositoryVisbilityPublic // Default Repository visibility used in PO request mocks.
View Source
const DefaultMockRequestID = "mockid" // Default Request ID used in PO request mocks.
View Source
const DefaultMockResponseTopic = "mocktopic" // Default Topic ID used in PO request mocks.
View Source
const DefaultMockSenderType = SenderTypeUser // Default Repository branch used in PO request mocks.
View Source
const DefaultMockUserEmail = "mockuser@entur.io" // Default verified user email used in PO request mocks.
View Source
const DefaultMockUserPermission = RepositoryPermissionAdmin // Default Repository permissions used in PO request mocks.
View Source
const DefaultMockUsername = "mockuser" // Default Github username used in PO request mocks.

Variables

This section is empty.

Functions

func NewCloudEventHandler added in v1.5.0

func NewCloudEventHandler(so Orchestrator, opts ...HandlerOption) func(context.Context, cloudevent.Event) error

func NewMockCloudEvent added in v1.5.0

func NewMockCloudEvent(manifest any, opts ...MockRequestOption) (*cloudevent.Event, error)

func UnmarshalCloudEvent added in v1.5.0

func UnmarshalCloudEvent(e cloudevent.Event, v any) error

Types

type APIVersion added in v1.5.0

type APIVersion string // Platform Orchestrator / Sub-Orchestrator APIVersion
const (
	APIVersionOrchestratorResponseV1 APIVersion = "orchestrator.entur.io/request/v1"  // Platform Orchestrator Request
	APIVersionOrchestratorRequestV1  APIVersion = "orchestrator.entur.io/response/v1" // Platform Orchestrator Response
)

type Action

type Action string
const (
	ActionApply       Action = "apply"
	ActionPlan        Action = "plan"
	ActionPlanDestroy Action = "plan_destroy"
	ActionDestroy     Action = "destroy"
)

type Change added in v1.5.0

type Change interface {
	String() string
}

The Change interface represents a planned/applied change in the context of a sub-orchestrator.

type CloudEventData added in v1.5.0

type CloudEventData struct {
	Subscription string
	Message      PubSubMessage
}

type ContextCache added in v1.5.0

type ContextCache struct {
	// contains filtered or unexported fields
}

func Ctx added in v1.5.0

func Ctx(ctx context.Context) ContextCache

Retrieve the value cache attached to the current request context

func (ContextCache) Get added in v1.5.0

func (c ContextCache) Get(key string) any

func (ContextCache) Set added in v1.5.0

func (c ContextCache) Set(key string, value any)

type FileChanges added in v1.5.0

type FileChanges struct {
	ContentsURL string `json:"contentsUrl"`
	BlobURL     string `json:"bloblUrl"`
	RawURL      string `json:"rawUrl"`
}

type HandlerConfig added in v1.2.0

type HandlerConfig struct {
	// contains filtered or unexported fields
}

type HandlerOption added in v1.2.0

type HandlerOption func(*HandlerConfig)

func WithCustomLogger added in v1.1.0

func WithCustomLogger(logger zerolog.Logger) HandlerOption

func WithCustomPubSubClient added in v1.5.0

func WithCustomPubSubClient(client *pubsub.Client) HandlerOption

type Kind

type Kind string // Sub-Orchestrator Manifest Kind

type Manifest

type Manifest = json.RawMessage

type ManifestHandler

type ManifestHandler interface {
	// Which APIVersion and Kind this handler operates on
	APIVersion() APIVersion
	Kind() Kind
	// Actions
	Plan(context.Context, Request, *Result) error
	PlanDestroy(context.Context, Request, *Result) error
	Apply(context.Context, Request, *Result) error
	Destroy(context.Context, Request, *Result) error
}

The ManifestHandler interface represents the logic used for handling a specific APIVersion and Kind.

type ManifestHeader

type ManifestHeader struct {
	APIVersion APIVersion `json:"apiVersion" jsonschema:"required,minLength=1,maxLength=2083,pattern=^orchestrator\\.entur\\.io\\/.*\\/[vV].*$"` // 'orchestrator.entur.io/mysuborchestrator/v1'
	Kind       Kind       `json:"kind" jsonschema:"required,minLength=2,maxLength=63"`                                                           // 'mymanifestkind'
}

type ManifestMetadata added in v1.7.0

type ManifestMetadata struct {
	ID          string  `json:"id" jsonschema:"required,minLength=1,maxLength=63"`
	Name        *string `json:"name"`
	DisplayName *string `json:"displayName"`
	Description *string `json:"description"`
	Owner       *string `json:"owner"`
}

type Manifests

type Manifests struct {
	Old *Manifest `json:"old"`
	New Manifest  `json:"new"`
}

type MiddlewareAfter added in v1.3.0

type MiddlewareAfter interface {
	MiddlewareAfter(context.Context, Request, *Result) error
}

The MiddlewareAfter interface represents the middleware running after every manifest event and/or a specific handler.

type MiddlewareBefore added in v1.3.0

type MiddlewareBefore interface {
	MiddlewareBefore(context.Context, Request, *Result) error
}

The MiddlewareBefore interface represents the middleware running before every manifest event and/or a specific handler.

type MockRequestOption added in v1.3.0

type MockRequestOption func(*Request)

func WithAction added in v1.5.0

func WithAction(action Action) MockRequestOption

func WithIAMEndpoint added in v1.5.0

func WithIAMEndpoint(url string) MockRequestOption

func WithSender added in v1.5.0

func WithSender(sender Sender) MockRequestOption

func WithVisibility added in v1.7.2

func WithVisibility(visbility RepositoryVisibility) MockRequestOption

type Orchestrator

type Orchestrator interface {
	Handlers() []ManifestHandler // The manifests this orchestrator can handle
}

The Orchestrator interface represents the main configuration of a sub-orchestrator in a Project.

type Origin

type Origin struct {
	FileName    string      `json:"fileName"`
	Repository  Repository  `json:"repository"` // 'https://github.com/entur/some-repo'
	FileChanges FileChanges `json:"fileChanges"`
	PullRequest PullRequest `json:"pullRequest"`
}

type PubSubMessage added in v1.1.0

type PubSubMessage struct {
	ID          string                  `json:"messageId"`
	PublishTime string                  `json:"publishTime"`
	Attributes  PubSubMessageAttributes `json:"attributes"`
	Data        []byte                  `json:"data"`
}

type PubSubMessageAttributes added in v1.1.0

type PubSubMessageAttributes struct{}

type PullRequest added in v1.5.0

type PullRequest struct {
	ID      int              `json:"id"`    // '123123145'
	State   PullRequestState `json:"state"` // 'open'
	Ref     string           `json:"ref"`
	Title   string           `json:"title"` // 'chore: Added .entur manifests'
	Body    string           `json:"body"`
	Number  int              `json:"number"`
	Labels  []string         `json:"labels"`
	HtmlURL string           `json:"htmlUrl"`
}

type PullRequestState added in v1.5.0

type PullRequestState string
const (
	PullRequestStateOpen   PullRequestState = "open"
	PullRequestStateClosed PullRequestState = "closed"
)

type Repository added in v1.5.0

type Repository struct {
	ID            int                  `json:"id"`            // '123123145'
	Name          string               `json:"name"`          // 'some-remo'
	FullName      string               `json:"fullName"`      // 'entur/some-repo'
	DefaultBranch string               `json:"defaultBranch"` // 'main'
	HtmlURL       string               `json:"htmlUrl"`       // 'https://github.com/entur/some-repo'
	Visibility    RepositoryVisibility `json:"visibility"`    // 'public'
}

type RepositoryPermission added in v1.5.0

type RepositoryPermission string
const (
	RepositoryPermissionAdmin    RepositoryPermission = "admin"
	RepositoryPermissionMaintain RepositoryPermission = "maintain"
	RepositoryPermissionWrite    RepositoryPermission = "write"
	RepositoryPermissionTriage   RepositoryPermission = "triage"
	RepositoryPermissionRead     RepositoryPermission = "read"
)

type RepositoryVisibility added in v1.5.0

type RepositoryVisibility string
const (
	RepositoryVisbilityPublic   RepositoryVisibility = "public"
	RepositoryVisbilityInternal RepositoryVisibility = "internal"
	RepositoryVisbilityPrivate  RepositoryVisibility = "private"
)

type Request

type Request struct {
	Action        Action          `json:"action"`
	APIVersion    APIVersion      `json:"apiVersion"` // 'orchestrator.entur.io/request/v1'
	Manifest      Manifests       `json:"manifest"`
	Metadata      RequestMetadata `json:"metadata"`
	Resources     Resources       `json:"resources"`
	Origin        Origin          `json:"origin"`
	Sender        Sender          `json:"sender"`
	ResponseTopic string          `json:"responseTopic"`
}

func NewMockRequest added in v1.3.0

func NewMockRequest(manifest any, opts ...MockRequestOption) (*Request, error)

type RequestMetadata added in v1.7.0

type RequestMetadata struct {
	RequestID string `json:"requestId"` // Request ID specified by Platform Orchestrator used to track the user request
	ContextID string `json:"contextId"` // Context ID specified by Platform Orchestrator used to track the user request
}

type Resource

type Resource struct {
	URL string `json:"url"` // 'https://eu-west1.cloudfunctions.net/someresource'
}

type ResourceIAMLookup

type ResourceIAMLookup = Resource

type Resources

type Resources struct {
	IAMLookup ResourceIAMLookup `json:"iamLookup"`
}

type Response

type Response struct {
	APIVersion APIVersion      `json:"apiVersion"` // 'orchestrator.entur.io/response/v1'
	Metadata   RequestMetadata `json:"metadata"`
	ResultCode ResultCode      `json:"result"` // 'success'
	Output     string          `json:"output"`
}

type Result

type Result struct {
	// contains filtered or unexported fields
}

func Process added in v1.1.0

func Process(ctx context.Context, so Orchestrator, req *Request) *Result

func (*Result) Code

func (r *Result) Code() ResultCode

Get the final result code.

func (*Result) Create

func (r *Result) Create(changes ...any)

Add a new 'create' change to the result. Valid change types are: * string * Stringer/Change interface * Slices/Arrays containing Stringer/Change interfaces

func (*Result) Creations

func (r *Result) Creations() []Change

Get all current 'create' changes.

func (*Result) Delete

func (r *Result) Delete(changes ...any)

Add a new 'delete' change to the result. Valid change types are: * string * Stringer/Change interface * Slices/Arrays containing Stringer/Change interfaces

func (*Result) Deletions

func (r *Result) Deletions() []Change

Get all current 'delete' changes.

func (*Result) Errors added in v1.5.0

func (r *Result) Errors() []error

Get all errors that have accumulated.

func (*Result) Fail added in v1.5.0

func (r *Result) Fail(summary string)

Mark the result as having failed.

func (*Result) Locked added in v1.5.0

func (r *Result) Locked() bool

Is the result locked for any further changes.

func (*Result) Output added in v1.5.0

func (r *Result) Output() string

Get the final result string output.

func (*Result) Succeed added in v1.5.0

func (r *Result) Succeed(summary string)

Mark the result as having succeeded.

func (*Result) Update

func (r *Result) Update(changes ...any)

Add a new 'update' change to the result. Valid change types are: * string * Stringer/Change interface * Slices/Arrays containing Stringer/Change interfaces

func (*Result) Updates

func (r *Result) Updates() []Change

Get all current 'update' changes.

type ResultCode

type ResultCode string
const (
	ResultCodeSuccess ResultCode = "success" // Sub-Orchestrator succeeded in processing the action
	ResultCodeFailure ResultCode = "failure" // Sub-Orchestrator detected a user failure when processing the action
	ResultCodeNoop    ResultCode = "noop"    // Sub-Orchestrator detected no changes after processing the action
	ResultCodeError   ResultCode = "error"   // Sub-Orchestrator experienced an internal error when processing the action
)

type Sender

type Sender struct {
	Username   string               `json:"githubLogin"` // 'mockuser'
	Email      string               `json:"githubEmail"` // 'mockuser@entur.org'
	ID         int                  `json:"githubId"`
	Permission RepositoryPermission `json:"githubRepositoryPermission"` // 'admin'
	Type       SenderType           `json:"type"`                       // 'user'
}

type SenderType

type SenderType string
const (
	SenderTypeUser SenderType = "user" // Github user
	SenderTypeBot  SenderType = "bot"  //
)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL