pkger

package
v2.0.0-rc.2 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2020 License: MIT Imports: 45 Imported by: 0

README

Pkger: the What and How

Responsibilities

  • Translating a declarative package file (either JSON | Yaml | Jsonnet) into resources in the platform
  • Exporting existing resources in the form of a pkg (either JSON | Yaml)
  • Managing the state of a pkg's side effects via a stack

Anatomy of a package

A package is a collection of resource configurations. These resource configurations can be seen in full in the pkger/testdata directory. The package itself does not have any state. Packages may contain resources that are uniquely identifiable within the platform and some that are not. If it is desired to use packages in a gitops scenario or in a manner that requires all resources are not duplicated, you will want to explore using a stack.

Properties of package files:

  • A package's resources are unique by a combination kind and metadata.name fields
  • A package guarantees that all resources within a package is applied consistently
    • the pkger service manages all state management concerns
  • A package does not have any state tracked without a stack
  • A package may consist of multiple packages where all uniqueness and state guarantees apply
Stacks

A stack is a stateful entity for which packages can be applied and managed. A stack uses a combination of a resource's kind and metadata.name fields to uniquely identify a resource inside a package and map that to state in the platform. Via this state, a stack provides the ability to apply a package idempotently. Stack's manage the full lifecyle of a package's resources, including creating, updating, and deleting resources.

Packages may contain resources that are not uniquely identifiable within the platform. For instance, a dashboard resource, does not have any unique identifier within the platform beyond its UUID. A stack uses the metadata.name field to uniquely identify a resource inside a package and map that to state in the platform.

Stacks will manage the following use cases:

We create a stack without any URLs to packages, henceforth identified as S1:

# S1 package - initial
kind: Label
metadata:
	name: lucid_einstein
spec:
	name: label_1
---
kind: Bucket
metadta: 
	name: pristine_noir
spec: 
	name: bucket_1
	association:
	 	- kind: Label
		   name: lucid_einstein
---
kind: Dashboard
metadata:
	name: charmed_saratoba
spec:
	name: dash_1
	association:
	 	- kind: Label
		   name: lucid_einstein
  1. The S1 package (seen above) with all new resources is applied

    • Side effects: all resources are created and a record of all resources (id, res type, etc) is added to the S1 stack record

      Stack Record
       {
         "stack_id": S1_UUID,
         "createdAt": CreatedAtTimestamp,
         "updatedAt": CreatedAtTimestamp,
         "config": {},
         "resources": [
           {
             "kind": "Label",
             "id": LABEL_UUID,
             "pkgName": "lucid_einstein"
           },
           {
             "kind": "Bucket",
             "id": BUCKET_UUID,
             "pkgName": "pristine_noir",
             "associations": [
               {
                 "kind": "Label",
                 "pkgName": "lucid_einstein"
               }
             ]
           },
           {
             "kind": "Dashboard",
             "id": DASHBOARD_UUID,
             "pkgName": "charmed_saratoba",
             "associations": [
               {
                 "kind": "Label",
                 "pkgName": "lucid_einstein"
               }
             ]
           }
         ]
       }  
      
  2. Same S1 package (seen above) is reapplied with no changes from step 1

    • Side effects: nothing, no changes

      Stack Record
        {
          "stack_id": S1_UUID,
          "createdAt": CreatedAtTimestamp,
          "updatedAt": CreatedAtTimestamp,
          "config": {},
          "resources": [
            {
              "kind": "Label",
              "id": LABEL_UUID,
              "pkgName": "lucid_einstein"
            },
            {
              "kind": "Bucket",
              "id": BUCKET_UUID,
              "pkgName": "pristine_noir",
              "associations": [
                {
                  "kind": "Label",
                  "pkgName": "lucid_einstein"
                }
              ]
            },
            {
              "kind": "Dashboard",
              "id": DASHBOARD_UUID,
              "pkgName": "charmed_saratoba",
              "associations": [
                {
                  "kind": "Label",
                  "pkgName": "lucid_einstein"
                }
              ]
            }
          ]
        }  
      


# S1 package - updated label name
kind: Label
metadata:
	name: lucid_einstein
spec:
	name: cool label name  #<<<<<< THIS NAME CHANGES
---
kind: Bucket
metadta: 
	name: pristine_noir
# snip - no changes
---
kind: Dashboard
metadata:
	name: charmed_saratoba
# snip - no changes
  1. The S1 package is applied with an update to the label resource

    • Side effects: platform label (LABEL_UUID) is renamed and updatedAt field in S1 record is updated

      Stack Record
      {
           "stack_id": S1_UUID,
           "createdAt": CreatedAtTimestamp,
           "updatedAt": LABEL_UPDATE_TIMESTAMP,
           "config": {},
           "resources": [
             ... snip, all resoruces are same
           ]
      }  
      


# S1 package - new reosource added
kind: Label
metadata:
	name: lucid_einstein
# snip - no change
---
kind: Bucket
metadta: 
	name: pristine_noir
# snip - no changes
---
kind: Dashboard
metadata:
	name: charmed_saratoba
# snip - no changes
---
kind: Task  #<<<<<< THIS RESOURCE IS ADDED
metadata:
	name: alcord_mumphries
spec:
	name: task_1
	association:
	 	- kind: Label
		   name: lucid_einstein
  1. The S1 package is applied with a new resource added

    • Side effects: new task is created and S1 record is updated

      Stack Record
      {
           "stack_id": S1_UUID,
           "createdAt": CreatedAtTimestamp,
           "updatedAt": TASK_ADD_TIMESTAMP,
           "config": {},
           "resources": [
             ... snip, all resoruces from before,
             {
             	"kind": "Task",
             	"id": TASK_UUID,
       				"pkgName": "alcord_mumphries",
               "associations": [
                 {
                   "kind": "Label",
                   "pkgName": "lucid_einstein"
                 }
               ]
             }
           ]
      }  
      


# S1 package - task resource is removed
kind: Label
metadata:
	name: lucid_einstein
# snip - no change
---
kind: Bucket
metadta: 
	name: pristine_noir
# snip - no changes
---
kind: Dashboard
metadata:
	name: charmed_saratoba
# snip - no changes
  1. The S1 package is applied with changes that removes an existing resource
    • Side effects: task is deleted from platform and S1 record is updated

      Stack Record
      {
          "stack_id": S1_UUID,
          "createdAt": CreatedAtTimestamp,
          "updatedAt": TASK_DELETE_TIMESTAMP,
          "config": {},
          "resources": [
            {
             "kind": "Label",
             "id": LABEL_UUID,
             "pkgName": "lucid_einstein"
           },
           {
             "kind": "Bucket",
             "id": BUCKET_UUID,
             "pkgName": "pristine_noir",
             "associations": [
               {
                 "kind": "Label",
                 "pkgName": "lucid_einstein"
               }
             ]
           },
           {
             "kind": "Dashboard",
             "id": DASHBOARD_UUID,
             "pkgName": "charmed_saratoba",
             "associations": [
               {
                 "kind": "Label",
                 "pkgName": "lucid_einstein"
               }
             ]
           }
          ]
      }  
      


# S1 package - label and associations to it are removed
kind: Bucket
metadta: 
	name: pristine_noir
spec: 
	name: bucket_1
---
kind: Dashboard
metadata:
	name: charmed_saratoba
spec:
	name: dash_1
  1. The S1 package is apllied with label and associations to that label removed
    • Side effects: label and all label assocations for that label are removed from the platform and S1 record is updated

      Stack Record
      {
          "stack_id": S1_UUID,
          "createdAt": CreatedAtTimestamp,
          "updatedAt": Label_DELETE_TIMESTAMP,
          "config": {},
          "resources": [
           {
             "kind": "Bucket",
             "id": BUCKET_UUID,
             "pkgName": "pristine_noir",
             "associations": []
           },
           {
             "kind": "Dashboard",
             "id": DASHBOARD_UUID,
             "pkgName": "charmed_saratoba",
             "associations": []
           }
          ]
      }  
      

From package to platform resources

There are 3 main building blocks that take a package and make the declarative package a reality. The following is a quick overview of the system that manages packages.

  1. Parser - parses package
    • informs the user of all validation errors in their package
    • enforces metadata.name field uniqueness constraint
  2. Service - all the business logic for managing packages
    • handles all state management concerns, including making the entire package applied
    • in case of failure to apply a package, the service guarantees the resoruces are returned to their existing state (if any) before the package was applied
  3. HTTP API / CLI - means for user to submit packges to be applied
    • provides the ability to export existing resources as a package, dry run a package, and apply a package
    • all CLI calls go through the HTTP API the same way a user generated request would
Parser internals

The parser converts a package in any of the supported encoding types (JSON|Yaml|Jsonnet), and turns it into a package model. The parser handles the following:

  • enforces naming uniqueness by metadata.name
  • split loop refactoring
  • returns ALL errors in validation with ability to turn off error checking via validation opts
  • trivial to extend to support different encoding types (JSON|Yaml|Jsonnet)

