Git Product home page Git Product logo

lieutenant-api's Introduction

Project Syn: Lieutenant API

Rest API to provide services like inventory, cluster registry, tenant management and GitOps helper.

Please note that this project is in it's early stages and under active development.

This repository is part of Project Syn. For documentation on Project Syn and this component, see https://syn.tools.

Documentation

Documentation for this component is written using Asciidoc and Antora. It is located in the docs/ folder. The Divio documentation structure is used to organize its content.

You can preview the documentation using the make antora command, and then opening a browser to http://localhost:2020.

OpenAPI Spec

The API is specified in OpenAPI 3 format. It's available in the file openapi.yaml in the root folder of this project.

Run API locally

To run the API on your local workstation, follow these steps:

export KUBECONFIG=~/.kube/myconfig
export NAMESPACE=syn-lieutenant
make run

The kubeconfig must grant access to the cluster.

Check with curl localhost:8080/healthz if the API is responding.

Example queries

Done with HTTPie, but also works with plain curl.

Create Tenant

http localhost:8080/tenants Authorization:"Bearer $(kubectl get secrets test-token-zzzzz -o json | jq ".data.token" -r | base64 --decode)" displayName="Syn Corp"

Query Tenants

http localhost:8080/tenants Authorization:"Bearer $(kubectl get secrets test-token-zzzzz -o json | jq ".data.token" -r | base64 --decode)"
  • test-token-zzzzz is the token of a ServiceAccount with all the needed RBAC rights on the underlying Kubernetes cluster

Development

API Versioning

There is no API versioning exposed. Internally the "API Evolution" approach is used which is described in this excellent blog post: API Versioning Has No "Right Way".

API Mocking

To test the API before writing actual code, API mocking can be used. One cool tool to do that is Prism. Example:

docker run --init --rm -p 4010:4010 -v $(pwd):/tmp stoplight/prism:3 mock -h 0.0.0.0 "/tmp/openapi.yaml"

curl http://localhost:4010/tenants

Code Generation

As the API spec is written with OpenAPI, the OpenAPI Generator is used to generate the Go boilerplate code.

Object Name Generation

Some API endpoints store data in Kubernetes objects. These objects must be named like this:

pwgen -A -B 6 1

Links

Some good links which help with OpenAPI development:

Contributing and license

This library is licensed under BSD-3-Clause. For information about how to contribute see CONTRIBUTING.

lieutenant-api's People

Contributors

akosma avatar bastjan avatar ccremer avatar cimnine avatar corvus-ch avatar glrf avatar kidswiss avatar mhutter avatar renovate-bot avatar renovate[bot] avatar srueg avatar tobru avatar zugao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

zugao

lieutenant-api's Issues

Throw an error for tenant registration requests with invalid GitRepo URL

