This commit is contained in:
18
.drone.yml
18
.drone.yml
@@ -17,6 +17,7 @@ steps:
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
- pkg.tools
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
@@ -36,13 +37,27 @@ steps:
|
||||
- go install github.com/a-h/templ/cmd/templ@latest
|
||||
- go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
|
||||
- go install github.com/swaggo/swag/cmd/swag@latest
|
||||
- go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest
|
||||
- sqlc generate
|
||||
- templ generate -path ./components
|
||||
- swag init --exclude "pkg.mod,pkg.build,pkg.tools" -o server/router/docs
|
||||
- chmod +x ./scripts/*.sh
|
||||
- ./scripts/update-swagger-ui.sh
|
||||
- ./scripts/drone.sh
|
||||
- cp ./build/cbs-linux-amd64 /shared/
|
||||
- cp ./build/vctp-linux-amd64 /shared/
|
||||
|
||||
- name: rpm
|
||||
image: ghcr.io/goreleaser/nfpm
|
||||
environment:
|
||||
TZ: UTC
|
||||
volumes:
|
||||
- name: shared
|
||||
path: /shared
|
||||
commands:
|
||||
- cp /shared/vctp-linux-amd64 ./build/vctp-linux-amd64
|
||||
#- find .
|
||||
- nfpm package --config vctp.yml --packager rpm --target ./build/
|
||||
- ls -lah ./build/
|
||||
|
||||
- name: dell-sftp-deploy
|
||||
image: hypervtechnics/drone-sftp
|
||||
@@ -76,6 +91,7 @@ steps:
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
- pkg.tools
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
234
README.md
234
README.md
@@ -1,110 +1,14 @@
|
||||
# Go + HTMX Template
|
||||
# Initial setup
|
||||
|
||||
This is built from the template https://github.com/Piszmog/go-htmx-template that comes with everything you need to build a Web Application using Go (templ) and HTMX.
|
||||
|
||||
The template comes with a basic structure of using a SQL DB (`sqlc`), E2E testing (playwright), and styling (tailwindcss).
|
||||
|
||||
## Getting Started
|
||||
|
||||
Clone https://github.com/Piszmog/go-htmx-template
|
||||
|
||||
Once cloned, run the `update_module.sh` script to change the module to your module name.
|
||||
## Pre-requisite tools
|
||||
|
||||
```shell
|
||||
./update_module my-new-module
|
||||
go install github.com/a-h/templ/cmd/templ@latest
|
||||
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
```
|
||||
|
||||
## Technologies
|
||||
|
||||
A few different technologies are configured to help getting off the ground easier.
|
||||
|
||||
- [sqlc](https://sqlc.dev/) for database layer
|
||||
- Stubbed to use SQLite
|
||||
- This can be easily swapped with [sqlx](https://jmoiron.github.io/sqlx/)
|
||||
- The script `upgrade_sqlc.sh` is available to upgrade GitHub Workflow files to latest sqlc version
|
||||
- [Tailwind CSS](https://tailwindcss.com/) for styling
|
||||
- Output is generated with the [CLI](https://tailwindcss.com/docs/installation)
|
||||
- [templ](https://templ.guide/) for creating HTML
|
||||
- The script `upgrade_templ.sh` is available to make upgrading easier
|
||||
- [HTMX](https://htmx.org/) for HTML interaction
|
||||
- The script `upgrade_htmx.sh` is available to make upgrading easier
|
||||
- [goose](https://github.com/pressly/goose) for DB migrations
|
||||
|
||||
TODO: investigate https://github.com/DATA-DOG/go-sqlmock for testing
|
||||
|
||||
Technologies we're no longer using:
|
||||
- [golang migrate](https://github.com/golang-migrate/migrate) for DB migrations
|
||||
- [playwright-go](https://github.com/playwright-community/playwright-go) for E2E testing.
|
||||
|
||||
Everything else uses the standard library.
|
||||
|
||||
## Structure
|
||||
(Now out of date)
|
||||
|
||||
```text
|
||||
.
|
||||
├── Makefile
|
||||
├── components
|
||||
│ ├── core
|
||||
│ │ └── html.templ
|
||||
│ └── home
|
||||
│ └── home.templ
|
||||
├── db
|
||||
│ ├── db.go
|
||||
│ ├── local.go
|
||||
│ ├── migrations
|
||||
│ │ ├── 20240407203525_init.down.sql
|
||||
│ │ └── 20240407203525_init.up.sql
|
||||
│ └── queries
|
||||
│ └── query.sql
|
||||
├── db.sqlite3
|
||||
├── dist
|
||||
│ ├── assets
|
||||
│ │ └── js
|
||||
│ │ └── htmx@1.9.10.min.js
|
||||
│ └── dist.go
|
||||
├── e2e
|
||||
│ ├── e2e_test.go
|
||||
│ ├── home_test.go
|
||||
│ └── testdata
|
||||
│ └── seed.sql
|
||||
├── go.mod
|
||||
├── go.sum
|
||||
├── log
|
||||
│ └── log.go
|
||||
├── main.go
|
||||
├── server
|
||||
│ ├── handler
|
||||
│ │ ├── handler.go
|
||||
│ │ └── home.go
|
||||
│ ├── middleware
|
||||
│ │ ├── cache.go
|
||||
│ │ ├── logging.go
|
||||
│ │ └── middleware.go
|
||||
│ ├── router
|
||||
│ │ └── router.go
|
||||
│ └── server.go
|
||||
├── sqlc.yml
|
||||
├── styles
|
||||
│ └── input.css
|
||||
├── tailwind.config.js
|
||||
└── version
|
||||
└── version.go
|
||||
```
|
||||
|
||||
### Components
|
||||
|
||||
This is where `templ` files live. Anything you want to render to the user goes here. Note, all
|
||||
`*.go` files will be ignored by `git` (configured in `.gitignore`).
|
||||
|
||||
### DB
|
||||
|
||||
This is the directory that `sqlc` generates to. Update `queries.sql` to build
|
||||
your database operations. The schema for `sqlc` lives in `db/schema.sql`.
|
||||
|
||||
Once `queries.sql` is updated, run `make generate-sql` to update the generated models
|
||||
|
||||
#### DB Migrations
|
||||
## Database
|
||||
This project now uses [goose](https://github.com/pressly/goose) for DB migrations.
|
||||
|
||||
Install via `brew install goose` on a mac, or install via golang with command `go install github.com/pressly/goose/v3/cmd/goose@latest`
|
||||
@@ -114,6 +18,16 @@ Create a new up/down migration file with this command
|
||||
goose -dir db/migrations sqlite3 ./db.sqlite3 create init sql
|
||||
```
|
||||
|
||||
```shell
|
||||
sqlc generate
|
||||
```
|
||||
|
||||
## HTML templates
|
||||
Run `templ generate -path ./components` to generate code based on template files
|
||||
|
||||
## Documentation
|
||||
Run `swag init --exclude "pkg.mod,pkg.build,pkg.tools" -o server/router/docs`
|
||||
|
||||
#### Database Configuration
|
||||
By default the app uses SQLite and creates/opens `db.sqlite3`. You can opt into PostgreSQL
|
||||
by setting environment variables:
|
||||
@@ -137,118 +51,4 @@ PostgreSQL migrations live in `db/migrations_postgres`, while SQLite migrations
|
||||
Hourly and daily snapshot table retention can be configured with environment variables:
|
||||
|
||||
- `HOURLY_SNAPSHOT_MAX_AGE_DAYS` (default: 60)
|
||||
- `DAILY_SNAPSHOT_MAX_AGE_MONTHS` (default: 12)
|
||||
|
||||
### Dist
|
||||
|
||||
This is where your assets live. Any Javascript, images, or styling needs to go in the
|
||||
`dist/assets` directory. The directory will be embedded into the application.
|
||||
|
||||
Note, the `dist/assets/css` will be ignored by `git` (configured in `.gitignore`) since the
|
||||
files that are written to this directory are done by the Tailwind CSS CLI. Custom styles should
|
||||
go in the `styles/input.css` file.
|
||||
|
||||
### E2E
|
||||
|
||||
To test the UI, the `e2e` directory contains the Go tests for performing End to end testing. To
|
||||
run the tests, run the command
|
||||
|
||||
```shell
|
||||
go test -v ./... -tags=e2e
|
||||
```
|
||||
|
||||
The end to end tests, will start up the app, on a random port, seeding the database using the
|
||||
`seed.sql` file. Once the tests are complete, the app will be stopped.
|
||||
|
||||
The E2E tests use Playwright (Go) for better integration into the Go tooling.
|
||||
|
||||
### Log
|
||||
|
||||
This contains helper function to create a `slog.Logger`. Log level and output type can be set
|
||||
with then environment variables `LOG_LEVEL` and `LOG_OUTPUT`. The logger will write to
|
||||
`stdout`.
|
||||
|
||||
### Server
|
||||
|
||||
This contains everything related to the HTTP server. It comes with a graceful shutdown handler
|
||||
that handles `SIGINT`.
|
||||
|
||||
#### Router
|
||||
|
||||
This package sets up the routing for the application, such as the `/assets/` path and `/` path.
|
||||
It uses the standard libraries mux for routing. You can easily swap out for other HTTP
|
||||
routers such as [gorilla/mux](https://github.com/gorilla/mux).
|
||||
|
||||
#### Middleware
|
||||
|
||||
This package contains any middleware to configured with routes.
|
||||
|
||||
#### Handler
|
||||
|
||||
This package contains the handler to handle the actual routes.
|
||||
|
||||
#### Styles
|
||||
|
||||
This contains the `input.css` that the Tailwind CSS CLI uses to generate your output CSS.
|
||||
Update `input.css` with any custom CSS you need and it will be included in the output CSS.
|
||||
|
||||
#### Version
|
||||
|
||||
This package allows you to set a version at build time. If not set, the version defaults to
|
||||
`dev`. To set the version run the following command,
|
||||
|
||||
```shell
|
||||
go build -o ./app -ldflags="-X version.Value=1.0.0"
|
||||
```
|
||||
|
||||
See the `Makefile` for building the application.
|
||||
|
||||
## Run
|
||||
|
||||
There are a couple builtin ways to run the application - using `air` or the `Makefile` helper
|
||||
commands.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Install [templ](https://templ.guide/quick-start/installation) - `go install github.com/a-h/templ/cmd/templ@latest`
|
||||
- Install [sqlc](https://docs.sqlc.dev/en/stable/overview/install.html)
|
||||
- Install [tailwindcss CLI](https://tailwindcss.com/docs/installation)
|
||||
|
||||
#### tailwindcss
|
||||
```shell
|
||||
# Example for macOS arm64
|
||||
curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-macos-arm64
|
||||
chmod +x tailwindcss-macos-arm64
|
||||
sudo mv tailwindcss-macos-arm64 /usr/local/bin/tailwindcss
|
||||
```
|
||||
|
||||
### Makefile
|
||||
|
||||
You can also run with the provided `Makefile`. There are commands to generate `templ` files and
|
||||
tailwind output css.
|
||||
|
||||
```shell
|
||||
# Generate and watch templ
|
||||
make generate-templ-watch
|
||||
|
||||
# Genrate and watch tailwindcss
|
||||
make generate-tailwind-watch
|
||||
|
||||
# Run application
|
||||
make run
|
||||
```
|
||||
|
||||
## Github Workflow
|
||||
|
||||
The repository comes with two Github workflows as well. One called `ci.yml` that lints and
|
||||
tests your code. The other called `release.yml` that creates a tag, GitHub Release, and
|
||||
attaches the Linux binary to the Release.
|
||||
|
||||
Note, the version of `github.com/a-h/templ/cmd/templ` matches the version in `go.mod`. If these
|
||||
do not match, the build will fail. When upgrading your `templ` version, make sure to update
|
||||
`ci.yml` and `release.yml`.
|
||||
|
||||
### GoReleaser
|
||||
|
||||
If you need to compile for more than Linux, see [GoReleaser](https://goreleaser.com/) for a
|
||||
better release process.
|
||||
- `DAILY_SNAPSHOT_MAX_AGE_MONTHS` (default: 12)
|
||||
@@ -10,5 +10,78 @@ templ Header() {
|
||||
<title>vCTP API</title>
|
||||
<script src="/assets/js/htmx@v2.0.2.min.js"></script>
|
||||
<link href={ "/assets/css/output@" + version.Value + ".css" } rel="stylesheet"/>
|
||||
<style>
|
||||
:root {
|
||||
--web2-blue: #3b82f6;
|
||||
--web2-cyan: #22d3ee;
|
||||
--web2-slate: #0f172a;
|
||||
--web2-card: #ffffff;
|
||||
--web2-shadow: 0 20px 40px rgba(15, 23, 42, 0.15);
|
||||
--web2-soft-shadow: 0 8px 20px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
body {
|
||||
font-family: "Trebuchet MS", "Lucida Grande", "Verdana", sans-serif;
|
||||
color: var(--web2-slate);
|
||||
}
|
||||
.web2-bg {
|
||||
background: radial-gradient(circle at top left, #e0f2fe 0%, #f8fafc 45%, #e2e8f0 100%);
|
||||
}
|
||||
.web2-shell {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 1.5rem 4rem;
|
||||
}
|
||||
.web2-header {
|
||||
background: linear-gradient(135deg, #0ea5e9 0%, #6366f1 100%);
|
||||
color: #fff;
|
||||
border-radius: 22px;
|
||||
box-shadow: var(--web2-shadow);
|
||||
padding: 1.5rem 2rem;
|
||||
}
|
||||
.web2-card {
|
||||
background: var(--web2-card);
|
||||
border-radius: 18px;
|
||||
box-shadow: var(--web2-soft-shadow);
|
||||
padding: 1.5rem 1.75rem;
|
||||
}
|
||||
.web2-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.35);
|
||||
padding: 0.35rem 0.8rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.85rem;
|
||||
letter-spacing: 0.02em;
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
.web2-link {
|
||||
color: var(--web2-blue);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
.web2-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.web2-button {
|
||||
background: linear-gradient(180deg, #60a5fa 0%, #2563eb 100%);
|
||||
color: #fff;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 6px 16px rgba(37, 99, 235, 0.35);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
.web2-button:hover {
|
||||
filter: brightness(1.05);
|
||||
}
|
||||
.web2-list li {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 14px;
|
||||
padding: 0.85rem 1.1rem;
|
||||
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,13 +38,13 @@ func Header() templ.Component {
|
||||
var templ_7745c5c3_Var2 templ.SafeURL
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinURLErrs("/assets/css/output@" + version.Value + ".css")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/core/header.templ`, Line: 12, Col: 61}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `core/header.templ`, Line: 12, Col: 61}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" rel=\"stylesheet\"></head>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" rel=\"stylesheet\"><style>\n\t\t\t:root {\n\t\t\t\t--web2-blue: #3b82f6;\n\t\t\t\t--web2-cyan: #22d3ee;\n\t\t\t\t--web2-slate: #0f172a;\n\t\t\t\t--web2-card: #ffffff;\n\t\t\t\t--web2-shadow: 0 20px 40px rgba(15, 23, 42, 0.15);\n\t\t\t\t--web2-soft-shadow: 0 8px 20px rgba(15, 23, 42, 0.12);\n\t\t\t}\n\t\t\tbody {\n\t\t\t\tfont-family: \"Trebuchet MS\", \"Lucida Grande\", \"Verdana\", sans-serif;\n\t\t\t\tcolor: var(--web2-slate);\n\t\t\t}\n\t\t\t.web2-bg {\n\t\t\t\tbackground: radial-gradient(circle at top left, #e0f2fe 0%, #f8fafc 45%, #e2e8f0 100%);\n\t\t\t}\n\t\t\t.web2-shell {\n\t\t\t\tmax-width: 1100px;\n\t\t\t\tmargin: 0 auto;\n\t\t\t\tpadding: 2rem 1.5rem 4rem;\n\t\t\t}\n\t\t\t.web2-header {\n\t\t\t\tbackground: linear-gradient(135deg, #0ea5e9 0%, #6366f1 100%);\n\t\t\t\tcolor: #fff;\n\t\t\t\tborder-radius: 22px;\n\t\t\t\tbox-shadow: var(--web2-shadow);\n\t\t\t\tpadding: 1.5rem 2rem;\n\t\t\t}\n\t\t\t.web2-card {\n\t\t\t\tbackground: var(--web2-card);\n\t\t\t\tborder-radius: 18px;\n\t\t\t\tbox-shadow: var(--web2-soft-shadow);\n\t\t\t\tpadding: 1.5rem 1.75rem;\n\t\t\t}\n\t\t\t.web2-pill {\n\t\t\t\tdisplay: inline-flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: 0.4rem;\n\t\t\t\tbackground: rgba(255, 255, 255, 0.2);\n\t\t\t\tborder: 1px solid rgba(255, 255, 255, 0.35);\n\t\t\t\tpadding: 0.35rem 0.8rem;\n\t\t\t\tborder-radius: 999px;\n\t\t\t\tfont-size: 0.85rem;\n\t\t\t\tletter-spacing: 0.02em;\n\t\t\t\tbackdrop-filter: blur(6px);\n\t\t\t}\n\t\t\t.web2-link {\n\t\t\t\tcolor: var(--web2-blue);\n\t\t\t\ttext-decoration: none;\n\t\t\t\tfont-weight: 600;\n\t\t\t}\n\t\t\t.web2-link:hover {\n\t\t\t\ttext-decoration: underline;\n\t\t\t}\n\t\t\t.web2-button {\n\t\t\t\tbackground: linear-gradient(180deg, #60a5fa 0%, #2563eb 100%);\n\t\t\t\tcolor: #fff;\n\t\t\t\tpadding: 0.5rem 1rem;\n\t\t\t\tborder-radius: 999px;\n\t\t\t\tbox-shadow: 0 6px 16px rgba(37, 99, 235, 0.35);\n\t\t\t\tfont-weight: 600;\n\t\t\t\ttext-decoration: none;\n\t\t\t}\n\t\t\t.web2-button:hover {\n\t\t\t\tfilter: brightness(1.05);\n\t\t\t}\n\t\t\t.web2-list li {\n\t\t\t\tbackground: rgba(255, 255, 255, 0.9);\n\t\t\t\tborder-radius: 14px;\n\t\t\t\tpadding: 0.85rem 1.1rem;\n\t\t\t\tbox-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);\n\t\t\t}\n\t\t</style></head>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
@@ -14,16 +14,39 @@ templ Index(info BuildInfo) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@core.Header()
|
||||
<body class="flex flex-col min-h-screen">
|
||||
<main class="flex-grow">
|
||||
<div>
|
||||
<h1 class="text-5xl font-bold">Build Information</h1>
|
||||
<p class="mt-4"><strong>Build Time:</strong> {info.BuildTime}</p>
|
||||
<p class="mt-4"><strong>SHA1 Version:</strong> {info.SHA1Ver}</p>
|
||||
<p class="mt-4"><strong>Go Runtime Version:</strong> {info.GoVersion}</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
@core.Footer()
|
||||
<body class="flex flex-col min-h-screen web2-bg">
|
||||
<main class="flex-grow web2-shell space-y-8">
|
||||
<section class="web2-header">
|
||||
<div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<div class="web2-pill">vCTP Console</div>
|
||||
<h1 class="mt-3 text-4xl font-bold">Build Intelligence Dashboard</h1>
|
||||
<p class="mt-2 text-sm opacity-90">A glossy, snapshot-ready view of what is running.</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<a class="web2-button" href="/snapshots/hourly">Hourly Snapshots</a>
|
||||
<a class="web2-button" href="/snapshots/daily">Daily Snapshots</a>
|
||||
<a class="web2-button" href="/snapshots/monthly">Monthly Snapshots</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid gap-6 md:grid-cols-3">
|
||||
<div class="web2-card">
|
||||
<p class="text-xs uppercase tracking-[0.2em] text-slate-400">Build Time</p>
|
||||
<p class="mt-3 text-xl font-semibold">{info.BuildTime}</p>
|
||||
</div>
|
||||
<div class="web2-card">
|
||||
<p class="text-xs uppercase tracking-[0.2em] text-slate-400">SHA1 Version</p>
|
||||
<p class="mt-3 text-xl font-semibold">{info.SHA1Ver}</p>
|
||||
</div>
|
||||
<div class="web2-card">
|
||||
<p class="text-xs uppercase tracking-[0.2em] text-slate-400">Go Runtime</p>
|
||||
<p class="mt-3 text-xl font-semibold">{info.GoVersion}</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
@core.Footer()
|
||||
</html>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,46 +47,46 @@ func Index(info BuildInfo) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<body class=\"flex flex-col min-h-screen\"><main class=\"flex-grow\"><div><h1 class=\"text-5xl font-bold\">Build Information</h1><p class=\"mt-4\"><strong>Build Time:</strong> ")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<body class=\"flex flex-col min-h-screen web2-bg\"><main class=\"flex-grow web2-shell space-y-8\"><section class=\"web2-header\"><div class=\"flex flex-col gap-4 md:flex-row md:items-center md:justify-between\"><div><div class=\"web2-pill\">vCTP Console</div><h1 class=\"mt-3 text-4xl font-bold\">Build Intelligence Dashboard</h1><p class=\"mt-2 text-sm opacity-90\">A glossy, snapshot-ready view of what is running.</p></div><div class=\"flex flex-wrap gap-3\"><a class=\"web2-button\" href=\"/snapshots/hourly\">Hourly Snapshots</a> <a class=\"web2-button\" href=\"/snapshots/daily\">Daily Snapshots</a> <a class=\"web2-button\" href=\"/snapshots/monthly\">Monthly Snapshots</a></div></div></section><section class=\"grid gap-6 md:grid-cols-3\"><div class=\"web2-card\"><p class=\"text-xs uppercase tracking-[0.2em] text-slate-400\">Build Time</p><p class=\"mt-3 text-xl font-semibold\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(info.BuildTime)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/index.templ`, Line: 21, Col: 80}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/index.templ`, Line: 37, Col: 59}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</p><p class=\"mt-4\"><strong>SHA1 Version:</strong> ")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</p></div><div class=\"web2-card\"><p class=\"text-xs uppercase tracking-[0.2em] text-slate-400\">SHA1 Version</p><p class=\"mt-3 text-xl font-semibold\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(info.SHA1Ver)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/index.templ`, Line: 22, Col: 80}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/index.templ`, Line: 41, Col: 57}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</p><p class=\"mt-4\"><strong>Go Runtime Version:</strong> ")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</p></div><div class=\"web2-card\"><p class=\"text-xs uppercase tracking-[0.2em] text-slate-400\">Go Runtime</p><p class=\"mt-3 text-xl font-semibold\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(info.GoVersion)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/index.templ`, Line: 23, Col: 88}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/index.templ`, Line: 45, Col: 59}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</p></div></main></body>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</p></div></section></main></body>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
@@ -25,21 +25,33 @@ templ SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@core.Header()
|
||||
<body class="flex flex-col min-h-screen">
|
||||
<main class="flex-grow">
|
||||
<div>
|
||||
<h1 class="text-4xl font-bold">{title}</h1>
|
||||
<p class="mt-2 text-gray-600">{subtitle}</p>
|
||||
<ul class="mt-6 space-y-2">
|
||||
<body class="flex flex-col min-h-screen web2-bg">
|
||||
<main class="flex-grow web2-shell space-y-8">
|
||||
<section class="web2-header">
|
||||
<div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<div class="web2-pill">Snapshot Library</div>
|
||||
<h1 class="mt-3 text-4xl font-bold">{title}</h1>
|
||||
<p class="mt-2 text-sm opacity-90">{subtitle}</p>
|
||||
</div>
|
||||
<a class="web2-button" href="/">Back to Dashboard</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="web2-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-lg font-semibold">Available Exports</h2>
|
||||
<span class="text-xs uppercase tracking-[0.2em] text-slate-400">{len(entries)} files</span>
|
||||
</div>
|
||||
<ul class="mt-6 space-y-3 web2-list">
|
||||
for _, entry := range entries {
|
||||
<li>
|
||||
<a class="text-blue-600 hover:underline" href={entry.Link}>
|
||||
{entry.Label}
|
||||
</a>
|
||||
<li class="flex items-center justify-between gap-4">
|
||||
<span class="text-sm font-semibold text-slate-700">{entry.Label}</span>
|
||||
<a class="web2-link" href={entry.Link}>Download XLSX</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
@core.Footer()
|
||||
|
||||
@@ -133,69 +133,82 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<body class=\"flex flex-col min-h-screen\"><main class=\"flex-grow\"><div><h1 class=\"text-4xl font-bold\">")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<body class=\"flex flex-col min-h-screen web2-bg\"><main class=\"flex-grow web2-shell space-y-8\"><section class=\"web2-header\"><div class=\"flex flex-col gap-4 md:flex-row md:items-center md:justify-between\"><div><div class=\"web2-pill\">Snapshot Library</div><h1 class=\"mt-3 text-4xl font-bold\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 31, Col: 42}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 34, Col: 49}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h1><p class=\"mt-2 text-gray-600\">")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h1><p class=\"mt-2 text-sm opacity-90\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(subtitle)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 32, Col: 44}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 35, Col: 51}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</p><ul class=\"mt-6 space-y-2\">")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</p></div><a class=\"web2-button\" href=\"/\">Back to Dashboard</a></div></section><section class=\"web2-card\"><div class=\"flex items-center justify-between\"><h2 class=\"text-lg font-semibold\">Available Exports</h2><span class=\"text-xs uppercase tracking-[0.2em] text-slate-400\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(len(entries))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 44, Col: 83}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, " files</span></div><ul class=\"mt-6 space-y-3 web2-list\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<li><a class=\"text-blue-600 hover:underline\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 templ.SafeURL
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(entry.Link)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 36, Col: 65}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<li class=\"flex items-center justify-between gap-4\"><span class=\"text-sm font-semibold text-slate-700\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Label)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 37, Col: 21}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 49, Col: 71}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</a></li>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</span> <a class=\"web2-link\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 templ.SafeURL
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinURLErrs(entry.Link)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 50, Col: 45}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">Download XLSX</a></li>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</ul></div></main></body>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</ul></section></main></body>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@@ -203,7 +216,7 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</html>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
type Querier interface {
|
||||
CleanupUpdates(ctx context.Context, arg queries.CleanupUpdatesParams) error
|
||||
CleanupUpdatesNullVm(ctx context.Context) error
|
||||
CreateEvent(ctx context.Context, arg queries.CreateEventParams) (queries.Events, error)
|
||||
CreateEvent(ctx context.Context, arg queries.CreateEventParams) (queries.Event, error)
|
||||
CreateInventory(ctx context.Context, arg queries.CreateInventoryParams) (queries.Inventory, error)
|
||||
CreateInventoryHistory(ctx context.Context, arg queries.CreateInventoryHistoryParams) (queries.InventoryHistory, error)
|
||||
CreateUpdate(ctx context.Context, arg queries.CreateUpdateParams) (queries.Updates, error)
|
||||
CreateUpdate(ctx context.Context, arg queries.CreateUpdateParams) (queries.Update, error)
|
||||
GetInventoryByName(ctx context.Context, name string) ([]queries.Inventory, error)
|
||||
GetInventoryByVcenter(ctx context.Context, vcenter string) ([]queries.Inventory, error)
|
||||
GetInventoryEventId(ctx context.Context, cloudid sql.NullString) (queries.Inventory, error)
|
||||
@@ -21,15 +21,15 @@ type Querier interface {
|
||||
GetInventoryVmId(ctx context.Context, arg queries.GetInventoryVmIdParams) (queries.Inventory, error)
|
||||
GetInventoryVmUuid(ctx context.Context, arg queries.GetInventoryVmUuidParams) (queries.Inventory, error)
|
||||
GetReportInventory(ctx context.Context) ([]queries.Inventory, error)
|
||||
GetReportUpdates(ctx context.Context) ([]queries.Updates, error)
|
||||
GetVmUpdates(ctx context.Context, arg queries.GetVmUpdatesParams) ([]queries.Updates, error)
|
||||
GetReportUpdates(ctx context.Context) ([]queries.Update, error)
|
||||
GetVmUpdates(ctx context.Context, arg queries.GetVmUpdatesParams) ([]queries.Update, error)
|
||||
InventoryCleanup(ctx context.Context, arg queries.InventoryCleanupParams) error
|
||||
InventoryCleanupTemplates(ctx context.Context) error
|
||||
InventoryCleanupVcenter(ctx context.Context, vc string) error
|
||||
InventoryMarkDeleted(ctx context.Context, arg queries.InventoryMarkDeletedParams) error
|
||||
InventoryUpdate(ctx context.Context, arg queries.InventoryUpdateParams) error
|
||||
ListEvents(ctx context.Context) ([]queries.Events, error)
|
||||
ListEvents(ctx context.Context) ([]queries.Event, error)
|
||||
ListInventory(ctx context.Context) ([]queries.Inventory, error)
|
||||
ListUnprocessedEvents(ctx context.Context, eventtime sql.NullInt64) ([]queries.Events, error)
|
||||
ListUnprocessedEvents(ctx context.Context, eventtime sql.NullInt64) ([]queries.Event, error)
|
||||
UpdateEventsProcessed(ctx context.Context, eid int64) error
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
export CGO_ENABLED=0
|
||||
|
||||
package_name=vctp
|
||||
package=./
|
||||
commit=$(git rev-parse HEAD)
|
||||
buildtime=$(date +%Y-%m-%dT%T%z)
|
||||
#Extract the version from yml
|
||||
@@ -16,6 +17,7 @@ echo Building::
|
||||
echo - Version $package_version
|
||||
echo - Commit $commit
|
||||
echo - Build Time $buildtime
|
||||
mkdir -p build
|
||||
for platform in "${platforms[@]}"
|
||||
do
|
||||
platform_split=(${platform//\// })
|
||||
@@ -38,6 +40,6 @@ do
|
||||
#sha256sum build/${output_name}.gz > build/${output_name}_checksum.txt
|
||||
done
|
||||
|
||||
#nfpm package --config $package_name.yml --packager rpm --target build/
|
||||
nfpm package --config $package_name.yml --packager rpm --target build/
|
||||
|
||||
ls -lah build
|
||||
|
||||
@@ -97,5 +97,4 @@ func (h *Handler) VmImport(w http.ResponseWriter, r *http.Request) {
|
||||
"status": "OK",
|
||||
"message": fmt.Sprintf("Successfully processed import request for VM '%s'", inData.Name),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "OK",
|
||||
"message": fmt.Sprintf("Received update event successfully but no config changes were found"),
|
||||
"message": "Received update event successfully but no config changes were found",
|
||||
})
|
||||
return
|
||||
} else {
|
||||
@@ -178,7 +178,7 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
|
||||
} else {
|
||||
h.Logger.Debug("Matched regex", "disk_owner", matches[1])
|
||||
|
||||
if strings.ToLower(matches[1]) == strings.ToLower(event.CloudEvent.Data.VM.Name) {
|
||||
if strings.EqualFold(matches[1], event.CloudEvent.Data.VM.Name) {
|
||||
h.Logger.Debug("This disk belongs to this VM")
|
||||
changeFound = true
|
||||
diskChangeFound = true
|
||||
@@ -278,7 +278,7 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "OK",
|
||||
"message": fmt.Sprintf("Successfully processed vm modify event"),
|
||||
"message": "Successfully processed vm modify event",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -304,7 +304,7 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "OK",
|
||||
"message": fmt.Sprintf("Successfully processed vm modify event"),
|
||||
"message": "Successfully processed vm modify event",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "ERROR",
|
||||
"message": fmt.Sprintf("CloudEvent missing resource pool data"),
|
||||
"message": "CloudEvent missing resource pool data",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -151,7 +151,7 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
|
||||
//fmt.Fprintf(w, "Processed update event: %v\n", result)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "OK",
|
||||
"message": fmt.Sprintf("Successfully processed move event"),
|
||||
"message": "Successfully processed move event",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
6
sqlc.yml
6
sqlc.yml
@@ -1,11 +1,13 @@
|
||||
version: 2
|
||||
sql:
|
||||
- engine: sqlite
|
||||
queries:
|
||||
- db/queries/query.sql
|
||||
schema:
|
||||
- db/schema.sql
|
||||
queries:
|
||||
- db/queries/query.sql
|
||||
gen:
|
||||
go:
|
||||
package: queries
|
||||
out: db/queries
|
||||
emit_json_tags: true
|
||||
emit_db_tags: true
|
||||
|
||||
10
src/postinstall.sh
Normal file
10
src/postinstall.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl daemon-reload || :
|
||||
if [ "$1" -eq 1 ]; then
|
||||
systemctl enable --now vctp.service || :
|
||||
else
|
||||
systemctl try-restart vctp.service || :
|
||||
fi
|
||||
fi
|
||||
8
src/postremove.sh
Normal file
8
src/postremove.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl daemon-reload || :
|
||||
if [ "$1" -ge 1 ]; then
|
||||
systemctl try-restart vctp.service || :
|
||||
fi
|
||||
fi
|
||||
45
src/preinstall.sh
Normal file
45
src/preinstall.sh
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
USER="vctp"
|
||||
GROUP="dtms"
|
||||
|
||||
# Path to the custom sudoers file
|
||||
SUDOERS_FILE="/etc/sudoers.d/${USER}"
|
||||
|
||||
# create a group & user if not exists
|
||||
getent group "$GROUP" >/dev/null || groupadd -r "$GROUP"; /bin/true
|
||||
getent passwd "$USER" >/dev/null || useradd -r -g "$GROUP" -m -s /bin/bash -c "vctp service" "$USER"
|
||||
getent passwd tftp >/dev/null || useradd -r -g tftp -s /sbin/nologin tftp
|
||||
|
||||
# create vctp config directory if it doesn't exist
|
||||
[ -d /etc/dtms ] || mkdir -p /etc/dtms
|
||||
|
||||
# set group ownership on vctp config directory if not already done
|
||||
[ "$(stat -c "%G" /etc/dtms)" = "$GROUP" ] || chgrp -R "$GROUP" /etc/dtms
|
||||
|
||||
# set permissions on vctp config directory if not already done
|
||||
[ "$(stat -c "%a" /etc/dtms)" = "774" ] || chmod -R 774 /etc/dtms
|
||||
|
||||
# create vctp data directory if it doesn't exist
|
||||
[ -d /var/lib/vctp ] || mkdir -p /var/lib/vctp
|
||||
|
||||
# set user ownership on vctp data directory if not already done
|
||||
[ "$(stat -c "%U" /var/lib/vctp)" = "$USER" ] || chown -R "$USER" /var/lib/vctp
|
||||
|
||||
# set group ownership on vctp data directory if not already done
|
||||
[ "$(stat -c "%G" /var/lib/vctp)" = "$GROUP" ] || chgrp -R "$GROUP" /var/lib/vctp
|
||||
|
||||
# Check if firewalld is installed and active
|
||||
if command -v systemctl >/dev/null 2>&1 && systemctl is-enabled firewalld >/dev/null 2>&1 && systemctl is-active firewalld >/dev/null 2>&1; then
|
||||
echo "Firewalld is enabled and running. Adding necessary ports..."
|
||||
|
||||
# Open HTTPS port (443/tcp)
|
||||
firewall-cmd --permanent --add-service=https >/dev/null 2>&1
|
||||
|
||||
# Open custom application port (9443/tcp)
|
||||
firewall-cmd --permanent --add-port=9443/tcp >/dev/null 2>&1
|
||||
|
||||
# Reload firewalld to apply changes
|
||||
firewall-cmd --reload >/dev/null 2>&1
|
||||
else
|
||||
echo "Firewalld is not running or not enabled. Skipping firewall configuration."
|
||||
fi
|
||||
8
src/preremove.sh
Normal file
8
src/preremove.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
if [ "$1" -eq 0 ]; then
|
||||
systemctl stop vctp.service || :
|
||||
systemctl disable vctp.service || :
|
||||
fi
|
||||
fi
|
||||
1
src/vctp.default
Normal file
1
src/vctp.default
Normal file
@@ -0,0 +1 @@
|
||||
CPE_OPTS='-config /etc/dtms/vctp.yml -log-level info -log-output text'
|
||||
21
src/vctp.service
Normal file
21
src/vctp.service
Normal file
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=vCTP monitors VMware VM inventory and event data to build chargeback reports
|
||||
Documentation=https://gitlab.dell.com/
|
||||
ConditionPathExists=/usr/bin/vctp-linux-amd64
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/default/vctp
|
||||
User=vctp
|
||||
ExecStart=/usr/bin/vctp-linux-amd64 $CPE_OPTS
|
||||
ExecStartPost=/usr/bin/sleep 3
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
#LimitNOFILE=65536
|
||||
SyslogIdentifier=vctp
|
||||
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_FOWNER CAP_DAC_OVERRIDE CAP_SETUID CAP_SETGID CAP_SYS_RESOURCE CAP_AUDIT_WRITE
|
||||
#AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
25
src/vctp.yml
Normal file
25
src/vctp.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
settings:
|
||||
data_location: "/var/lib/cbs"
|
||||
kickstart_location: "/var/lib/cbs/ks"
|
||||
database_filename: "/var/lib/cbs/cbs.db"
|
||||
bind_ip:
|
||||
bind_port: 443
|
||||
bind_disable_tls: false
|
||||
tls_cert_filename: "/etc/dtms/cbs.crt"
|
||||
tls_key_filename: "/etc/dtms/cbs.key"
|
||||
tftp_root_directory: "/var/lib/tftpboot"
|
||||
tftp_images_subdirectory: "images"
|
||||
replacements:
|
||||
omapi:
|
||||
key_name: "OMAPI"
|
||||
key_secret:
|
||||
special_files:
|
||||
ldap_groups:
|
||||
ldap_bind_address: ""
|
||||
ldap_base_dn: ""
|
||||
ldap_trust_cert_file: ""
|
||||
ldap_disable_validation: false
|
||||
ldap_insecure: false
|
||||
auth_token_lifespan_hours: 2
|
||||
auth_api_key: ""
|
||||
|
||||
40
vctp.yml
Normal file
40
vctp.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
name: "vctp"
|
||||
arch: "amd64"
|
||||
platform: "linux"
|
||||
version: "v26.1.1"
|
||||
version_schema: semver
|
||||
description: vCTP monitors VMware VM inventory and event data to build chargeback reports
|
||||
maintainer: "@coadn"
|
||||
vendor: "Dell Technologies Managed Services"
|
||||
homepage: "https://gitlab.dell.com/"
|
||||
license: "Apache-2.0"
|
||||
|
||||
contents:
|
||||
- src: build/vctp-linux-amd64
|
||||
dst: /usr/bin/vctp-linux-amd64
|
||||
|
||||
- src: src/vctp.yml
|
||||
dst: /etc/dtms/vctp.yml
|
||||
type: config|noreplace
|
||||
file_info:
|
||||
mode: 0644
|
||||
owner: vctp
|
||||
group: dtms
|
||||
|
||||
- src: src/vctp.service
|
||||
dst: /usr/lib/systemd/system/vctp.service
|
||||
|
||||
- src: src/vctp.default
|
||||
dst: /etc/default/vctp
|
||||
type: config|noreplace
|
||||
|
||||
scripts:
|
||||
preinstall: src/preinstall.sh
|
||||
postinstall: src/postinstall.sh
|
||||
preremove: src/preremove.sh
|
||||
postremove: src/postremove.sh
|
||||
|
||||
depends:
|
||||
- systemd
|
||||
- tftp-server
|
||||
- dhcp-server
|
||||
Reference in New Issue
Block a user