You can explore more the goary details here.

Service internals

The service manages all intracommunication to other services and encapsulates the rules for the package domain. The pkger service depends on every service that we currently sans write and query services. Details of the service dependencies can be found here:

type Service struct {
	log *zap.Logger

	// internal dependencies
	applyReqLimit int
	idGen         influxdb.IDGenerator
	store         Store
	timeGen       influxdb.TimeGenerator

	// external service dependencies
	bucketSVC   influxdb.BucketService
	checkSVC    influxdb.CheckService
	dashSVC     influxdb.DashboardService
	labelSVC    influxdb.LabelService
	endpointSVC influxdb.NotificationEndpointService
	orgSVC      influxdb.OrganizationService
	ruleSVC     influxdb.NotificationRuleStore
	secretSVC   influxdb.SecretService
	taskSVC     influxdb.TaskService
	teleSVC     influxdb.TelegrafConfigStore
	varSVC      influxdb.VariableService
}

The behavior of the servcie includes the following:

  1. Dry run a package
  2. Apply a package
  3. Export a package
  4. Initialize a stack

The following sections explore this behavior further.

Dry run a package

When a package is submitted for a dry run the service takes the contents of that package and identifies the impact of its application before it is run. This is similar to terraform plan.

This command is a convenient way to check whether the package matches your expectations without making any changes to real resources. For example, a dry run might be run before committing a change to version control, to create confidence that it will behave as expected.

A dry run requires that the package to be dry run has been parsed and graphed. If it has not, the dry run will do so before it attempts the dry run functionality. When a dry run is executed, the caller will have returned a summary of the package and a detailed diff of the impact of the package were it to be applied.

The package summary is as follows:

type Summary struct {
	Buckets               []SummaryBucket               `json:"buckets"`
	Checks                []SummaryCheck                `json:"checks"`
	Dashboards            []SummaryDashboard            `json:"dashboards"`
	NotificationEndpoints []SummaryNotificationEndpoint `json:"notificationEndpoints"`
	NotificationRules     []SummaryNotificationRule     `json:"notificationRules"`
	Labels                []SummaryLabel                `json:"labels"`
	LabelMappings         []SummaryLabelMapping         `json:"labelMappings"`
	MissingEnvs           []string                      `json:"missingEnvRefs"`
	MissingSecrets        []string                      `json:"missingSecrets"`
	Tasks                 []SummaryTask                 `json:"summaryTask"`
	TelegrafConfigs       []SummaryTelegraf             `json:"telegrafConfigs"`
	Variables             []SummaryVariable             `json:"variables"`
}

type SummaryBucket struct {
	ID          SafeID `json:"id,omitempty"`
	OrgID       SafeID `json:"orgID,omitempty"`
	Name        string `json:"name"`
	Description string `json:"description"`
	// TODO: return retention rules?
	RetentionPeriod   time.Duration  `json:"retentionPeriod"`
	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

// snip other resources

The package diff is as follows:

type Diff struct {
	Buckets               []DiffBucket               `json:"buckets"`
	Checks                []DiffCheck                `json:"checks"`
	Dashboards            []DiffDashboard            `json:"dashboards"`
	Labels                []DiffLabel                `json:"labels"`
	LabelMappings         []DiffLabelMapping         `json:"labelMappings"`
	NotificationEndpoints []DiffNotificationEndpoint `json:"notificationEndpoints"`
	NotificationRules     []DiffNotificationRule     `json:"notificationRules"`
	Tasks                 []DiffTask                 `json:"tasks"`
	Telegrafs             []DiffTelegraf             `json:"telegrafConfigs"`
	Variables             []DiffVariable             `json:"variables"`
}

// DiffBucketValues are the varying values for a bucket.
type DiffBucketValues struct {
	Description    string         `json:"description"`
	RetentionRules retentionRules `json:"retentionRules"`
}

// DiffBucket is a diff of an individual bucket.
type DiffBucket struct {
	ID   SafeID            `json:"id"`
	Name string            `json:"name"`
	New  DiffBucketValues  `json:"new"`
	Old  *DiffBucketValues `json:"old,omitempty"` // using omitempty here to signal there was no prev state with a nil
}

// snip other resources

If errors are encountered in the parsing, the dry run will return errors in addition to the package summary and diff.

Apply a package

When a package is submitted to be applied, the service takes the contents of that package and identifies the impact of its application before it is run (Dry Run). It then brings the platform to the desired state of the package.

Apply is used to apply the changes required to reach the desired state of the package

If a package had not been verified by a dry run when applying, it will be done to identify existing state within the platform. This existing state has to be maintained to account for an unexpected event that stops the package from being applied. The side effects created from the application will all be rolled back at this point. If a resource was newly created during the application, it will be removed. For a resource that existed in the platform, it will be returned to its state from before the application took place. The guarantee of state consistency is a best attempt. It is not bullet proof. However, a user can reapply the package and arrive at their desired state therafter. Upon successful application of a package, a summary will be provided to the user.

The service takes advantage of split loop refactoring to break the package up by resource. The platform requires certain dependencies be met before a resource is created. For instance, when a label mapping is desired for a new label and bucket, it forces us to guarantee the label exists before creating the label mapping. To accomplish this, labels are always applied first. You can see it in action here:

func (s *Service) Apply(ctx context.Context, orgID, userID influxdb.ID, pkg *Pkg, opts ...ApplyOptFn) (sum Summary, e error) {
	// snipping preceding code

	coordinator := &rollbackCoordinator{sem: make(chan struct{}, s.applyReqLimit)}
	defer coordinator.rollback(s.log, &e, orgID)

	// each grouping here runs for its entirety, then returns an error that
	// is indicative of running all appliers provided. For instance, the labels
	// may have 1 variable fail and one of the buckets fails. The errors aggregate so
	// the caller will be informed of both the failed label variable the failed bucket.
	// the groupings here allow for steps to occur before exiting. The first step is
	// adding the dependencies, resources that are associated by other resources. Then the
	// primary resources. Here we get all the errors associated with them.
	// If those are all good, then we run the secondary(dependent) resources which
	// rely on the primary resources having been created.
	appliers := [][]applier{
		{
			// adds secrets that are referenced it the pkg, this allows user to
			// provide data that does not rest in the pkg.
			s.applySecrets(opt.MissingSecrets),
		},
		{
			// deps for primary resources
			s.applyLabels(pkg.labels()),
		},
		{
			// primary resources, can have relationships to labels
			s.applyVariables(pkg.variables()),
			s.applyBuckets(pkg.buckets()),
			s.applyChecks(pkg.checks()),
			s.applyDashboards(pkg.dashboards()),
			s.applyNotificationEndpoints(pkg.notificationEndpoints()),
			s.applyTasks(pkg.tasks()),
			s.applyTelegrafs(pkg.telegrafs()),
		},
	}

	for _, group := range appliers {
		if err := coordinator.runTilEnd(ctx, orgID, userID, group...); err != nil {
			return Summary{}, internalErr(err)
		}
	}

	// snipping succeeding code

	return pkg.Summary(), nil
}

Looking at the above you may have noticed we have groups of appliers. The second group contains the label resources. Each group's individual resources are applied concurrently. The coordinator.runTilEnd(ctx, orgID, userID, group...) call takes the group, and fans out all the state changes and processes them concurrently for writes. The label resources are guaranteed to have succeeded before processing the primary resources which can have relationships with the label.

When an issue is encountered that cannot be recovered from, and error is returned, and upon seeing that error we roll back all changes. The defer coordinator.rollback(s.log, &e, orgID) line rollsback all resources to their prexisting state. For a more in depth look at that check out here.

Exporting existing resources as a package

If a user has put a lot of effort in creating dashboards, notifications, and telegraf configs, we have the ability for them to export that work in the shape of a package :-). This enables them to both share that work within the community or their org, and also source control the changes to dashboards.

Resources can be exported all at once, via the export by organization, by specific resource IDs, a combination of the above, and advanced filtering (i.e. by label name or resource type). You can read up more on the export options here.

Each resouce that is exported is assigned a uniq metadata.name entry. The names are generated and are not strictly required to remain in that shape. If a user decides to use metadata.name as the name of the resource, they are free to do so. The only requirement is that within a package every resource type has a unique metadata.name per its type. For example each resource kind metadata.name field should have be unique amongst all resources of the same kind within a package.

Each label should have a unique metadata.name field amongst all labels in the package.

Initializing a stack

When creating a stack we create an stub stack record that contains all the metadata about that stack. Optionally, a user may set URLs in the stack config. These URLs may be used to apply packages from a remote location (i.e. S3 bucket). A stack looks like the following:

