Skip to content

Commit

Permalink
Merge pull request #21 from get-glu/gm/docs
Browse files Browse the repository at this point in the history
feat: initial docs
  • Loading branch information
GeorgeMac authored Nov 13, 2024
2 parents 83e209a + 3fdcd7c commit c28a189
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 13 deletions.
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ It is a framework for orchestrating, manipulating and introspecting the state of

Use it to implement anything that involes automating updates to Git repositories via commits and pull-requests.

### Docker and OCI image version updates (think Renovate / Kargo)

TODO(georgemac): Give demonstration (e.g. with FluxCD for the delivery component).
Demonstrate how the API can be used for introspection of pipeline state.
- ✅ Track new versions of applications in source repositories (OCI, Helm etc) and trigger updates to target configuration repositories (Git).
- ⌛️ Coordinate any combination of scheduled, event driven or manually triggered promotions from one environment to the next.
- ⏳ Expose a single pane of glass to compare and manipulating the state of your resources in one environment to the next.
- 🗓️ Export standardized telemetry which ties together your entire end to end CI/CD and promotion pipeline sequence of events.

## Development

### Glu Framework

The core framework is implemented in Go and is designed to be embedded in your own application.
Glu's documentation site goes into details for integrating it into your own codebase and learning the concepts.

// TODO(mark): more details.
If you want to contribute to Glu, then Go (version 1.23+) is currently the only requirement to get building.

### Glu UI

Expand All @@ -35,8 +36,18 @@ npm start

This will start a local server which can be viewed in your browser at http://localhost:1234.

## Roadmap
## Roadmap Ideas

In the future we plan to support more use-case, such as:

