Skip to content

Commit

Permalink
feat: add mango-helper cli tool mh
Browse files Browse the repository at this point in the history
Been using this for a while, finally bothering to tidy it up to push up.
Small tool to help make working with mango easier.

`mh` has 2 primary subcommands:
- `inventory` to work with an inventory directory
- `mango` to work with a running mango server instance

Options are further documented in readme, but the gist is that it's
possible to create a skeleton inventory, list inventory items (including
filtering by host enrollment), collect pprof profiles from running mango
instances, and collect metrics from running mango instances.
  • Loading branch information
tjhop committed Oct 21, 2024
1 parent add15ac commit 6a97bc5
Show file tree
Hide file tree
Showing 23 changed files with 1,050 additions and 16 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist/
.golangci-lint/
mango
mh
14 changes: 13 additions & 1 deletion .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
version: 2

builds:
- env:
- id: mango
env:
- CGO_ENABLED=0
goos:
- linux
Expand All @@ -11,6 +12,17 @@ builds:
- -X github.com/tjhop/mango/internal/version.Commit={{ .Commit }}
binary: mango
main: './cmd/mango'
- id: mh
env:
- CGO_ENABLED=0
goos:
- linux
ldflags:
- -X github.com/tjhop/mango/internal/version.BuildDate={{ .CommitDate }}
- -X github.com/tjhop/mango/internal/version.Version={{ .Version }}
- -X github.com/tjhop/mango/internal/version.Commit={{ .Commit }}
binary: mh
main: './cmd/mh'
gomod:
proxy: true
mod: mod
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ FROM cgr.dev/chainguard/busybox:latest
COPY --from=certs /etc/ssl/certs /etc/ssl/certs

COPY mango /usr/bin/mango
COPY mh /usr/bin/mh
ENTRYPOINT ["/usr/bin/mango"]
CMD ["--inventory.path", "/opt/mango/inventory"]
1 change: 1 addition & 0 deletions Dockerfile-testbox-arch
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ RUN pacman -Syu --needed --noconfirm && \

# setup mango
COPY ./mango /usr/bin/mango
COPY ./mh /usr/bin/mh
COPY ./packaging/systemd/mango.service /etc/systemd/system/
COPY ./test/mockup/services/mango/test-flags.conf /etc/systemd/system/mango.service.d/test-flags.conf
RUN systemctl enable mango.service
Expand Down
1 change: 1 addition & 0 deletions Dockerfile-testbox-ubuntu
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ RUN apt-get update && \

# setup mango
COPY ./mango /usr/bin/mango
COPY ./mh /usr/bin/mh
COPY ./packaging/systemd/mango.service /etc/systemd/system/
COPY ./test/mockup/services/mango/test-flags.conf /etc/systemd/system/mango.service.d/test-flags.conf
RUN systemctl enable mango.service
Expand Down
19 changes: 13 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,19 @@ lint:
mkdir -p ${GOLANGCILINT_CACHE} || true
podman run --rm -v ${CURDIR}:/app -v ${GOLANGCILINT_CACHE}:/root/.cache -w /app docker.io/golangci/golangci-lint:latest golangci-lint run -v

## binary: build a binary
binary: fmt tidy lint
goreleaser build --clean --single-target --snapshot --output .
## build-mango build the `mango` configuration management server
build-mango: fmt tidy lint
goreleaser build --clean --single-target --snapshot --output . --id "mango"

## build: alias for `binary`
build: binary
## build-mh build `mh`, the helper tool for mango
build-mh: fmt tidy lint
goreleaser build --clean --single-target --snapshot --output . --id "mh"

## build: alias for `build-mango build-mh`
build: build-mango build-mh

## binary: alias for `build`
binary: build

## container: build container image with binary
container: binary
Expand All @@ -45,7 +52,7 @@ podman: container
docker: container

## test-container: build test containers with binary for testing purposes
test-container: binary container
test-container: binary
podman image build -t "mango-test-ubuntu" -f Dockerfile-testbox-ubuntu .
podman image build -t "mango-test-arch" -f Dockerfile-testbox-arch .

Expand Down
101 changes: 93 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ While packages are built for several systems, there are currently no plans to at

## Usage

### Binary Usage
### `mango`
#### Binary Usage