type (
	// Stack is an identifier for stateful application of a package(s). This stack
	// will map created resources from the pkg(s) to existing resources on the
	// platform. This stack is updated only after side effects of applying a pkg.
	// If the pkg is applied, and no changes are had, then the stack is not updated.
	Stack struct {
		ID        influxdb.ID
		OrgID     influxdb.ID
		Name      string
		Desc      string
		URLs      []url.URL
		Resources []StackResource

		influxdb.CRUDLog
	}

	// StackResource is a record for an individual resource side effect genereated from
	// applying a pkg.
	StackResource struct {
		APIVersion string
		ID         influxdb.ID
		Kind       Kind
		Name       string
	}
)

Documentation

Overview

Package pkger implements a means to create and consume reusable templates for what will eventually come to support all influxdb resources.

The parser supports JSON, Jsonnet, and YAML encodings as well as a number of different ways to read the file/reader/string as it may.

As an example, you can use the following to parse and validate a YAML file and see a summary of its contents:

newTemplate, err := Parse(EncodingYAML, FromFile(PATH_TO_FILE))
if err != nil {
	panic(err) // handle error as you see fit
}
sum := newTemplate.Summary()
fmt.Println(sum) // do something with the summary

The parser will validate all contents of the template and provide any and all fields/entries that failed validation.

If you wish to use the Template type in your transport layer and let the the transport layer manage the decoding, then you can run the following to validate the template after the raw decoding is done:

if err := template.Validate(); err != nil {
	panic(err) // handle error as you see fit
}

If a validation error is encountered during the validation or parsing then the error returned will be of type *parseErr. The parseErr provides a rich set of validations failures. There can be numerous failures in a template and we did our best to inform the caller about them all in a single run.

If you want to see the effects of a template before applying it to the organization's influxdb platform, you have the flexibility to dry run the template and see the outcome of what would happen after it were to be applied. You may use the following to dry run a template within your organization:

svc := NewService(serviceOpts...)
summary, diff, err := svc.DryRun(ctx, orgID, userID, ApplyWithTemplate(template))
if err != nil {
	panic(err) // handle error as you see fit
}
// explore the summary and diff

The diff provided here is a diff of the existing state of the platform for your organization and the concluding the state after the application of a template. All buckets, labels, and variables, when given a name that already exists, will not create a new resource, but rather, will edit the existing resource. If this is not a desired result, then rename your bucket to something else to avoid the imposed changes applying this template would incur. The summary provided is a summary of the template itself. If a resource exists all IDs will be populated for them, if they do not, then they will be zero values. Any zero value ID is safe to assume is not populated. All influxdb.ID's must be non zero to be in existence.

If you would like to apply a template you may use the service to do so. The following will apply the template in full to the provided organization.

svc := NewService(serviceOpts...)
summary, err := svc.Apply(ctx, orgID, userID, ApplyWithTemplate(template))
if err != nil {
	panic(err) // handle error as you see fit
}
// explore the summary

The summary will be populated with valid IDs that were created during the application of the template. If an error is encountered during the application of a template, then all changes that had occurred will be rolled back. However, as a warning for buckets, changes may have incurred destructive changes. The changes are not applied inside a large transaction, for numerous reasons, but it is something to be considered. If you have dry run the template before it is to be applied, then the changes should have been made known to you. If not, then there is potential loss of data if the changes to a bucket resulted in the retention period being shortened in the template.

If you would like to export existing resources into the form of a template, then you have the ability to do so using the following:

resourcesToClone := []ResourceToClone{
	{
		Kind: KindBucket,
		ID:   Existing_BUCKET_ID,
		Name: "new bucket name"
	},
	{
		Kind: KindDashboard,
		ID:   Existing_Dashboard_ID,
	},
	{
		Kind: KindLabel,
		ID:   Existing_Label_ID,
	},
	{
		Kind: KindVarible,
		ID:   Existing_Var_ID,
	},
}

svc := NewService(serviceOpts...)
newTemplate, err := svc.Export(ctx, ExportWithExistingResources(resourcesToClone...))
if err != nil {
	panic(err) // handle error as you see fit
}
// explore newly created and validated template

Things to note about the behavior of exporting existing resources. All label associations with existing resources will be included in the new template. However, the variables that are used within a dashboard query will not be added automatically to the template. Variables will need to be passed in alongside the dashboard to be added to the template.

Index

Constants

View Source
const (
	ActionTypeSkipKind     actionType = "skipKind"
	ActionTypeSkipResource actionType = "skipResource"
)

various ActionTypes the transport API speaks

View Source
const APIVersion = "influxdata.com/v2alpha1"

APIVersion marks the current APIVersion for influx packages.

View Source
const APIVersion2 = "influxdata.com/v2alpha2"
View Source
const ResourceTypeStack influxdb.ResourceType = "stack"
View Source
const RoutePrefixStacks = "/api/v2/stacks"
View Source
const RoutePrefixTemplates = "/api/v2/templates"

Variables

View Source
var ErrInvalidEncoding = errors.New("invalid encoding provided")

ErrInvalidEncoding indicates the encoding is invalid type for the parser.

Functions

func IsExisting

func IsExisting(status StateStatus) bool

IsExisting identifies state status as existing in the platform.

func IsNew

func IsNew(status StateStatus) bool

IsNew identifies state status as new to the platform.

func IsParseErr

func IsParseErr(err error) bool

IsParseErr inspects a given error to determine if it is a parseErr. If a parseErr it is, it will return it along with the confirmation boolean. If the error is not a parseErr it will return nil values for the parseErr, making it unsafe to use.

func IsRemoval

func IsRemoval(status StateStatus) bool

IsRemoval identifies state status as existing resource that will be removed from the platform.

func NewParseError

func NewParseError(errs ...ValidationErr) error

NewParseError creates a new parse error from existing validation errors.

Types

type ActionSkipKind

type ActionSkipKind struct {
	Kind Kind `json:"kind"`
}

ActionSkipKind provides an action from the consumer to use the template with modifications to the resource kinds will be applied.

type ActionSkipResource

type ActionSkipResource struct {
	Kind     Kind   `json:"kind"`
	MetaName string `json:"resourceTemplateName"`
}

ActionSkipResource provides an action from the consumer to use the template with modifications to the resource kind and template name that will be applied.

type ApplyOpt

type ApplyOpt struct {
	Templates       []*Template
	EnvRefs         map[string]interface{}
	MissingSecrets  map[string]string
	StackID         influxdb.ID
	ResourcesToSkip map[ActionSkipResource]bool
	KindsToSkip     map[Kind]bool
}

ApplyOpt is an option for applying a package.

type ApplyOptFn

type ApplyOptFn func(opt *ApplyOpt)

ApplyOptFn updates the ApplyOpt per the functional option.

func ApplyWithEnvRefs

func ApplyWithEnvRefs(envRefs map[string]interface{}) ApplyOptFn

ApplyWithEnvRefs provides env refs to saturate the missing reference fields in the template.

func ApplyWithKindSkip

func ApplyWithKindSkip(action ActionSkipKind) ApplyOptFn

ApplyWithKindSkip provides an action skip a kidn in the application of a template.

func ApplyWithResourceSkip

func ApplyWithResourceSkip(action ActionSkipResource) ApplyOptFn

ApplyWithResourceSkip provides an action skip a resource in the application of a template.

func ApplyWithSecrets

func ApplyWithSecrets(secrets map[string]string) ApplyOptFn

ApplyWithSecrets provides secrets to the platform that the template will need.

func ApplyWithStackID

func ApplyWithStackID(stackID influxdb.ID) ApplyOptFn

ApplyWithStackID associates the application of a template with a stack.

func ApplyWithTemplate

func ApplyWithTemplate(template *Template) ApplyOptFn

ApplyWithTemplate provides a template to the application/dry run.

type AuthAgent

type AuthAgent interface {
	IsWritable(ctx context.Context, orgID influxdb.ID, resType influxdb.ResourceType) error
	OrgPermissions(ctx context.Context, orgID influxdb.ID, action influxdb.Action, rest ...influxdb.Action) error
}

type Diff

type Diff struct {
	Buckets               []DiffBucket               `json:"buckets"`
	Checks                []DiffCheck                `json:"checks"`
	Dashboards            []DiffDashboard            `json:"dashboards"`
	Labels                []DiffLabel                `json:"labels"`
	LabelMappings         []DiffLabelMapping         `json:"labelMappings"`
	NotificationEndpoints []DiffNotificationEndpoint `json:"notificationEndpoints"`
	NotificationRules     []DiffNotificationRule     `json:"notificationRules"`
	Tasks                 []DiffTask                 `json:"tasks"`
	Telegrafs             []DiffTelegraf             `json:"telegrafConfigs"`
	Variables             []DiffVariable             `json:"variables"`
}

Diff is the result of a service DryRun call. The diff outlines what is new and or updated from the current state of the platform.

func (Diff) HasConflicts

func (d Diff) HasConflicts() bool