- (In Progress) Progressive delivery (think Kargo / Argo Rollouts)
- New sources:
- Helm
- Webhook / API
- Kubernetes (direct to cluster)
- Progressive delivery (think Kargo / Argo Rollouts)
- Ability to guard promotion with condition checks on resource status
- Expose status via Go function definitions on resource types
- Pinning, history and rollback
- Ability to view past states for phases
- Be able to pin phases to current or manually overridden states
- Rollback phases to previous known states
6 changes: 3 additions & 3 deletions cmd/experiment/experiment.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ func run(ctx context.Context) error {

// build a controller for the staging environment which source from the git repository
// configure it to promote from the OCI controller
gitStaging, err := controllers.New(glu.Name("git-staging", glu.Label("env", "staging")),
staging, err := controllers.New(glu.Name("staging", glu.Label("env", "staging")),
pipeline, gitSource, core.PromotesFrom(ociController))
if err != nil {
return nil, err
}

// build a controller for the production environment which source from the git repository
// configure it to promote from the staging git controller
_, err = controllers.New(glu.Name("git-production", glu.Label("env", "production")),
pipeline, gitSource, core.PromotesFrom(gitStaging))
_, err = controllers.New(glu.Name("production", glu.Label("env", "production")),
pipeline, gitSource, core.PromotesFrom(staging))
if err != nil {
return nil, err
}
Expand Down
Empty file added docs/.nojekyll
Empty file.
170 changes: 170 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Welcome <!-- {docsify-ignore-all} -->

> Glu is progressive delivery as code
Glu is a framework written and consumed in the Go programming language.
It is intended to glue together configuration repositories and artefact sources using `code`.

## Goals

The goals outlined here are defined to set a target for the project to work towards.
Glu has not yet reached all of these goals, but hopefully it gives an idea of our intended direction.
They're also not immutable and we would love for your help in shaping them.

- Allow engineers to define application delivery across multiple environments as `code`.
- Create a central pane of glass for inspecting and interacting with promotion pipelines.
- Support defining complex rules to guard automated promotion using strategies such as smoke testing and performance evaluation.
- Simple and quick integration with common existing CI/CD and source control management platforms.
- Expose standardized telemetry for the entire end-to-end delivery of changes in your system.

## Overview

Glu has an opinionated set of models and abstractions, which when combined, allow you to build consistent command-line and server processes for orchestrating the progression of applications and configuration across target environments.

```go
// build a controller which sources from our OCI repository
ociController, err := controllers.New(glu.Name("oci"), pipeline, ociSource)
if err != nil {
return nil, err
}

// build a controller for the staging environment which sources from our git repository
// and configures it to promote from the OCI controller
staging, err := controllers.New(glu.Name("staging", glu.Label("env", "staging")),
pipeline, gitSource, core.PromotesFrom(ociController))
if err != nil {
return nil, err
}

// build a controller for the production environment which also sources from our git repository
// and configures it to promote from the staging git controller
_, err = controllers.New(glu.Name("production", glu.Label("env", "production")),
pipeline, gitSource, core.PromotesFrom(staging))
if err != nil {
return nil, err
}
```

The Glu framework comprises of a set of abstractions for declaring the resources (your applications and configuration), update strategies (we call them controllers) and rules for progression (how and when to promote) within a pipeline.

### System

At the top of the tree we have the `glu.System`.
This is our entrypoint and wrapper for building a Glu configured application.

```go
func main() {
glu.NewSystem(context.Background()).Run()
}
```

The `glu.System` instance has methods for building new pipelines and configuring triggers.

By delegating control to a `glu.System` instance we get a few out-of-the-box conveniences:

1. Pre-built configuration format and parsing for accessing and authenticating the built-in sources (Git, OCI and so on).
1. A CLI interface for inspecting and manually promoting resources on the command-line.
1. An API interface for inspecting and manually promoting resources over a network.
1. Lifecycle control (signal handling and graceful shutdown).
1. Add the optional UI component to visualize your pipelines in a browser.

### Resources

Resources are the primary definition of _what_ is being represented in your pipeline and _how_ they are represented in target sources.
In Go, resources are represented as an interface for the author (that's you) to fill in the blanks:

```go
// Resource is an instance of a resource in a controller.
// Primarilly, it exposes a Digest method used to produce
// a hash digest of the instances current state.
type Resource interface {
Digest() (string, error)
}
```

The core abstraction (currently) only requires the type to implement a single `Digest()` method.
This should be used to produce a content digest of the resources state in a given moment.
It is used in the system to perform equality checks when deciding whether or not to promote.

The other sources in the Glu codebase will require additional functions to be implemented in order to integrate with them.
For example, the Git source requires you to define how your resource is encoded and decoded to and from a filesystem.

```go
type SomeResource struct {
ImageName string `json:"image_name"`
ImageDigest string `json:"image_digest"`
}

func (s *SomeResource) Digest() (string, error) { return s.ImageDigest, nil }
```

### Pipelines

Pipelines carry your specific resources type across controller destinations.
They coordinate the edges in the workflow that is your promotion pipeline.

They are also responsible for constructing new instances of your resource types.
These are used when fetching and updating controllers and sources during promotion.

```go
pipeline := glu.NewPipeline(glu.Name("mypipeline"), func() *SomeResource {
// this is an opportunity to set any initial default values
// for fields before the rest of the fields are populated
// from a target controller source
return &SomeResource{ImageName: "someimagename"}
})
```

### Controllers

Controllers have the job of interfacing with both sources and other upstream controllers to manage the promotion lifecycle.
They have metadata to uniquely identify themselves within the context of a pipeline.
They're also bound to a particular source implementation, and are optional dependent on an upstream source of the _same resource type_.

When a controller attempts a promotion (`controller.Promote(ctx)`) the following occurs:

1. If there is no upstream controller to promote from, then return (no op).
2. Get the current resource state from the target source based on controller metadata.
3. Get the current resource state from the upstream promotion target controller.
4. If the resource from (2) is equal to that of (3) (based on comparing their digest), the return (no op).
5. Update the state of the source with the state of the upstream resource (3) (this is a promotion).

### Sources

Sources are the core engine for controllers to both view and update resources in a target external system.
While controllers handle the lifecycle of promotion, sources interface with your resource types and sources of truth to perform relevant transactions.

Currently, Glu has implementations for the following sources:

- OCI
- Git

We look to add more in the not-so-distant future. However, these can also be implemented by hand via the following interfaces:

```go
// Controller is the core interface for resource sourcing and management.
// These types can be registered on pipelines and can depend upon on another for promotion.
type Controller interface {
Metadata() Metadata
Get(context.Context) (any, error)
Promote(context.Context) error
}

// ResourceController is a Controller bound to a Resource type R.
type ResourceController[R Resource] interface {
Controller
GetResource(context.Context) (R, error)
}
```

### Triggers

Schedule promotions to run automatically on an interval for controllers matching a specific set of labels:

```go
// schedule promotion attempts to staging every 10 seconds
system.SchedulePromotion(
glu.ScheduleInterval(10*time.Second),
glu.ScheduleMatchesLabel("env", "staging"),
)
```
12 changes: 12 additions & 0 deletions docs/_coverpage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
![stu the mascot for glu](/images/stu.png ':size=20%')

# Glu

> Progressive delivery that sticks
- A framework for orchestrating and introspecting delivery pipelines
- Integrates with directly with Git, OCI and more (to come)
- Optional user interface for pipeline introspection and manipulation

[GitHub](https://github.com/get-glu/glu/)
[Get Started](#welcome)
Binary file added docs/images/stu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'Glu',
repo: 'get-glu/glu',
coverpage: true
}
</script>
<!-- Docsify v4 -->
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-go.min.js"></script>
</body>
</html>
6 changes: 3 additions & 3 deletions pkg/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ type Controller interface {
Promote(context.Context) error
}

// Resource is an instance of a resource in a phase
// It exposes its metadata, unique current digest and functionality
// for extracting from updating a filesystem with the current version.
// Resource is an instance of a resource in a controller.
// Primarilly, it exposes a Digest method used to produce
// a hash digest of the resource instances current state.
type Resource interface {
Digest() (string, error)
}
Expand Down

0 comments on commit c28a189

Please sign in to comment.