chore: add k8s and docker as service to agent and update logic for ansible deploy
ci-agent / build (push) Failing after 2m35s

This commit is contained in:
d3m0k1d
2026-04-05 01:43:38 +03:00
parent 428140ff15
commit 3e5e4815d9
9 changed files with 385 additions and 48 deletions
+53 -12
View File
@@ -7,32 +7,39 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
)
// ErrUnknownDeployType is returned when an unsupported deployment type is specified
var ErrUnknownDeployType = fmt.Errorf("unknown deploy type, expected 'docker' or 'binary'")
// Executor handles running Ansible playbooks
type Executor struct {
workDir string
grpcServerHost string
grpcServerPort string
backendURL string
workDir string
grpcServerHost string
grpcServerPort string
backendURL string
giteaReleasesURL string
}
// ExecutorConfig holds configuration for the Executor
type ExecutorConfig struct {
WorkDir string
GRPCServerHost string
GRPCServerPort string
BackendURL string
WorkDir string
GRPCServerHost string
GRPCServerPort string
BackendURL string
GiteaReleasesURL string
}
// NewExecutor creates a new Ansible executor
func NewExecutor(cfg ExecutorConfig) *Executor {
return &Executor{
workDir: cfg.WorkDir,
grpcServerHost: cfg.GRPCServerHost,
grpcServerPort: cfg.GRPCServerPort,
backendURL: cfg.BackendURL,
workDir: cfg.WorkDir,
grpcServerHost: cfg.GRPCServerHost,
grpcServerPort: cfg.GRPCServerPort,
backendURL: cfg.BackendURL,
giteaReleasesURL: cfg.GiteaReleasesURL,
}
}
@@ -55,12 +62,42 @@ func (e *Executor) GRPCURL() string {
return e.grpcServerHost + ":" + e.grpcServerPort
}
// CheckDockerCollection verifies that the community.docker Ansible collection is installed.
// Returns an error if the collection is not found.
func (e *Executor) CheckDockerCollection() error {
cmd := exec.Command("ansible-galaxy", "collection", "list", "community.docker")
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("community.docker collection not found: %s", stderr.String())
}
// ansible-galaxy collection list returns output like:
// # /usr/share/ansible/collections/ansible_collections
// Collection Version
// ---------------- -------
// community.docker 3.10.0
//
// If the collection is not installed, it won't appear in the output.
if !strings.Contains(stdout.String(), "community.docker") {
return fmt.Errorf("community.docker collection is not installed. Run: ansible-galaxy collection install community.docker")
}
return nil
}
// Deploy runs Ansible playbook for the given inventory
func (e *Executor) Deploy(
ctx context.Context,
inventoryPath string,
deployType string,
) ([]DeployResult, error) {
if deployType != "docker" && deployType != "binary" {
return nil, fmt.Errorf("invalid deploy type %q: %w", deployType, ErrUnknownDeployType)
}
playbookName := "binary_deploy.yml"
if deployType == "docker" {
playbookName = "docker_deploy.yml"
@@ -72,6 +109,7 @@ func (e *Executor) Deploy(
"-i", inventoryPath,
"-e", fmt.Sprintf("backend_url=%s", e.backendURL),
"-e", fmt.Sprintf("grpc_url=%s", e.grpcServerHost+":"+e.grpcServerPort),
"-e", fmt.Sprintf("gitea_releases_url=%s", e.giteaReleasesURL),
playbookPath,
)
@@ -100,6 +138,7 @@ func (e *Executor) DeployParallel(
deployType string,
) (map[string][]DeployResult, error) {
var wg sync.WaitGroup
var mu sync.Mutex
results := make(map[string][]DeployResult)
errCh := make(chan error, len(inventoryPaths))
@@ -111,7 +150,9 @@ func (e *Executor) DeployParallel(
if err != nil {
errCh <- err
}
mu.Lock()
results[p] = res
mu.Unlock()
}(path)
}
+7 -10
View File
@@ -26,16 +26,13 @@ type Inventory struct {
Hosts []InventoryHost
}
const inventoryTemplateText = `{{ range .Hosts }}
{{ .Name }} ansible_host={{ .IP }} ansible_port={{ .Port }} ansible_user={{ .User }} ansible_connection=ssh
{{ if eq .AuthMethod "key" }}ansible_ssh_private_key_file={{ .SSHKey }}{{ end }}
{{ if eq .AuthMethod "password" }}ansible_ssh_pass={{ .Password }}{{ end }}
deploy_type={{ .DeployType }}
agent_token={{ .Token }}
agent_label={{ .Name }}
grpc_url={{ .GRPCURL }}
{{ end }}`
const inventoryTemplateText = `{{- range $i, $host := .Hosts }}
{{ $host.Name }} ansible_host={{ $host.IP }} ansible_port={{ $host.Port }} ansible_user={{ $host.User }} ansible_connection=ssh{{ if eq $host.AuthMethod "key" }} ansible_ssh_private_key_file={{ $host.SSHKey }}{{ end }}{{ if eq $host.AuthMethod "password" }} ansible_ssh_pass={{ $host.Password }}{{ end }}
deploy_type={{ $host.DeployType }}
agent_token={{ $host.Token }}
agent_label={{ $host.Name }}
grpc_url={{ $host.GRPCURL }}
{{ end -}}`
// GenerateInventory generates an Ansible inventory file from the given hosts
func GenerateInventory(hosts []InventoryHost, outputPath string) error {
+55 -18
View File
@@ -1,8 +1,7 @@
package ansible
// BinaryDeployPlaybook returns the Ansible playbook for binary deployment.
// Downloads the agent binary, writes config, and starts it directly (no systemd).
// systemd unit is managed separately (e.g. via goreleaser .deb/.rpm packages).
// Downloads the agent binary, writes config, and installs a systemd unit for automatic restart.
const BinaryDeployPlaybook = `---
- name: Deploy HellreigN Agent (Binary)
hosts: all
@@ -14,6 +13,7 @@ const BinaryDeployPlaybook = `---
install_dir: /opt/hellreign
bin_name: hellreign-agent
cert_dir: "{{ install_dir }}/certs"
gitea_releases_url: "{{ gitea_releases_url | default('https://gitea.d3m0k1d.ru/d3m0k1d/HellreigN/releases/latest/download') }}"
tasks:
- name: Create installation directory
@@ -30,7 +30,7 @@ const BinaryDeployPlaybook = `---
- name: Download HellreigN Agent binary
get_url:
url: "https://gitea.d3m0k1d.ru/d3m0k1d/HellreigN/releases/latest/download/{{ bin_name }}"
url: "{{ gitea_releases_url }}/{{ bin_name }}"
dest: "{{ install_dir }}/{{ bin_name }}"
mode: '0755'
@@ -48,16 +48,43 @@ const BinaryDeployPlaybook = `---
dest: "{{ install_dir }}/config.yml"
mode: '0644'
- name: Start HellreigN Agent
shell: |
nohup {{ install_dir }}/{{ bin_name }} > /dev/null 2>&1 &
echo $!
args:
executable: /bin/bash
environment:
CONFIG_FILE: "{{ install_dir }}/config.yml"
register: agent_pid
changed_when: true
- name: Create systemd unit file
copy:
content: |
[Unit]
Description=HellreigN Agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart={{ install_dir }}/{{ bin_name }}
Restart=always
RestartSec=5
Environment=CONFIG_FILE={{ install_dir }}/config.yml
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/hellreign-agent.service
mode: '0644'
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- name: Enable and start HellreigN Agent service
systemd:
name: hellreign-agent
enabled: yes
state: started
- name: Wait for agent to start
pause:
seconds: 3
- name: Verify HellreigN Agent is running
command: systemctl is-active --quiet hellreign-agent
changed_when: false
`
// DockerDeployPlaybook returns the Ansible playbook for Docker deployment.
@@ -72,7 +99,9 @@ const DockerDeployPlaybook = `---
grpc_url: "{{ grpc_url | default('localhost:9001') }}"
container_name: hellreign-agent-{{ agent_label }}
image: "gitea.d3m0k1d.ru/d3m0k1d/hellreign-agent:latest"
install_dir: /opt/hellreign
cert_dir: /etc/hellreign-agent/certs
config_dir: /etc/hellreign-agent
tasks:
- name: Install Docker (if not present)
@@ -94,6 +123,12 @@ const DockerDeployPlaybook = `---
state: directory
mode: '0755'
- name: Create configuration directory
file:
path: "{{ config_dir }}"
state: directory
mode: '0755'
- name: Pull HellreigN Agent image
community.docker.docker_image:
name: "{{ image }}"
@@ -103,14 +138,15 @@ const DockerDeployPlaybook = `---
copy:
content: |
backend_url: "{{ backend_url }}"
grpc_url: "{{ grpc_url }}"
grpc_url: "{{ grpc_url | default('localhost:9001') }}"
label: "{{ agent_label }}"
registration_token: "{{ agent_token }}"
cert_dir: "{{ cert_dir }}"
services:
- name: system
type: journald
dest: "{{ cert_dir }}/config.yml"
- name: "{{ agent_label }}"
type: docker
path: "{{ container_name }}"
dest: "{{ config_dir }}/config.yml"
mode: '0644'
- name: Create and run HellreigN Agent container
@@ -121,6 +157,7 @@ const DockerDeployPlaybook = `---
restart_policy: always
volumes:
- "{{ cert_dir }}:/etc/hellreign-agent/certs"
- "{{ config_dir }}/config.yml:/etc/hellreign-agent/config.yml:ro"
env:
CONFIG_FILE: /etc/hellreign-agent/certs/config.yml
CONFIG_FILE: /etc/hellreign-agent/config.yml
`
+2 -3
View File
@@ -1,5 +1,4 @@
package ansible
const BaseInvTemplate = `
`
// This package contains embedded Ansible templates for playbooks and inventory generation.
// All templates are defined in playbooks.go and inventory.go.