HasConflicts provides a binary t/f if there are any changes within package after dry run is complete.

type DiffBucket

type DiffBucket struct {
	DiffIdentifier

	New DiffBucketValues  `json:"new"`
	Old *DiffBucketValues `json:"old"`
}

DiffBucket is a diff of an individual bucket.

type DiffBucketValues

type DiffBucketValues struct {
	Name           string         `json:"name"`
	Description    string         `json:"description"`
	RetentionRules retentionRules `json:"retentionRules"`
}

DiffBucketValues are the varying values for a bucket.

type DiffChart

type DiffChart SummaryChart

DiffChart is a diff of oa chart. Since all charts are new right now. the SummaryChart is reused here.

func (*DiffChart) MarshalJSON

func (d *DiffChart) MarshalJSON() ([]byte, error)

func (*DiffChart) UnmarshalJSON

func (d *DiffChart) UnmarshalJSON(b []byte) error

type DiffCheck

type DiffCheck struct {
	DiffIdentifier

	New DiffCheckValues  `json:"new"`
	Old *DiffCheckValues `json:"old"`
}

DiffCheck is a diff of an individual check.

type DiffCheckValues

type DiffCheckValues struct {
	influxdb.Check
}

DiffCheckValues are the varying values for a check.

func (DiffCheckValues) MarshalJSON

func (d DiffCheckValues) MarshalJSON() ([]byte, error)

MarshalJSON implementation here is forced by the embedded check value here.

func (*DiffCheckValues) UnmarshalJSON

func (d *DiffCheckValues) UnmarshalJSON(b []byte) (err error)

UnmarshalJSON decodes the check values.

type DiffDashboard

type DiffDashboard struct {
	DiffIdentifier

	New DiffDashboardValues  `json:"new"`
	Old *DiffDashboardValues `json:"old"`
}

DiffDashboard is a diff of an individual dashboard.

type DiffDashboardValues

type DiffDashboardValues struct {
	Name   string      `json:"name"`
	Desc   string      `json:"description"`
	Charts []DiffChart `json:"charts"`
}

DiffDashboardValues are values for a dashboard.

type DiffIdentifier

type DiffIdentifier struct {
	ID          SafeID      `json:"id"`
	StateStatus StateStatus `json:"stateStatus"`
	MetaName    string      `json:"templateMetaName"`
	Kind        Kind        `json:"kind"`
}

DiffIdentifier are the identifying fields for any given resource. Each resource dictates if the resource is new, to be removed, or will remain.

func (DiffIdentifier) IsNew

func (d DiffIdentifier) IsNew() bool

IsNew indicates the resource is new to the platform.

type DiffLabel

type DiffLabel struct {
	DiffIdentifier

	New DiffLabelValues  `json:"new"`
	Old *DiffLabelValues `json:"old"`
}

DiffLabel is a diff of an individual label.

type DiffLabelMapping

type DiffLabelMapping struct {
	StateStatus StateStatus `json:"stateStatus"`

	ResType     influxdb.ResourceType `json:"resourceType"`
	ResID       SafeID                `json:"resourceID"`
	ResName     string                `json:"resourceName"`
	ResMetaName string                `json:"resourceTemplateMetaName"`

	LabelID       SafeID `json:"labelID"`
	LabelName     string `json:"labelName"`
	LabelMetaName string `json:"labelTemplateMetaName"`
}

DiffLabelMapping is a diff of an individual label mapping. A single resource may have multiple mappings to multiple labels. A label can have many mappings to other resources.

type DiffLabelValues

type DiffLabelValues struct {
	Name        string `json:"name"`
	Color       string `json:"color"`
	Description string `json:"description"`
}

DiffLabelValues are the varying values for a label.

type DiffNotificationEndpoint

type DiffNotificationEndpoint struct {
	DiffIdentifier

	New DiffNotificationEndpointValues  `json:"new"`
	Old *DiffNotificationEndpointValues `json:"old"`
}

DiffNotificationEndpoint is a diff of an individual notification endpoint.

type DiffNotificationEndpointValues

type DiffNotificationEndpointValues struct {
	influxdb.NotificationEndpoint
}

DiffNotificationEndpointValues are the varying values for a notification endpoint.

func (DiffNotificationEndpointValues) MarshalJSON

func (d DiffNotificationEndpointValues) MarshalJSON() ([]byte, error)

MarshalJSON implementation here is forced by the embedded check value here.

func (*DiffNotificationEndpointValues) UnmarshalJSON

func (d *DiffNotificationEndpointValues) UnmarshalJSON(b []byte) (err error)

UnmarshalJSON decodes the notification endpoint. This is necessary unfortunately.

type DiffNotificationRule

type DiffNotificationRule struct {
	DiffIdentifier

	New DiffNotificationRuleValues  `json:"new"`
	Old *DiffNotificationRuleValues `json:"old"`
}

DiffNotificationRule is a diff of an individual notification rule.

type DiffNotificationRuleValues

type DiffNotificationRuleValues struct {
	Name        string `json:"name"`
	Description string `json:"description"`

	// These 3 fields represent the relationship of the rule to the endpoint.
	EndpointID   SafeID `json:"endpointID"`
	EndpointName string `json:"endpointName"`
	EndpointType string `json:"endpointType"`

	Every           string              `json:"every"`
	Offset          string              `json:"offset"`
	MessageTemplate string              `json:"messageTemplate"`
	StatusRules     []SummaryStatusRule `json:"statusRules"`
	TagRules        []SummaryTagRule    `json:"tagRules"`
}

DiffNotificationRuleValues are the values for an individual rule.

type DiffTask

type DiffTask struct {
	DiffIdentifier

	New DiffTaskValues  `json:"new"`
	Old *DiffTaskValues `json:"old"`
}

DiffTask is a diff of an individual task.

type DiffTaskValues

type DiffTaskValues struct {
	Name        string          `json:"name"`
	Cron        string          `json:"cron"`
	Description string          `json:"description"`
	Every       string          `json:"every"`
	Offset      string          `json:"offset"`
	Query       string          `json:"query"`
	Status      influxdb.Status `json:"status"`
}

DiffTaskValues are the values for an individual task.

type DiffTelegraf

type DiffTelegraf struct {
	DiffIdentifier

	New influxdb.TelegrafConfig  `json:"new"`
	Old *influxdb.TelegrafConfig `json:"old"`
}

DiffTelegraf is a diff of an individual telegraf. This resource is always new.

type DiffVariable

type DiffVariable struct {
	DiffIdentifier

	New DiffVariableValues  `json:"new"`
	Old *DiffVariableValues `json:"old,omitempty"` // using omitempty here to signal there was no prev state with a nil
}

DiffVariable is a diff of an individual variable.

type DiffVariableValues

type DiffVariableValues struct {
	Name        string                      `json:"name"`
	Description string                      `json:"description"`
	Args        *influxdb.VariableArguments `json:"args"`
}

DiffVariableValues are the varying values for a variable.

type Encoder

type Encoder interface {
	Encode(v interface{}) error
}

Encoder is an encodes a type.

type Encoding

type Encoding int

Encoding describes the encoding for the raw package data. The encoding determines how the raw data is parsed.

const (
	EncodingUnknown Encoding = iota
	EncodingJSON
	EncodingJsonnet
	EncodingSource // EncodingSource draws the encoding type by inferring it from the source.
	EncodingYAML
)

encoding types

func (Encoding) String

func (e Encoding) String() string

String provides the string representation of the encoding.

type ExportByOrgIDOpt

type ExportByOrgIDOpt struct {
	OrgID         influxdb.ID
	LabelNames    []string
	ResourceKinds []Kind
}

ExportByOrgIDOpt identifies an org to export resources for and provides multiple filtering options.

type ExportOpt

type ExportOpt struct {
	StackID   influxdb.ID
	OrgIDs    []ExportByOrgIDOpt
	Resources []ResourceToClone
}

ExportOpt are the options for creating a new package.

type ExportOptFn

type ExportOptFn func(opt *ExportOpt) error

ExportOptFn is a functional input for setting the template fields.

func ExportWithAllOrgResources

func ExportWithAllOrgResources(orgIDOpt ExportByOrgIDOpt) ExportOptFn

ExportWithAllOrgResources allows the create method to clone all existing resources for the given organization.

func ExportWithExistingResources

func ExportWithExistingResources(resources ...ResourceToClone) ExportOptFn

ExportWithExistingResources allows the create method to clone existing resources.

func ExportWithStackID

func ExportWithStackID(stackID influxdb.ID) ExportOptFn

ExportWithStackID provides an export for the given stack ID.

type HTTPRemoteService

type HTTPRemoteService struct {
	Client *httpc.Client
}

HTTPRemoteService provides an http client that is fluent in all things template.

func (*HTTPRemoteService) Apply

func (s *HTTPRemoteService) Apply(ctx context.Context, orgID, userID influxdb.ID, opts ...ApplyOptFn) (ImpactSummary, error)