```bash
mango --inventory.path /path/to/inventory
Expand Down Expand Up @@ -61,18 +62,101 @@ https://www.vim.org/iccf/
https://www.iccf.nl/
```
### Container Usage
#### Container Usage
Since `mango` is intended to be run on the system it is managing and thus requires access to the host system, if you must run `mango` as a container, you may want to use the `--privileged` flag.
```
```bash
# docker works too, but podman is wonderful
podman run \
-v /path/to/inventory:/opt/mango/inventory \
--privileged \
ghcr.io/tjhop/mango
```
### `mango-helper`
`mango-helper` is a helper utility that ships with `mango` to make it easier to interact with various aspects of `mango`:
```bash
mh -h
Mango Helper is a utility tool to aid in working with mango
Usage:
mh [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
inventory Command to interact with mango inventory
mango Command to interact with a running mango server
Flags:
-h, --help help for mh
-l, --logging.level string Logging level may be one of: [debug, info, warning, error] (default "info")
--logging.output string Logging format may be one of: [logfmt, json] (default "logfmt")
-v, --version version for mh
Use "mh [command] --help" for more information about a command.
```
The `mh inventory` command has several subcommands available to assist in working with the mango inventory:
```bash
mh inventory -h
Command to interact with the mango inventory, such as initializing skeleton inventory directory structures
Usage:
mh inventory [command]
Aliases:
inventory, inv
Available Commands:
directive Command to interact with mango directives in the inventory
group Command to interact with mango groups in the inventory
host Command to interact with mango hosts in the inventory
init Create an empty inventory
module Command to interact with mango modules in the inventory
role Command to interact with mango roles in the inventory
Flags:
--enrolled-only Only return modules that the provided host is enrolled for
-h, --help help for inventory
--hostname string (Requires root) Custom hostname to use [default is system hostname]
-i, --inventory.path string Path to mango configuration inventory
Global Flags:
-l, --logging.level string Logging level may be one of: [debug, info, warning, error] (default "info")
--logging.output string Logging format may be one of: [logfmt, json] (default "logfmt")
Use "mh inventory [command] --help" for more information about a command.
```
The `mh mango` command has further subcommands available to interact with a running mango server:
```bash
mh mango -h
Command to interact with a running mango server, including interacting with pprofs, metrics, etc
Usage:
mh mango [command]
Available Commands:
metrics Command to simplify metrics interactions for mango
pprof Command to simplify pprof interactions for mango
Flags:
--address string Address of the running mango server (default "127.0.0.1:9555")
-h, --help help for mango
Global Flags:
-l, --logging.level string Logging level may be one of: [debug, info, warning, error] (default "info")
--logging.output string Logging format may be one of: [logfmt, json] (default "logfmt")
Use "mh mango [command] --help" for more information about a command.
```
## Configuration Management
`Mango` is intended to be run as a daemon on the system that it will be managing.
Expand All @@ -81,21 +165,22 @@ ghcr.io/tjhop/mango
### Inventory
`Mango`'s inventory is based on [aviary.sh's](https://github.com/frameable/aviary.sh) inventory.
Initially, `mango` will be an aviary.sh-compatible daemon, with configurations written as scripts/executables.
A detailed explanation of the differences between `mango` and `aviary.sh`, as well as a detailed explanation of each component/file in the mango inventory, can be found below.
#### Inventory Setup
Please see [aviary.sh's documentation on inventory setup](https://github.com/frameable/aviary.sh#inventory-setup) for more information.
An inventory can be created using the companion `mango-helper` tool that ships with mango releases/builds:
```
```bash
mkdir inventory
cd inventory
mkdir {groups,hosts,modules,roles,directives}
touch {groups,hosts,modules,roles,directives}/.gitkeep
mh inventory init
git init
git add .
git commit -m "initial commit"
```
The `mh inventory` command also has other utility functions to make working with the inventory easier. See [mango-helper](#mango-helper) for more details.
*NOTE*: While `aviary.sh`'s inventory system is designed to work with bash
scripts, it's possible to write a module in any language. Mango treats module
test scripts as optional (yet recommended), and module/host variables are
Expand Down
87 changes: 87 additions & 0 deletions cmd/mh/directive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package main

import (
"fmt"
"log/slog"
"path/filepath"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
dirCmd = &cobra.Command{
Use: "directive",
Aliases: []string{"directives"},
Short: "Command to interact with mango directives in the inventory",
Long: "Command to interact with mango directive, including adding, deleting, etc",
}

dirAddCmd = &cobra.Command{
Use: "add",
Aliases: addCmdAliases,
Short: "Create an empty directive with the provided name",
Long: "Command to add a new directive by adding a new directory with the given" +
" name and creating empty directive files to bootstrap",
Args: cobra.ExactArgs(1),
Run: directiveAdd,
}

dirDeleteCmd = &cobra.Command{
Use: "delete",
Aliases: delCmdAliases,
Short: "Delete the directive with the provided name",
Long: "Command to delete a directive by recursively removing it from the inventory",
Args: cobra.ExactArgs(1),
Run: directiveDelete,
}

dirListCmd = &cobra.Command{
Use: "list",
Aliases: listCmdAliases,
Short: "List directives in the inventory",
Long: "List directives in the inventory",
Args: cobra.ExactArgs(0),
Run: directiveList,
}
)

func init() {
inventoryCmd.AddCommand(dirCmd)
dirCmd.AddCommand(dirAddCmd)
dirCmd.AddCommand(dirDeleteCmd)
dirCmd.AddCommand(dirListCmd)
}

func directiveAdd(cmd *cobra.Command, args []string) {
dirName := args[0]
logger := slog.Default().With("component", "directive", "directive", dirName)

dirDir := filepath.Join(viper.GetString("inventory.path"), "directives")
dirPath := filepath.Join(dirDir, dirName)

if err := inventoryAddFile(dirPath); err != nil {
logger.Warn("Error creating directive file", "err", err, "file", dirPath)
} else {
logger.Debug("Created directive file", "file", dirPath)
}
}

func directiveDelete(cmd *cobra.Command, args []string) {
dirName := args[0]
logger := slog.Default().With("component", "directive", "directive", dirName)

dirDir := filepath.Join(viper.GetString("inventory.path"), "directives")
dirPath := filepath.Join(dirDir, dirName)

if err := inventoryRemoveAll(dirPath); err != nil {
logger.Warn("Error deleting directive", "err", err)
}
}

func directiveList(cmd *cobra.Command, args []string) {
inv := loadInventory()
for _, d := range inv.GetDirectives() {
fmt.Println(d.String())
}
}
Loading

0 comments on commit 6a97bc5

Please sign in to comment.