When registering a Tenant, if the Tenant GitRepo URL is provided in an incorrect format (e.g. ssh://[email protected]:group/tenant-repo.git, note the colon after git.example.com), the Lieutenant API silently fails to fill in the field spec.gitRepoTemplate of the resulting tenant.

In terms of user experience, it would be nicer to return an error if we receive a request to create a tenant with an invald GitRepo URL.

Steps to Reproduce the Problem

  1. Register a tenant with an invalid GitRepo URL (e.g. use a colon after the git host)

Actual Behavior

The registration request with the invalid GitRepo URL results in a Tenant object with an empty spec.gitRepoTemplate field.

With the described invalid input (colon after the host instead of a slash) we return nil either because parsing the provided value as an URL fails (lines 310-313), or because we don't have enough path parts in the parsed URL (lines 314-318):

url, err := url.Parse(*repo.Url)
if err != nil {
return nil
}
pathParts := strings.Split(url.Path, "/")
pathParts = pathParts[1:]
if len(pathParts) < 2 {
return nil
}

Expected Behavior

The API should reject requests with GitRepo type auto and a GitRepo URL which cannot be parsed with an error, as a tenant resulting from this combination will not be usable in any case.

Make `gitRepo` in Tenant object mandatory

Make the field gitRepo.url on the Tenant object mandatory.

While it is possible today to create a Tenant without specifying a gitRepo.url, it doesn't really make sense because in practice it's undefined where this git repo will be stored and it is most likely different per customer. With this change it shouldn't be possible anymore to create a Tenant without specifying where the tenant repo is stored.

Expose Bootstrap Token Reset Functionality in API

Context

It happens every so often that more time passes between cluster registration in Lieutenant and the actual bootstrapping of Steward so that the bootstrap token already expired. Or the same cluster needs to be replaced again with the same cluster ID, but the bootstrap token has already been used.

Expose a functionality in the API to reset the cluster bootstrap token to be valid (again).

Manual process, directly on the Kubernetes API object:

curl -k -H "${LIEUTENANT_AUTH}" -H "Content-Type: application/json-patch+json" -X PATCH -d '[{ "op": "remove", "path": "/status/bootstrapToken" }]' "https://localhost:6443/apis/syn.tools/v1alpha1/namespaces/lieutenant/clusters/${CLUSTER_ID}/status"

It boils down to remove the field .status.bootstrapToken from the Cluster object, the bootstrap token gets recreated by the Lieutenant Operator automatically again.

Alternatives

Only document how to reset the bootstrap token, not exposing any automation for it.

Assess and Fix API Slowness

The API feels very slow when working with many objects (see integration in VSHN Portal). While this is at first sight a cosmetic issue, it hinders to have a good user feeling.

Steps to Reproduce the Problem

  1. Login to control.vshn.net
  2. Browse around in Lieutenant section
  3. Feel the slowness

Actual Behavior

It's very slow, also reported by the Portal itself.

Expected Behavior

It's fast.

Allow update of Global GitRepo Settings

The fields introduced in #90 (gitRepoRevision, globalGitRepoURL, globalGitRepoRevision) cannot be updated via the API because the corresponding code is missing.

Updating these fields must be possible.

Provide a simple way to start the Lieutenant API

Context

As a user, I want to have the ability to easily start the lieutenant API without having to go through the hassle of installing all needed software like go, make or cloning this repository, etc.

Preferentially, I would like to use docker to run an instance of the API, so I can work/try out on Commodore more easily.

Possible way of running:

    docker run --rm -v $HOME/.kube/myconfig:$HOME/.kube/myconfig -d -p 8080:8080 vshn/lieutenant-api

If you like this proposal, I can share a PR with the solution I'm currently using. The only problem I'm facing is that I don't know how to get the API Token in a local instance.

Alternatives

Can not think of any.

Rework Documentation of Lieutenant API

Currently the documentation of Lieutenant API is relatively scarce and should be updated to make using and understanding the Lieutenant API a breeze.

The documentation should:

  • describe the concept of Lieutenant API: What does it do? How does it work?
  • show the configuration options

Also the start page of https://syn.tools/lieutenant-api/index.html should give a short intro to Lieutenant API, so that it gives an idea what it's all about.

Adhere to https://documentation.divio.com/ for putting the pages and content into the right context.

  • Make sure the menu entry Technical reference -> API documentation works again.

Support HTTP Proxy Settings in InstallSteward

Context

When applying the manifest returned by an installURL to a cluster which requires an HTTP proxy to communicate with the outside world, the deployment will fail to get ready.
It would be nice to have an additional query parameter which could be used to pass HTTP proxy settings to the lieutenant API which would then be rendered into the manifest returned by the installURL.
As a workaround, I patched the returned manifest locally before applying it to the cluster.

Affected code: https://github.com/projectsyn/lieutenant-api/blob/master/pkg/service/steward.go

Alternatives

An alternative implementation could be the usage of cluster facts for HTTP proxy settings.

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

Filtering clusters by tenant does not work

According to the documentation, clusters can be filtered by tenant ID. This does not work.

Steps to Reproduce the Problem

curl -sS -H "$LIEUTENANT_AUTH" "https://${LIEUTENANT_URL}/clusters?tenant=t-xxx" | jq '.[].displayName'

Actual Behavior

  • List of ALL clusters in the API

Expected Behavior

  • List of the specific tenant's clusters.

Workaround

curl -sS -H "$LIEUTENANT_AUTH" "https://${LIEUTENANT_URL}/clusters" | jq '.[] | select(.tenant == "t-xxx") | .displayName'

Host Lieutenant OpenAPI Specification

Generate the OpenAPI docs for the specification. Make sure the API itself hosts them (i.e. on /docs) and include them in the Antora docs of the API.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

dockerfile
Dockerfile
  • docker.io/golang 1.22
github-actions
.github/workflows/release.yml
  • actions/checkout v4
  • mikepenz/release-changelog-builder-action v4
  • actions/create-release v1
.github/workflows/test.yml
  • actions/checkout v4
  • actions/checkout v4
  • actions/checkout v4
gomod
go.mod
  • go 1.22.0
  • go 1.22.3
  • github.com/AlekSi/pointer v1.2.0
  • github.com/cosmtrek/air v1.52.0
  • github.com/deepmap/oapi-codegen/v2 v2.1.0
  • github.com/getkin/kin-openapi v0.123.0
  • github.com/go-logr/logr v1.4.2
  • github.com/hashicorp/golang-lru v1.0.2
  • github.com/labstack/echo/v4 v4.12.0
  • github.com/oapi-codegen/echo-middleware v1.0.1
  • github.com/oapi-codegen/runtime v1.1.1
  • github.com/oapi-codegen/testutil v1.1.0
  • github.com/projectsyn/lieutenant-operator v1.11.6
  • github.com/stretchr/testify v1.9.0
  • github.com/taion809/haikunator v0.0.0-20150324135039-4e414e676fd1@4e414e676fd1
  • go.uber.org/multierr v1.11.0

  • Check this box to trigger a request for Renovate to run again on this repository

Research Feasibility to Remove the Lieutenant API Completely

Context

A discussion came up if the Lieutenant API is actually an added value to Project Syn. All information needed could also be acquired by directly accessing the Kubernetes API and the CRDs of Lieutenant Operator. The API adds some additional features and does not only do data conversion from one into another format, this needs to be taken in to consideration while working on this issue.

Task

  1. Create a list of additional functionality the API adds on top of CRUD to Lieutenant Operator CRDs and list options to replace this functionality by other means.
  2. List changes needed to Commodore and other tools currently using the Lieutenant API.
  3. Write down other implications of removing the API: What would we have to do?

Write Documentation

Write some basic documentation about this tool. If possible include the generated OpenAPI spec documentation in Antora.

Task Deliverables

  • Basic documentation about lieutenant-api

Improving the build experience

Epic: As a developer, especially a first-time user of the project, I do not want to get avoidable error message in the middle of a build. Instead, a preparation step before the build will tell me that the build will succeed with guarantee or at least with high likelihood.

Feature: Think autoconf + ahead-of-time check of available resources. This reduces the need to read + follow documentation and puts more of these preparations into code. It could be implemented first in one Syn component and then in similar form rolled out to others to decrease the participation barrier.

Something like:

diff --git a/Makefile b/Makefile
index 00fd32f..a40b63d 100644
--- a/Makefile
+++ b/Makefile
@@ -88,3 +88,10 @@ $(web_dir)/index.html: playbook.yml $(pages)
 .PHONY: check
 check: generate-api-docs
        $(vale_cmd)
+
+.PHONY: prep
+prep:
+       @go version >/dev/null 2>&1 || echo "Missing dependency 'go'. Please install: golang / https://golang.org/."
+       @test `go version | sed 's/.*go1\.\([[:digit:]]\+\)\..*/\1/'` -gt 12 || echo "Go version outdated, needs 1.13+, please update: golang / https://golang.org/."
+       @test `LANG=C df $(PWD) | tail -1 | awk '{print $$4}'` -gt 4000000 || echo "Disk space likely insufficient, needs 4+ GB."
+       @echo "All fine. Type 'make'."

More memorable cluster and tenant names

Today I have had the chance to work with the lieutenant API while synfecting several clusters. Even with smaller numbers of tenants and clusters, I got confused and had to concentrate really hard to not mix them up. I suggest to switch to a more memorable naming scheme.

Personally, I prefer something in the format <adjective>-<noun>-<four digit number> as it can be generated with https://github.com/taion809/haikunator.

Race conditions when creating cluster: 409 response or missing installURL

There are at least two race conditions when creating a cluster:

  • API returns 409 "conflict" with body '{"reason":"Operation cannot be fulfilled on clusters.syn.tools 'c-unicornfarts2': the object has been modified; please apply your changes to the latest version and try again"}' or similar
  • API returns new cluster object without the installURL being set

I assume the two problems are related.

Steps to Reproduce the Problem

Create a cluster with valid data, e.g. the problem has been reproduced by POSTing
{"id":"c-unicornfarts7","displayName":"Unicorn FARTS 7!","annotations":{},"tenant":"t-sg-test","facts":{"cloud":"c","service_level":"best_effort","access_policy":"regular","release_channel":"a","sales_order":"NONE","distribution":"b"},"gitRepo":{"type":"auto"}}
to /clusters.

Being a race condition the problem is hard to reproduce reliably.

Actual Behavior

Sometimes it works, sometimes I get back a cluster that doesn't have an installURL, sometimes I get back a 409 conflict with body {"reason":"Operation cannot be fulfilled on clusters.syn.tools 'c-unicornfarts7': the object has been modified; please apply your changes to the latest version and try again"}

Expected Behavior

I reliably get back a cluster object with installURL set.

Moreover the 409 response code does not appear in https://syn.tools/lieutenant-api/references/index.html#_createcluster . Whether that's an implementation bug or a documentation bug I don't know, but it should be fixed one way or another.

Allow Setting ID in API

Context

Allow to set the ID of the object to be created (Tenant or Cluster) instead of auto-generating it. If the ID is not passed, the ID should still be auto-generated.

Alternatives

The generated IDs are not always a good idea and has been brought up as a usability issue from time to time. So the only alternative is not doing it.

Introduce Goreleaser to pipeline

Use Goreleaser to build and release new releases to GitHub.

Goreleaser has several advanced packaging features:

  • Docker build & push, including floating tag support
  • Run test & vet before build, with Hooks
  • Create checksum files, and sign with GPG
  • Attach binary (or zip archive) to releases
  • Create DEB and RPM packages

Example Implementation which implements all of the above (including pipeline)

Allow Cluster Facts and Annotations to be deleted via API

Context

Currently cluster facts and annotations (cluster and tenants) can only be added via the API but not deleted. Make it possible to be able to delete cluster facts and annotations (cluster and tenant) via the API.

Use cases to support

Current behaviour

Given a cluster
And the cluster has the annotation "foo" set to "foo-value"
And the cluster has the annotation "bar" set to "bar-value"
When I submit a patch request not containing anything related to annotations
Then the cluster has the annotation "foo" set to "foo-value"
And the cluster has the annotation "bar" set to "bar-value"
Given a cluster
And the cluster has the annotation "foo" set to "foo-value"
And the cluster has the annotation "bar" set to "bar-value"
When I submit a patch request
"""
annotations:
  bar: "bar-value-changed"
"""
Then the cluster has the annotation "foo" set to "foo-value"
And the cluster has the annotation "bar" set to "bar-value-changed"
Given a cluster
And the cluster has the annotation "foo" set to "foo-value"
When I submit a patch request
"""
annotations:
  bar: "bar-value"
"""
Then the cluster has the annotation "foo" set to "foo-value"
And the cluster has the annotation "bar" set to "bar-value"
Given a cluster
And the cluster has the annotation "foo" set to "foo-value"
And the cluster has the annotation "bar" set to "bar-value"
When I submit a patch request
"""
annotations:
  bar: ""
"""
Then the cluster has the annotation "foo" set to "foo-value"
And the cluster does not have the annotation "bar" set to ""

Missing behaviour

Given a cluster
And the cluster has the annotation "foo" set to "foo-value"
And the cluster has the annotation "bar" set to "bar-value"
When I submit a patch request
"""
annotations:
  bar: ~
"""
Then the cluster has the annotation "foo" set to "foo-value"
And the cluster does not have the annotation "bar"

The trigger is any nil value. Empty string values do not trigger the removal.

For Clusters, that behaviour applies also to the field spec.facts.

Set valid clusterTemplate when creating Tenant Objects

Context

projectsyn/lieutenant-operator#110 added a cluster template to the Tenant object which is not accessible throught the API. This is an issue as ``spec.clusterTemplate.gitRepoTemplate.apiSecretRef.name` needs to be set. The name of that secret differs between instances of Lieutenant.

When creating a tenant the following structure must be set:

{
  "spec": {
    "clusterTemplate": {
      "gitRepoTemplate": {
        "apiSecretRef": {
          "name": "<name of secret>"
        },
        "path": "",
        "repoName": "{{ .Name }}"
      },
      "tenantRef": {}
    }
  }
}

This could be done by exposing the field clusterTemplate as a whole or the variable field of the secret name. It also would be acceptable to have the secret name configured as an environment variable and have that data structure hard coded.

Expose Object Annotations in API

For various use cases we need the annotations of the Tenant and Cluster object exposed via the API so that annotations are available in the respective objects and can be created, read, updated and deleted.

Expand the OpenAPI schema for annotations support and implement the needed functionality in the API.

Dependency Dashboard

This issue provides visibility into Renovate updates and their statuses. Learn more

This repository currently has no open or pending branches.

Update `getServiceAccountToken()` to work correctly on Kubernetes 1.24+

Context

Kubernetes 1.24+ doesn't create service account token secrets by default anymore. Additionally, when creating a token secret explicitly, the secret isn't added to field secrets in the ServiceAccount object.

We need to update getServiceAccountToken() to no longer find the token secret via the service account's secrets field, but instead by looking at the secret's kubernetes.io/service-account.name or kubernetes.io/service-account.uid annotations.

Since existing ServiceAccount token secrets already have those annotations (at least secrets created on Kubernetes 1.22+), we don't need to have multiple ways to lookup secrets based on whether the ServiceAccount and token secret were created on 1.24 or before.

Alternatives

Extend the operator to add the manually created secret to the ServiceAccount's secrets field.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.