Apply will apply all the resources identified in the provided template. The entire template will be applied in its entirety. If a failure happens midway then the entire template will be rolled back to the state from before the template was applied.

func (*HTTPRemoteService) DeleteStack

func (s *HTTPRemoteService) DeleteStack(ctx context.Context, identifiers struct{ OrgID, UserID, StackID influxdb.ID }) error

func (*HTTPRemoteService) DryRun

func (s *HTTPRemoteService) DryRun(ctx context.Context, orgID, userID influxdb.ID, opts ...ApplyOptFn) (ImpactSummary, error)

DryRun provides a dry run of the template application. The template will be marked verified for later calls to Apply. This func will be run on an Apply if it has not been run already.

func (*HTTPRemoteService) Export

func (s *HTTPRemoteService) Export(ctx context.Context, opts ...ExportOptFn) (*Template, error)

Export will produce a template from the parameters provided.

func (*HTTPRemoteService) InitStack

func (s *HTTPRemoteService) InitStack(ctx context.Context, userID influxdb.ID, stack StackCreate) (Stack, error)

func (*HTTPRemoteService) ListStacks

func (s *HTTPRemoteService) ListStacks(ctx context.Context, orgID influxdb.ID, f ListFilter) ([]Stack, error)

func (*HTTPRemoteService) ReadStack

func (s *HTTPRemoteService) ReadStack(ctx context.Context, id influxdb.ID) (Stack, error)

func (*HTTPRemoteService) UninstallStack

func (s *HTTPRemoteService) UninstallStack(ctx context.Context, identifiers struct{ OrgID, UserID, StackID influxdb.ID }) (Stack, error)

func (*HTTPRemoteService) UpdateStack

func (s *HTTPRemoteService) UpdateStack(ctx context.Context, upd StackUpdate) (Stack, error)

type HTTPServerStacks

type HTTPServerStacks struct {
	chi.Router
	// contains filtered or unexported fields
}

HTTPServerStacks is a server that manages the stacks HTTP transport.

func NewHTTPServerStacks

func NewHTTPServerStacks(log *zap.Logger, svc SVC) *HTTPServerStacks

NewHTTPServerStacks constructs a new http server.

func (*HTTPServerStacks) Prefix

func (s *HTTPServerStacks) Prefix() string

Prefix provides the prefix to this route tree.

type HTTPServerTemplates

type HTTPServerTemplates struct {
	chi.Router
	// contains filtered or unexported fields
}

HTTPServerTemplates is a server that manages the templates HTTP transport.

func NewHTTPServerTemplates

func NewHTTPServerTemplates(log *zap.Logger, svc SVC) *HTTPServerTemplates

NewHTTPServerTemplates constructs a new http server.

func (*HTTPServerTemplates) Prefix

func (s *HTTPServerTemplates) Prefix() string

Prefix provides the prefix to this route tree.

type ImpactSummary

type ImpactSummary struct {
	Sources []string
	StackID influxdb.ID
	Diff    Diff
	Summary Summary
}

ImpactSummary represents the impact the application of a template will have on the system.

type Kind

type Kind string

Kind is a resource kind.

const (
	KindUnknown                       Kind = ""
	KindBucket                        Kind = "Bucket"
	KindCheck                         Kind = "Check"
	KindCheckDeadman                  Kind = "CheckDeadman"
	KindCheckThreshold                Kind = "CheckThreshold"
	KindDashboard                     Kind = "Dashboard"
	KindLabel                         Kind = "Label"
	KindNotificationEndpoint          Kind = "NotificationEndpoint"
	KindNotificationEndpointHTTP      Kind = "NotificationEndpointHTTP"
	KindNotificationEndpointPagerDuty Kind = "NotificationEndpointPagerDuty"
	KindNotificationEndpointSlack     Kind = "NotificationEndpointSlack"
	KindNotificationRule              Kind = "NotificationRule"
	KindPackage                       Kind = "Package"
	KindTask                          Kind = "Task"
	KindTelegraf                      Kind = "Telegraf"
	KindVariable                      Kind = "Variable"
)

Package kind types.

func Kinds

func Kinds() []Kind

Kinds is a list of known pkger kinds.

func (Kind) OK

func (k Kind) OK() error

OK validates the kind is valid.

func (Kind) ResourceType

func (k Kind) ResourceType() influxdb.ResourceType

ResourceType converts a kind to a known resource type (if applicable).

func (Kind) String

func (k Kind) String() string

String provides the kind in human readable form.

type ListFilter

type ListFilter struct {
	StackIDs []influxdb.ID
	Names    []string
}

ListFilter are filter options for filtering stacks from being returned.

type NameGenerator

type NameGenerator func() string

NameGenerator generates a random name. Includes an optional fuzz option to further randomize the name.

type Object

type Object struct {
	APIVersion string   `json:"apiVersion" yaml:"apiVersion"`
	Kind       Kind     `json:"kind" yaml:"kind"`
	Metadata   Resource `json:"metadata" yaml:"metadata"`
	Spec       Resource `json:"spec" yaml:"spec"`
}

Object describes the metadata and raw spec for an entity of a package kind.

func BucketToObject

func BucketToObject(name string, bkt influxdb.Bucket) Object

BucketToObject converts a influxdb.Bucket into an Object.

func CheckToObject

func CheckToObject(name string, ch influxdb.Check) Object

func DashboardToObject

func DashboardToObject(name string, dash influxdb.Dashboard) Object

DashboardToObject converts an influxdb.Dashboard to an Object.

func LabelToObject

func LabelToObject(name string, l influxdb.Label) Object

LabelToObject converts an influxdb.Label to an Object.

func NotificationEndpointToObject

func NotificationEndpointToObject(name string, e influxdb.NotificationEndpoint) Object

NotificationEndpointToObject converts an notification endpoint into a pkger Object.

func NotificationRuleToObject

func NotificationRuleToObject(name, endpointPkgName string, iRule influxdb.NotificationRule) Object

NotificationRuleToObject converts an notification rule into a pkger Object.

func TaskToObject

func TaskToObject(name string, t influxdb.Task) Object

TaskToObject converts an influxdb.Task into a pkger.Object.

func TelegrafToObject

func TelegrafToObject(name string, t influxdb.TelegrafConfig) Object

TelegrafToObject converts an influxdb.TelegrafConfig into a pkger.Object.

func VariableToObject

func VariableToObject(name string, v influxdb.Variable) Object

VariableToObject converts an influxdb.Variable to a pkger.Object.

func (Object) AddAssociations

func (k Object) AddAssociations(associations ...ObjectAssociation)

AddAssociations adds an association to the object.

func (Object) Name

func (k Object) Name() string

Name returns the name of the kind.

func (Object) SetMetadataName

func (k Object) SetMetadataName(name string)

SetMetadataName sets the metadata.name field.

type ObjectAssociation

type ObjectAssociation struct {
	Kind     Kind
	MetaName string
}

ObjectAssociation is an association for an object. The supported types at this time are KindLabel.

type ParseError

type ParseError interface {
	ValidationErrs() []ValidationErr
}

ParseError is the error from parsing the given package. The ParseError behavior provides a list of resources that failed and all validations that failed for that resource. A resource can multiple errors, and a parseErr can have multiple resources which themselves can have multiple validation failures.

type ReaderFn

type ReaderFn func() (r io.Reader, source string, err error)

ReaderFn is used for functional inputs to abstract the individual entrypoints for the reader itself.

func FromFile

func FromFile(filePath string) ReaderFn

FromFile reads a file from disk and provides a reader from it.

func FromHTTPRequest

func FromHTTPRequest(addr string) ReaderFn

FromHTTPRequest parses a pkg from the request body of a HTTP request. This is very useful when using packages that are hosted..

func FromReader

func FromReader(r io.Reader, sources ...string) ReaderFn

FromReader simply passes the reader along. Useful when consuming this from an HTTP request body. There are a number of other useful places for this functional input.

func FromString

func FromString(s string) ReaderFn

FromString parses a pkg from a raw string value. This is very useful in tests.

type ReqApply

type ReqApply struct {
	DryRun  bool                `json:"dryRun" yaml:"dryRun"`
	OrgID   string              `json:"orgID" yaml:"orgID"`
	StackID *string             `json:"stackID" yaml:"stackID"` // optional: non nil value signals stack should be used
	Remotes []ReqTemplateRemote `json:"remotes" yaml:"remotes"`

	RawTemplates []ReqRawTemplate `json:"templates" yaml:"templates"`
	RawTemplate  ReqRawTemplate   `json:"template" yaml:"template"`

	EnvRefs map[string]interface{} `json:"envRefs"`
	Secrets map[string]string      `json:"secrets"`

	RawActions []ReqRawAction `json:"actions"`
}

ReqApply is the request body for a json or yaml body for the apply template endpoint.

func (ReqApply) Templates

