diff --git a/astro.config.mjs b/astro.config.mjs index a7bc050..6860216 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -109,6 +109,7 @@ export default defineConfig({ integrations: [ starlight({ title: 'grlx Docs', + lastUpdated: true, description: 'Documentation for grlx. Fleet configuration management that is low overhead, dependency free, and easy to install.', components: { @@ -129,16 +130,21 @@ export default defineConfig({ github: 'https://github.com/gogrlx/grlx', 'x.com': 'https://x.com/gogrlx', discord: 'https://discord.gg/RNsZ3KWjXm', + email: 'mailto:grlx@adatomic.com?subject=Question' }, sidebar: [ { label: 'Getting Started', link: '/getting-started' }, + { + label: 'Architecture', + autogenerate: { directory: 'architecture' }, + }, { label: 'Ingredients', autogenerate: { directory: 'ingredients' }, }, { - label: 'Architecture', - autogenerate: { directory: 'architecture' }, + label: 'Recipes', + autogenerate: { directory: 'recipes' }, }, ], }), diff --git a/cspell.json b/cspell.json new file mode 100644 index 0000000..c7e2a3c --- /dev/null +++ b/cspell.json @@ -0,0 +1,13 @@ +{ + "version": "0.2", + "language": "en", + "words": [ + "grlx", + "FARMERINTERFACE", + "FARMERORGANIZATION", + "NATS", + "FARMERBUSPORT", + "FARMERAPIPORT", + "PUBKEYS", + ], +} diff --git a/flake.nix b/flake.nix index 84f828a..a198b43 100644 --- a/flake.nix +++ b/flake.nix @@ -23,7 +23,7 @@ # Equivalent to inputs'.nixpkgs.legacyPackages.hello; devShells.default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ nodejs_18 nodePackages_latest.prettier]; + nativeBuildInputs = with pkgs; [ nodejs_18 nodePackages_latest.prettier nodePackages_latest.cspell ]; }; }; flake = { diff --git a/src/assets/grlx-arch-dark.webp b/src/assets/grlx-arch-dark.webp new file mode 100644 index 0000000..0c39050 --- /dev/null +++ b/src/assets/grlx-arch-dark.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c0be79de7cde17b03b1e46ef75edb2baebebd32b0605bad3fcb3a2babe924e6 +size 68258 diff --git a/src/assets/grlx-arch-light.webp b/src/assets/grlx-arch-light.webp new file mode 100644 index 0000000..8e42672 --- /dev/null +++ b/src/assets/grlx-arch-light.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:852c13313142bfb83fefad5bbabd64f5e9f9eba95ef7bf180553dbe140ba2f24 +size 66244 diff --git a/src/components/ArchitectureImage.astro b/src/components/ArchitectureImage.astro new file mode 100644 index 0000000..9f6482d --- /dev/null +++ b/src/components/ArchitectureImage.astro @@ -0,0 +1,16 @@ +--- +import { Image } from 'astro:assets' +import darkArch from "../assets/grlx-arch-dark.webp" +import lightArch from '../assets/grlx-arch-light.webp' +--- + +ADAtomic logo + diff --git a/src/content/docs/architecture/overview.md b/src/content/docs/architecture/overview.md deleted file mode 100644 index 64d4c26..0000000 --- a/src/content/docs/architecture/overview.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: Overview -description: A brief description of the grlx architecture ---- -At a high level our architecture looks like the following: - -We can boil down the `grlx` into three different parts: the farmer, the sprout, and the CLI. - -## Farmer - -The farmer is your control server. This has analogs in other similar configuration platforms. In SaltStack, this is your Salt Master, or in Chef, your Chef Server. `grlx` utilizes the farmer for things like authentication, job processing, and [ingredients](/architecture/overview#ingredients). - -## Sprout - -The sprout is what the farmer manages. This is similar to a Salt Minion in SaltStack or a Chef Client in Chef. Jobs are received from the farmer over the NATS message bus for actions to be performed on the sprout itself. - -## CLI - -## Ingredients diff --git a/src/content/docs/architecture/overview.mdx b/src/content/docs/architecture/overview.mdx new file mode 100644 index 0000000..06838b0 --- /dev/null +++ b/src/content/docs/architecture/overview.mdx @@ -0,0 +1,23 @@ +--- +title: Overview +description: A brief description of the grlx architecture +--- + +import ArchitectureImage from '../../../components/ArchitectureImage.astro' + +At a high level the grlx architecture looks like the following: + + +We can boil down the `grlx` into three different parts: the farmer, the sprout, and the CLI. + +## Farmer +The farmer is your management server running the `grlx-farmer` binary. The binary can run as a systemd service or be hosted in a container. This has analogs in other similar configuration platforms such as a Salt Master in SaltStack or a Chef Server in Chef. grlx utilizes the farmer for things like authentication, job processing, and [ingredients](/architecture/overview#ingredients). Additionally, the farmer contains is responsible for holding your [recipes](/architecture/overview#recipes). + +## Sprout +The sprout is a managed node running the `grlx-sprout` binary. Sprouts receive commands from the farmer over the NATS message bus. These can be immediate shell commands, or actions that are performed by Ingredients defined in a recipe (e.g. ensure that a file exists, a service is started). Sprouts are similar to a Salt Minion in SaltStack or a Chef Client in Chef. Jobs are received from the farmer over the NATS message bus. Sprouts will then execute the job and report back to the farmer the results of the job. + +## CLI +The CLI is a tool used to interact with the farmer and manage sprouts. The CLI is used to accept keys from sprouts and `cook` (run) recipes that are hosted on the farmer. The CLI also contains tools to tail the traffic over the NAT bus, test sprout connections, and run arbitrary commands on sprouts. + +## Recipes +Recipes are the core of grlx and are responsible for handling the configuration of your sprouts. Recipes are written with the `.grlx` extension and are a combination of YAML and Go templates. Recipes are stored on the farmer and are executed by the sprouts. Recipes are responsible for defining the [ingredients](/architecture/overview#ingredients) and in what order they are executed. For more information see the [recipes](/recipes) section. diff --git a/src/content/docs/getting-started.mdx b/src/content/docs/getting-started.mdx index 374f7fc..a0ffa73 100644 --- a/src/content/docs/getting-started.mdx +++ b/src/content/docs/getting-started.mdx @@ -240,4 +240,7 @@ grlx -T \* cmd run --out json -- uname -a #### Uninstalling -If you ever need to uninstall `grlx` +If you ever need to uninstall the `grlx-farmer`, you can do so with the following commands: +```bash +curl -L https://bootstrap.grlx.dev/latest/farmer | UNINSTALL=true sudo bash +``` diff --git a/src/content/docs/ingredients/cmd.md b/src/content/docs/ingredients/cmd.md index 3b815a4..e96b8e1 100644 --- a/src/content/docs/ingredients/cmd.md +++ b/src/content/docs/ingredients/cmd.md @@ -10,9 +10,19 @@ Runs shell commands against a sprout |-----------|------|----------|-------------| | _name_ | string | true | the command to run | _runas_ | string | false | user who will run this command +| _path_ | string | false | the path to the binary, this is prepended to the name +| _cwd_ | string | false | the directory to run this command +| _env_ | list | false | environmental variables to set like the following: key1=value1 +| _timeout_ | string | false | set a timeout for the command using [Go Duration](https://pkg.go.dev/time#ParseDuration) ```yaml cmd.run: - name: go version - runas: super-cool-user + - path: /usr/local/bin + - cwd: /tmp + - env: + - GOOS=linux + - GOARCH=arm64 + - timeout: 10s ``` diff --git a/src/content/docs/ingredients/file-providers.md b/src/content/docs/ingredients/file-providers.md index 7540a9e..6b2dbe2 100644 --- a/src/content/docs/ingredients/file-providers.md +++ b/src/content/docs/ingredients/file-providers.md @@ -12,7 +12,7 @@ type FileProvider interface { Verify(context.Context) (bool, error) } ``` -By default, `grlx` has three built-in providers: local, HTTP, and S3. +By default, `grlx` has two built-in providers: local and HTTP. ## Local The local provider would be how you would use a file from your host system. @@ -31,6 +31,3 @@ file.cached: - source: https://go.dev/dl/go1.21.3.src.tar.gz - hash: sha256=186f2b6f8c8b704e696821b09ab2041a5c1ee13dcbc3156a13adcf75931ee488 ``` - -## TODO: S3 -The S3 allows you to get a file from an S3 compatible bucket. diff --git a/src/content/docs/ingredients/file.md b/src/content/docs/ingredients/file.md index ecd0000..4ec9256 100644 --- a/src/content/docs/ingredients/file.md +++ b/src/content/docs/ingredients/file.md @@ -12,7 +12,7 @@ Deletes a file or directory #### Example ```yaml file.absent: - name: ~/.config/sytemd/user/backup.service + name: ~/.config/systemd/user/backup.service ``` ## **file.append** @@ -61,7 +61,7 @@ Copies content into a given file #### Example ```yaml file.content: - - name: /srv/ngnix/nginx.conf + - name: /srv/nginx/nginx.conf - makdirs: true - text: | server { @@ -106,7 +106,7 @@ file.directory: - makdirs: false - user: grlx - group: grlx - - dir_moode: 755 + - dir_mode: 755 - recurse: false ``` @@ -147,3 +147,20 @@ file.symlink: - name: ~/localbash - target: /usr/bin/bash ``` + +## **file.touch** +Performs a `touch` on a file +| parameter | type | required | description | +|-----------|------|----------|-------------| +| _name_ | string | yes | the name/path of the file +| _atime_ | time (RFC339) | no | the access time to set the file to, set to the current time by default +| _mtime_ | time (RFC339) | no | the modified time to set the file to, sets to the current time by default +| _makedirs_ | bool | yes | whether or not to create any provided parent directories, false by default +```yaml +file.touch: + - name: /tmp/parent/new-file + - atime: Mon, 06 Nov 2023 00:00:00 +0000 + - mtime: Mon, 06 Nov 2023 00:00:00 +0000 + - makedirs: true +``` + diff --git a/src/content/docs/ingredients/groups.md b/src/content/docs/ingredients/groups.md new file mode 100644 index 0000000..818991f --- /dev/null +++ b/src/content/docs/ingredients/groups.md @@ -0,0 +1,39 @@ +--- +title: grlx.ingredients.group +desc: An overview of grlx.ingredients.group +--- +The group ingredient handles group operations on sprouts. +## **group.absent** +Removes a group +#### Parameters +| parameter | type | required | description | +|-----------|------|----------|-------------| +| _name_ | string | no | The name of the group to remove +```yaml +group.absent: + - name: sprout-group +``` + +## **group.exists** +Validates if a group exists +#### Parameters +| parameter | type | required | description | +|-----------|------|----------|-------------| +| _name_ | string | yes | The group name to check +```yaml +group.exists: + - name: sprout-group +``` + +## **group.present** +Creates a group if it does not exist +#### Parameters +| parameter | type | required | description | +|-----------|------|----------|-------------| +| _name_ | string | yes | The name of the group to create +| _gid_ | int | no | The GID of the group to create +```yaml +group.present: + - name: sprout-group + - gid: 1000 +``` diff --git a/src/content/docs/ingredients/service-providers.md b/src/content/docs/ingredients/service-providers.md index 108d2aa..f6d27be 100644 --- a/src/content/docs/ingredients/service-providers.md +++ b/src/content/docs/ingredients/service-providers.md @@ -2,7 +2,7 @@ title: grlx.ingredients.service.providers description: grlx built-in service providers --- -grlx has a concept of service providers for different ways to interact with a sprout's various services. This uses a provider interface to keep this extensible and provide a standard way to interact with different service managers. The `go` interface for Service Providers looks like the following: +grlx has a concept of service providers for different ways to interact with a sprout's various services. This uses a provider interface to keep this extensible and provide a standard way to interact with different service managers. The Go interface for Service Providers looks like the following: ```go type ServiceProvider interface { Properties() (map[string]interface{}, error) @@ -30,7 +30,7 @@ type ServiceProvider interface { By default, grlx only has a `systemd` provider. ## systemd -The local provider would be how you would use a file from your host system. +The [`systemd` provider](/ingredients/service) allows for control over a sprout's `systemd` services. #### Example ```yaml service.disabled: diff --git a/src/content/docs/ingredients/user.md b/src/content/docs/ingredients/user.md new file mode 100644 index 0000000..7475818 --- /dev/null +++ b/src/content/docs/ingredients/user.md @@ -0,0 +1,51 @@ +--- +title: grlx.ingredients.user +desc: An overview of grlx.ingredients.user +--- +The user ingredient handles user operations on sprouts. +## **user.absent** +Removes a user if it exists +#### Parameters +| parameter | type | required | description | +|-----------|------|----------|-------------| +| _name_ | string | yes | the name of the user to be removed +```yaml +user.absent: + - name: super-sprout +``` + +## **user.exists** +Validates if a user exists +#### Parameters +| parameter | type | required | description | +|-----------|------|----------|-------------| +| _name_ | string | yes | The username to check +```yaml +user.exists: + - name: sprout-user +``` + +## **user.present** +Creates a new user if it does not exist +#### Parameters +| parameter | type | required | description | +|-----------|------|----------|-------------| +| _name_ | string | yes | The username of the user +| _uid_ | int | no | The UID assigned to the user +| _gid_ | int | no | The GID to the user +| _groups_ | list, string | no | A list groups the user is part of +| _shell_ | bool | no | The user login shell, false by default +| _home_ | string | no | The path to the user's home directory if one is required +```yaml +user.present: + - name: sprout-user + - uid: 1000 + - gid: 1000 + - groups: + - wheel + - media + - sudo + - shell: no + - home: /var/sprout-user +``` + diff --git a/src/content/docs/recipes/overview.md b/src/content/docs/recipes/overview.md new file mode 100644 index 0000000..2d69874 --- /dev/null +++ b/src/content/docs/recipes/overview.md @@ -0,0 +1,46 @@ +--- +title: Overview +description: An overview of grlx recipes +--- +Recipes are the core of grlx functionality, providing a structured way for developers to deploy actions to sprouts. Recipes are a collection of ingredients which can be executed against a sprout. Recipes must be placed on the farmer at `/srv/grlx/recipes/prod` (with support for other non-prod environments in the future). Furthermore, recipes can utilize [Go's builtin templating engine](https://pkg.go.dev/text/template) to provide dynamic functionality for deployment. Below is a simple example of the makeup of a recipe. +```yaml +include: + - .super-sprout-steps +steps: +{{ if props hostname super-sprout }} + install super-sprout: + file.touch: + - name: ~/super-sprout-config + requisites: + - require: super-sprout-steps-completed +{{ else }} + install normal-sprout: + file.touch: + - name: ~/normal-sprout-config +{{ end }} +``` +In this example, an include is created for a `super-sprout-steps.grlx` file. This file would contain a list of steps with a final step `grlx-sprout-steps-completed`. Next we have our list of steps, bounded by Go templates. This template checks the hostname of the sprout and renders the steps to send to the farmer. In this case, if the sprout's hostname is `super-sprout`, then it will render a template that looks like this: +```yaml +include: + - .super-sprout-steps +steps: + install super-sprout: + file.touch: + - name: ~/super-sprout-config + requisites: + - require: super-sprout-steps-completed +``` +If the hostname is anything else, the sprout will run: +```yaml +include: + - .super-sprout-steps +steps: + install normal-sprout: + file.touch: + - name: ~/normal-sprout-config +``` + +It is important to note the requisites listed. This ensures that the step from the include (`super-sprout-steps-completed`) occurs _before_ the `install-super-sprout` step is run. +:::note +Deployment of recipe steps is non-deterministic unless requisites are provided. Otherwise, are steps run as is. If order is important, than order ***must*** be specified. +::: diff --git a/src/custom.css b/src/custom.css index 43e37eb..39c3006 100644 --- a/src/custom.css +++ b/src/custom.css @@ -1,5 +1,9 @@ .discord-bg .card .icon{ - background-color: #7289da; + background-color: #5865F2; --sl-card-border: #454FBF !important; } +[data-theme="light"] .hidden{ + display: none; +} +