func (r ReqApply) Templates(encoding Encoding) (*Template, error)

Templates returns all templates associated with the request.

type ReqCreateStack

type ReqCreateStack struct {
	OrgID       string   `json:"orgID"`
	Name        string   `json:"name"`
	Description string   `json:"description"`
	URLs        []string `json:"urls"`
}

ReqCreateStack is a request body for a create stack call.

func (*ReqCreateStack) OK

func (r *ReqCreateStack) OK() error

OK validates the request body is valid.

type ReqExport

type ReqExport struct {
	StackID   string              `json:"stackID"`
	OrgIDs    []ReqExportOrgIDOpt `json:"orgIDs"`
	Resources []ResourceToClone   `json:"resources"`
}

ReqExport is a request body for the export endpoint.

func (*ReqExport) OK

func (r *ReqExport) OK() error

OK validates a create request.

type ReqExportOrgIDOpt

type ReqExportOrgIDOpt struct {
	OrgID   string `json:"orgID"`
	Filters struct {
		ByLabel        []string `json:"byLabel"`
		ByResourceKind []Kind   `json:"byResourceKind"`
	} `json:"resourceFilters"`
}

ReqExportOrgIDOpt provides options to export resources by organization id.

type ReqRawAction

type ReqRawAction struct {
	Action     string          `json:"action"`
	Properties json.RawMessage `json:"properties"`
}

ReqRawAction is a raw action consumers can provide to change the behavior of the application of a template.

type ReqRawTemplate

type ReqRawTemplate struct {
	ContentType string          `json:"contentType" yaml:"contentType"`
	Sources     []string        `json:"sources" yaml:"sources"`
	Template    json.RawMessage `json:"contents" yaml:"contents"`
}

func (ReqRawTemplate) Encoding

func (p ReqRawTemplate) Encoding() Encoding

type ReqTemplateRemote

type ReqTemplateRemote struct {
	URL         string `json:"url" yaml:"url"`
	ContentType string `json:"contentType" yaml:"contentType"`
}

ReqTemplateRemote provides a package via a remote (i.e. a gist). If content type is not provided then the service will do its best to discern the content type of the contents.

func (ReqTemplateRemote) Encoding

func (p ReqTemplateRemote) Encoding() Encoding

Encoding returns the encoding type that corresponds to the given content type.

type ReqUpdateStack

type ReqUpdateStack struct {
	Name                *string                  `json:"name"`
	Description         *string                  `json:"description"`
	TemplateURLs        []string                 `json:"templateURLs"`
	AdditionalResources []ReqUpdateStackResource `json:"additionalResources"`

	// Deprecating the urls field and replacing with templateURLs field.
	// This is remaining here for backwards compatibility.
	URLs []string `json:"urls"`
}

ReqUpdateStack is the request body for updating a stack.

type ReqUpdateStackResource

type ReqUpdateStackResource struct {
	ID       string `json:"resourceID"`
	Kind     Kind   `json:"kind"`
	MetaName string `json:"templateMetaName"`
}

type Resource

type Resource map[string]interface{}

Resource is a pkger Resource kind. It can be one of any of available kinds that are supported.

func (Resource) Name

func (r Resource) Name() string

Name returns the name of the resource.

type ResourceToClone

type ResourceToClone struct {
	Kind Kind        `json:"kind"`
	ID   influxdb.ID `json:"id,omitempty"`
	Name string      `json:"name"`
	// note(jsteenb2): For time being we'll allow this internally, but not externally. A lot of
	// issues to account for when exposing this to the outside world. Not something I'm keen
	// to accommodate at this time.
	MetaName string `json:"-"`
}

ResourceToClone is a resource that will be cloned.

func (ResourceToClone) OK

func (r ResourceToClone) OK() error

OK validates a resource clone is viable.

type RespApply

type RespApply struct {
	Sources []string `json:"sources" yaml:"sources"`
	StackID string   `json:"stackID" yaml:"stackID"`
	Diff    Diff     `json:"diff" yaml:"diff"`
	Summary Summary  `json:"summary" yaml:"summary"`

	Errors []ValidationErr `json:"errors,omitempty" yaml:"errors,omitempty"`
}

RespApply is the response body for the apply template endpoint.

type RespExport

type RespExport []Object

RespExport is a response body for the create template endpoint.

type RespListStacks

type RespListStacks struct {
	Stacks []RespStack `json:"stacks"`
}

RespListStacks is the HTTP response for a stack list call.

type RespStack

type RespStack struct {
	ID        string           `json:"id"`
	OrgID     string           `json:"orgID"`
	CreatedAt time.Time        `json:"createdAt"`
	Events    []RespStackEvent `json:"events"`

	// maintain same interface for backward compatability
	RespStackEvent
}

RespStack is the response body for a stack.

type RespStackEvent

type RespStackEvent struct {
	EventType   string              `json:"eventType"`
	Name        string              `json:"name"`
	Description string              `json:"description"`
	Resources   []RespStackResource `json:"resources"`
	Sources     []string            `json:"sources"`
	URLs        []string            `json:"urls"`
	UpdatedAt   time.Time           `json:"updatedAt"`
}

type RespStackResource

type RespStackResource struct {
	APIVersion   string                   `json:"apiVersion"`
	ID           string                   `json:"resourceID"`
	Kind         Kind                     `json:"kind"`
	MetaName     string                   `json:"templateMetaName"`
	Associations []RespStackResourceAssoc `json:"associations"`
	Links        RespStackResourceLinks   `json:"links"`
}

RespStackResource is the response for a stack resource. This type exists to decouple the internal service implementation from the deprecates usage of templates in the API. We could add a custom UnmarshalJSON method, but I would rather keep it obvious and explicit with a separate field.

type RespStackResourceAssoc

type RespStackResourceAssoc struct {
	Kind     Kind   `json:"kind"`
	MetaName string `json:"metaName"`
}

RespStackResourceAssoc is the response for a stack resource's associations.

type RespStackResourceLinks struct {
	Self string `json:"self"`
}

type SVC

type SVC interface {
	InitStack(ctx context.Context, userID influxdb.ID, stack StackCreate) (Stack, error)
	UninstallStack(ctx context.Context, identifiers struct{ OrgID, UserID, StackID influxdb.ID }) (Stack, error)
	DeleteStack(ctx context.Context, identifiers struct{ OrgID, UserID, StackID influxdb.ID }) error
	ListStacks(ctx context.Context, orgID influxdb.ID, filter ListFilter) ([]Stack, error)
	ReadStack(ctx context.Context, id influxdb.ID) (Stack, error)
	UpdateStack(ctx context.Context, upd StackUpdate) (Stack, error)

	Export(ctx context.Context, opts ...ExportOptFn) (*Template, error)
	DryRun(ctx context.Context, orgID, userID influxdb.ID, opts ...ApplyOptFn) (ImpactSummary, error)
	Apply(ctx context.Context, orgID, userID influxdb.ID, opts ...ApplyOptFn) (ImpactSummary, error)
}

SVC is the packages service interface.

type SVCMiddleware

type SVCMiddleware func(SVC) SVC

SVCMiddleware is a service middleware func.

func MWAuth

func MWAuth(authAgent AuthAgent) SVCMiddleware

MWAuth is an auth service middleware for the packager domain.

func MWLogging

func MWLogging(log *zap.Logger) SVCMiddleware

MWLogging adds logging functionality for the service.

func MWMetrics

func MWMetrics(reg *prom.Registry) SVCMiddleware

MWMetrics is a metrics service middleware for the notification endpoint service.

func MWTracing

func MWTracing() SVCMiddleware

MWTracing adds tracing functionality for the service.

type SafeID

type SafeID influxdb.ID

SafeID is an equivalent influxdb.ID that encodes safely with zero values (influxdb.ID == 0).

func (SafeID) Encode

func (s SafeID) Encode() ([]byte, error)

Encode will safely encode the id.

func (SafeID) String

func (s SafeID) String() string

String prints a encoded string representation of the id.

type Service

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

Service provides the template business logic including all the dependencies to make this resource sausage.

func NewService

func NewService(opts ...ServiceSetterFn) *Service

NewService is a constructor for a template Service.

func (*Service) Apply

func (s *Service) Apply(ctx context.Context, orgID, userID influxdb.ID, opts ...ApplyOptFn) (impact ImpactSummary, e error)

Apply will apply all the resources identified in the provided template. The entire template will be applied in its entirety. If a failure happens midway then the entire template will be rolled back to the state from before the template were applied.

func (*Service) DeleteStack

func (s *Service) DeleteStack(ctx context.Context, identifiers struct{ OrgID, UserID, StackID influxdb.ID }) (e error)

DeleteStack removes a stack and all the resources that have are associated with the stack.

func (*Service) DryRun

func (s *Service) DryRun(ctx context.Context, orgID, userID influxdb.ID, opts ...ApplyOptFn) (ImpactSummary, error)

DryRun provides a dry run of the template application. The template will be marked verified for later calls to Apply. This func will be run on an Apply if it has not been run already.

func (*Service) Export

func (s *Service) Export(ctx context.Context, setters ...ExportOptFn) (*Template, error)

Export will produce a templates from the parameters provided.

func (*Service) InitStack

func (s *Service) InitStack(ctx context.Context, userID influxdb.ID, stCreate StackCreate) (Stack, error)

InitStack will create a new stack for the given user and its given org. The stack can be created with urls that point to the location of packages that are included as part of the stack when it is applied.

func (*Service) ListStacks

func (s *Service) ListStacks(ctx context.Context, orgID influxdb.ID, f ListFilter) ([]Stack, error)

ListStacks returns a list of stacks.

func (*Service) ReadStack

func (s *Service) ReadStack(ctx context.Context, id influxdb.ID) (Stack, error)

ReadStack returns a stack that matches the given id.

func (*Service) UninstallStack

func (s *Service) UninstallStack(ctx context.Context, identifiers struct{ OrgID, UserID, StackID influxdb.ID }) (Stack, error)

UninstallStack will remove all resources associated with the stack.

func (*Service) UpdateStack

func (s *Service) UpdateStack(ctx context.Context, upd StackUpdate) (Stack, error)

UpdateStack updates the stack by the given parameters.

type ServiceSetterFn

type ServiceSetterFn func(opt *serviceOpt)

ServiceSetterFn is a means of setting dependencies on the Service type.

func WithBucketSVC

func WithBucketSVC(bktSVC influxdb.BucketService) ServiceSetterFn

WithBucketSVC sets the bucket service.

func WithCheckSVC

func WithCheckSVC(checkSVC influxdb.CheckService) ServiceSetterFn

WithCheckSVC sets the check service.

func WithDashboardSVC

func WithDashboardSVC(dashSVC influxdb.DashboardService) ServiceSetterFn

WithDashboardSVC sets the dashboard service.

func WithIDGenerator

func WithIDGenerator(idGen influxdb.IDGenerator) ServiceSetterFn

WithIDGenerator sets the id generator for the service.

func WithLabelSVC

func WithLabelSVC(labelSVC influxdb.LabelService) ServiceSetterFn

WithLabelSVC sets the label service.

func WithLogger

func WithLogger(log *zap.Logger) ServiceSetterFn

WithLogger sets the logger for the service.

func WithNotificationEndpointSVC

func WithNotificationEndpointSVC(endpointSVC influxdb.NotificationEndpointService) ServiceSetterFn

WithNotificationEndpointSVC sets the endpoint notification service.

func WithNotificationRuleSVC

func WithNotificationRuleSVC(ruleSVC influxdb.NotificationRuleStore) ServiceSetterFn

WithNotificationRuleSVC sets the endpoint rule service.

func WithOrganizationService

func WithOrganizationService(orgSVC influxdb.OrganizationService) ServiceSetterFn

WithOrganizationService sets the organization service for the service.

func WithSecretSVC

func WithSecretSVC(secretSVC influxdb.SecretService) ServiceSetterFn

WithSecretSVC sets the secret service.

func WithStore

func WithStore(store Store) ServiceSetterFn

WithStore sets the store for the service.

func WithTaskSVC

func WithTaskSVC(taskSVC influxdb.TaskService) ServiceSetterFn

WithTaskSVC sets the task service.

func WithTelegrafSVC

func WithTelegrafSVC(telegrafSVC influxdb.TelegrafConfigStore) ServiceSetterFn

WithTelegrafSVC sets the telegraf service.

func WithTimeGenerator

func WithTimeGenerator(timeGen influxdb.TimeGenerator) ServiceSetterFn

WithTimeGenerator sets the time generator for the service.

func WithVariableSVC

func WithVariableSVC(varSVC influxdb.VariableService) ServiceSetterFn

WithVariableSVC sets the variable service.

type Stack

type Stack struct {
	ID        influxdb.ID
	OrgID     influxdb.ID
	CreatedAt time.Time `json:"createdAt"`
	Events    []StackEvent
}

Stack is an identifier for stateful application of a package(s). This stack will map created resources from the template(s) to existing resources on the platform. This stack is updated only after side effects of applying a template. If the template is applied, and no changes are had, then the stack is not updated.

func (Stack) LatestEvent

func (s Stack) LatestEvent() StackEvent

type StackAdditionalResource

type StackAdditionalResource struct {
	APIVersion string
	ID         influxdb.ID
	Kind       Kind
	MetaName   string
}

type StackCreate

type StackCreate struct {
	OrgID        influxdb.ID
	Name         string
	Description  string
	Sources      []string
	TemplateURLs []string
	Resources    []StackResource
}

type StackEvent

type StackEvent struct {
	EventType    StackEventType
	Name         string
	Description  string
	Sources      []string
	TemplateURLs []string
	Resources    []StackResource
	UpdatedAt    time.Time `json:"updatedAt"`
}

type StackEventType

type StackEventType uint
const (
	StackEventCreate StackEventType = iota
	StackEventUpdate
	StackEventUninstalled
)

func (StackEventType) String

func (e StackEventType) String() string

type StackResource

type StackResource struct {
	APIVersion   string
	ID           influxdb.ID
	Name         string
	Kind         Kind
	MetaName     string
	Associations []StackResourceAssociation
}

StackResource is a record for an individual resource side effect genereated from applying a template.

type StackResourceAssociation

type StackResourceAssociation struct {
	Kind     Kind
	MetaName string
}

StackResourceAssociation associates a stack resource with another stack resource.

type StackUpdate

type StackUpdate struct {
	ID                  influxdb.ID
	Name                *string
	Description         *string
	TemplateURLs        []string
	AdditionalResources []StackAdditionalResource
}

StackUpdate provides a means to update an existing stack.

type StateStatus

type StateStatus string

StateStatus indicates the status of a diff or summary resource

const (
	StateStatusExists StateStatus = "exists"
	StateStatusNew    StateStatus = "new"
	StateStatusRemove StateStatus = "remove"
)

type Store

type Store interface {
	CreateStack(ctx context.Context, stack Stack) error
	ListStacks(ctx context.Context, orgID influxdb.ID, filter ListFilter) ([]Stack, error)
	ReadStackByID(ctx context.Context, id influxdb.ID) (Stack, error)
	UpdateStack(ctx context.Context, stack Stack) error
	DeleteStack(ctx context.Context, id influxdb.ID) error
}

Store is the storage behavior the Service depends on.

type StoreKV

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

StoreKV is a store implementation that uses a kv store backing.

func NewStoreKV

func NewStoreKV(store kv.Store) *StoreKV

NewStoreKV creates a new StoreKV entity. This does not initialize the store. You will want to init it if you want to have this init donezo at startup. If not it'll lazy load the buckets as they are used.

func (*StoreKV) CreateStack

func (s *StoreKV) CreateStack(ctx context.Context, stack Stack) error

CreateStack will create a new stack. If collisions are found will fail.

func (*StoreKV) DeleteStack

func (s *StoreKV) DeleteStack(ctx context.Context, id influxdb.ID) error

DeleteStack deletes a stack by id.

func (*StoreKV) ListStacks

func (s *StoreKV) ListStacks(ctx context.Context, orgID influxdb.ID, f ListFilter) ([]Stack, error)

ListStacks returns a list of stacks.

func (*StoreKV) ReadStackByID

func (s *StoreKV) ReadStackByID(ctx context.Context, id influxdb.ID) (Stack, error)

ReadStackByID reads a stack by the provided ID.

func (*StoreKV) UpdateStack

func (s *StoreKV) UpdateStack(ctx context.Context, stack Stack) error

UpdateStack updates a stack.

type Summary

type Summary struct {
	Buckets               []SummaryBucket               `json:"buckets"`
	Checks                []SummaryCheck                `json:"checks"`
	Dashboards            []SummaryDashboard            `json:"dashboards"`
	NotificationEndpoints []SummaryNotificationEndpoint `json:"notificationEndpoints"`
	NotificationRules     []SummaryNotificationRule     `json:"notificationRules"`
	Labels                []SummaryLabel                `json:"labels"`
	LabelMappings         []SummaryLabelMapping         `json:"labelMappings"`
	MissingEnvs           []string                      `json:"missingEnvRefs"`
	MissingSecrets        []string                      `json:"missingSecrets"`
	Tasks                 []SummaryTask                 `json:"summaryTask"`
	TelegrafConfigs       []SummaryTelegraf             `json:"telegrafConfigs"`
	Variables             []SummaryVariable             `json:"variables"`
}

Summary is a definition of all the resources that have or will be created from a pkg.

type SummaryBucket

type SummaryBucket struct {
	SummaryIdentifier
	ID          SafeID `json:"id,omitempty"`
	OrgID       SafeID `json:"orgID,omitempty"`
	Name        string `json:"name"`
	Description string `json:"description"`
	// TODO: return retention rules?
	RetentionPeriod time.Duration `json:"retentionPeriod"`

	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

SummaryBucket provides a summary of a pkg bucket.

type SummaryChart

type SummaryChart struct {
	Properties influxdb.ViewProperties `json:"-"`

	XPosition int `json:"xPos"`
	YPosition int `json:"yPos"`
	Height    int `json:"height"`
	Width     int `json:"width"`
}

SummaryChart provides a summary of a pkg dashboard's chart.

func (*SummaryChart) MarshalJSON

func (s *SummaryChart) MarshalJSON() ([]byte, error)

MarshalJSON marshals a summary chart.

func (*SummaryChart) UnmarshalJSON

func (s *SummaryChart) UnmarshalJSON(b []byte) error

UnmarshalJSON unmarshals a view properties and other data.

type SummaryCheck

type SummaryCheck struct {
	SummaryIdentifier
	Check  influxdb.Check  `json:"check"`
	Status influxdb.Status `json:"status"`

	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

SummaryCheck provides a summary of a pkg check.

func (*SummaryCheck) UnmarshalJSON

func (s *SummaryCheck) UnmarshalJSON(b []byte) error

type SummaryDashboard

type SummaryDashboard struct {
	SummaryIdentifier
	ID          SafeID         `json:"id"`
	OrgID       SafeID         `json:"orgID"`
	Name        string         `json:"name"`
	Description string         `json:"description"`
	Charts      []SummaryChart `json:"charts"`

	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

SummaryDashboard provides a summary of a pkg dashboard.

type SummaryIdentifier

type SummaryIdentifier struct {
	Kind          Kind               `json:"kind"`
	MetaName      string             `json:"templateMetaName"`
	EnvReferences []SummaryReference `json:"envReferences"`
}

SummaryIdentifier establishes the shared identifiers for a given resource within a template.

type SummaryLabel

type SummaryLabel struct {
	SummaryIdentifier
	ID         SafeID `json:"id"`
	OrgID      SafeID `json:"orgID"`
	Name       string `json:"name"`
	Properties struct {
		Color       string `json:"color"`
		Description string `json:"description"`
	} `json:"properties"`
}

SummaryLabel provides a summary of a pkg label.

type SummaryLabelMapping

type SummaryLabelMapping struct {
	Status           StateStatus           `json:"status,omitempty"`
	ResourceID       SafeID                `json:"resourceID"`
	ResourceMetaName string                `json:"resourceTemplateMetaName"`
	ResourceName     string                `json:"resourceName"`
	ResourceType     influxdb.ResourceType `json:"resourceType"`
	LabelMetaName    string                `json:"labelTemplateMetaName"`
	LabelName        string                `json:"labelName"`
	LabelID          SafeID                `json:"labelID"`
	// contains filtered or unexported fields
}

SummaryLabelMapping provides a summary of a label mapped with a single resource.

type SummaryNotificationEndpoint

type SummaryNotificationEndpoint struct {
	SummaryIdentifier
	NotificationEndpoint influxdb.NotificationEndpoint `json:"notificationEndpoint"`

	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

SummaryNotificationEndpoint provides a summary of a pkg notification endpoint.

func (*SummaryNotificationEndpoint) UnmarshalJSON

func (s *SummaryNotificationEndpoint) UnmarshalJSON(b []byte) error

UnmarshalJSON unmarshals the notificatio endpoint. This is necessary b/c of the notification endpoint does not have a means ot unmarshal itself.

type SummaryNotificationRule

type SummaryNotificationRule struct {
	SummaryIdentifier
	ID          SafeID `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`

	// These fields represent the relationship of the rule to the endpoint.
	EndpointID       SafeID `json:"endpointID"`
	EndpointMetaName string `json:"endpointTemplateMetaName"`
	EndpointType     string `json:"endpointType"`

	Every           string              `json:"every"`
	Offset          string              `json:"offset"`
	MessageTemplate string              `json:"messageTemplate"`
	Status          influxdb.Status     `json:"status"`
	StatusRules     []SummaryStatusRule `json:"statusRules"`
	TagRules        []SummaryTagRule    `json:"tagRules"`

	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

Summary types for NotificationRules which provide a summary of a pkg notification rule.

type SummaryReference

type SummaryReference struct {
	Field        string      `json:"resourceField"`
	EnvRefKey    string      `json:"envRefKey"`
	ValType      string      `json:"valueType"`
	Value        interface{} `json:"value"`
	DefaultValue interface{} `json:"defaultValue"`
}

SummaryReference informs the consumer of required references for this resource.

type SummaryStatusRule

type SummaryStatusRule struct {
	CurrentLevel  string `json:"currentLevel"`
	PreviousLevel string `json:"previousLevel"`
}

Summary types for NotificationRules which provide a summary of a pkg notification rule.

type SummaryTagRule

type SummaryTagRule struct {
	Key      string `json:"key"`
	Value    string `json:"value"`
	Operator string `json:"operator"`
}

Summary types for NotificationRules which provide a summary of a pkg notification rule.

type SummaryTask

type SummaryTask struct {
	SummaryIdentifier
	ID          SafeID          `json:"id"`
	Name        string          `json:"name"`
	Cron        string          `json:"cron"`
	Description string          `json:"description"`
	Every       string          `json:"every"`
	Offset      string          `json:"offset"`
	Query       string          `json:"query"`
	Status      influxdb.Status `json:"status"`

	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

SummaryTask provides a summary of a task.

type SummaryTelegraf

type SummaryTelegraf struct {
	SummaryIdentifier
	TelegrafConfig influxdb.TelegrafConfig `json:"telegrafConfig"`

	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

SummaryTelegraf provides a summary of a pkg telegraf config.

type SummaryVariable

type SummaryVariable struct {
	SummaryIdentifier
	ID          SafeID                      `json:"id,omitempty"`
	OrgID       SafeID                      `json:"orgID,omitempty"`
	Name        string                      `json:"name"`
	Description string                      `json:"description"`
	Selected    []string                    `json:"variables"`
	Arguments   *influxdb.VariableArguments `json:"arguments"`

	LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

SummaryVariable provides a summary of a pkg variable.

type Template

type Template struct {
	Objects []Object `json:"-" yaml:"-"`
	// contains filtered or unexported fields
}

Template is the model for a package. The resources are more generic that one might expect at first glance. This was done on purpose. The way json/yaml/toml or w/e scripting you want to use, can have very different ways of parsing. The different parsers are limited for the parsers that do not come from the std lib (looking at you yaml/v2). This allows us to parse it and leave the matching to another power, the graphing of the package is handled within itself.

func Combine

func Combine(pkgs []*Template, validationOpts ...ValidateOptFn) (*Template, error)

Combine combines pkgs together. Is useful when you want to take multiple disparate pkgs and compile them into one to take advantage of the parser and service guarantees.

func Parse

func Parse(encoding Encoding, readerFn ReaderFn, opts ...ValidateOptFn) (*Template, error)

Parse parses a pkg defined by the encoding and readerFns. As of writing this we can parse both a YAML, JSON, and Jsonnet formats of the Template model.

func (*Template) Contains

func (p *Template) Contains(k Kind, pkgName string) bool

Contains identifies if a pkg contains a given object identified by its kind and metadata.Name (MetaName) field.

func (*Template) Encode

func (p *Template) Encode(encoding Encoding) ([]byte, error)

Encode is a helper for encoding the pkg correctly.

func (*Template) Sources

func (p *Template) Sources() []string

func (*Template) Summary

func (p *Template) Summary() Summary

Summary returns a package Summary that describes all the resources and associations the pkg contains. It is very useful for informing users of the changes that will take place when this pkg would be applied.

func (*Template) Validate

func (p *Template) Validate(opts ...ValidateOptFn) error

Validate will graph all resources and validate every thing is in a useful form.

type ValidateOptFn

type ValidateOptFn func(*validateOpt)

ValidateOptFn provides a means to disable desired validation checks.

func ValidSkipParseError

func ValidSkipParseError() ValidateOptFn

ValidSkipParseError ignores the validation check from the of resources. This is useful for the service Create to ignore this and allow the creation of a pkg without resources.

func ValidWithoutResources

func ValidWithoutResources() ValidateOptFn

ValidWithoutResources ignores the validation check for minimum number of resources. This is useful for the service Create to ignore this and allow the creation of a pkg without resources.

type ValidationErr

type ValidationErr struct {
	Kind    string   `json:"kind" yaml:"kind"`
	Fields  []string `json:"fields" yaml:"fields"`
	Indexes []*int   `json:"idxs" yaml:"idxs"`
	Reason  string   `json:"reason" yaml:"reason"`
}

ValidationErr represents an error during the parsing of a package.

func (ValidationErr) Error

func (v ValidationErr) Error() string

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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