add docs
This commit is contained in:
parent
40ff6408f3
commit
7681f346bd
@ -31,6 +31,9 @@ var (
|
|||||||
ErrSSHExecute = errors.New("unable to execute command")
|
ErrSSHExecute = errors.New("unable to execute command")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewSSHConn instanciates a new SSH connection.
|
||||||
|
// The `privkey` arg is the path of private key where the corresponding
|
||||||
|
// public has been deployed on the `user` server.
|
||||||
func NewSSHConn(addr, user string, port int, privkey string) (SSHConn, error) {
|
func NewSSHConn(addr, user string, port int, privkey string) (SSHConn, error) {
|
||||||
var newconn SSHConn
|
var newconn SSHConn
|
||||||
|
|
||||||
@ -75,6 +78,13 @@ func (c *SSHConn) Close() error {
|
|||||||
return c.client.Close()
|
return c.client.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CopyFile copies a local `src` file to the remote `dest` server.
|
||||||
|
//
|
||||||
|
// NOTE: for now the `dest` filepath (absolute or relative) does not
|
||||||
|
// create a push the file to the desired location.
|
||||||
|
// All the files are copied in the remote user HOME.
|
||||||
|
//
|
||||||
|
// TODO: create the `dest` if not exist.
|
||||||
func (c *SSHConn) CopyFile(src, dest string) error {
|
func (c *SSHConn) CopyFile(src, dest string) error {
|
||||||
sshSession, err := c.client.NewSession()
|
sshSession, err := c.client.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -134,6 +144,7 @@ func (c *SSHConn) CopyFile(src, dest string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute executes a shell command remotly and returns the output.
|
||||||
func (c *SSHConn) Execute(cmd string) (string, error) {
|
func (c *SSHConn) Execute(cmd string) (string, error) {
|
||||||
sshSession, err := c.client.NewSession()
|
sshSession, err := c.client.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -30,6 +30,14 @@ const (
|
|||||||
GracefulTimeout = 10 * time.Second
|
GracefulTimeout = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Base struct of the deployers.
|
||||||
|
// It handles the main informations to build a deployer.
|
||||||
|
//
|
||||||
|
// "Inherited" deployers must implement three methods in order
|
||||||
|
// to satify the `IDeployer` contract:
|
||||||
|
// - `Deploy() error`: run shell command to deploy the archive remotly
|
||||||
|
// - `Build() error`: build the archive
|
||||||
|
// - `Clear() error`: clean all the ressources locally and remotly
|
||||||
type deployer struct {
|
type deployer struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
fnCancel context.CancelFunc
|
fnCancel context.CancelFunc
|
||||||
@ -63,6 +71,12 @@ func (d *deployer) setDone(err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetCancellationFunc sets a context cancellation function for the deployer.
|
||||||
|
//
|
||||||
|
// If two deployers are related on the same context, one failed and you want
|
||||||
|
// to stop the execution of the others. Then, associate a cancel function
|
||||||
|
// for the deployer and the cancel func will be fired if error occurred
|
||||||
|
// during a deployment step. Stopping all the deployers.
|
||||||
func (d *deployer) SetCancellationFunc(fnCancel context.CancelFunc) {
|
func (d *deployer) SetCancellationFunc(fnCancel context.CancelFunc) {
|
||||||
d.fnCancel = fnCancel
|
d.fnCancel = fnCancel
|
||||||
}
|
}
|
||||||
@ -75,6 +89,13 @@ func (d *deployer) Error() error {
|
|||||||
return d.errFlag
|
return d.errFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Done returns a channel providing the shutdown or the termination
|
||||||
|
// of the deployer.
|
||||||
|
//
|
||||||
|
// If the context is done, it will wait until all the current actions are done
|
||||||
|
// for a graceful shutdown. It has a graceful timeout (see: `GracefulTimeout`).
|
||||||
|
//
|
||||||
|
// If the deployer is done, succeed or failed, it simply returns.
|
||||||
func (d *deployer) Done() <-chan struct{} {
|
func (d *deployer) Done() <-chan struct{} {
|
||||||
chDone := make(chan struct{})
|
chDone := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NginxDeployer handles the deployment of an Nginx configuration.
|
||||||
type NginxDeployer struct {
|
type NginxDeployer struct {
|
||||||
*deployer
|
*deployer
|
||||||
conn connection.IConnection
|
conn connection.IConnection
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import (
|
|||||||
|
|
||||||
var ErrSwarmDeployerNoArchive = errors.New("no archive found to be deployed")
|
var ErrSwarmDeployerNoArchive = errors.New("no archive found to be deployed")
|
||||||
|
|
||||||
|
// SwarmDeployer handles the deployment of a Docker service on the swarm instance.
|
||||||
type SwarmDeployer struct {
|
type SwarmDeployer struct {
|
||||||
*deployer
|
*deployer
|
||||||
conn connection.IConnection
|
conn connection.IConnection
|
||||||
@ -78,6 +79,10 @@ func (sd *SwarmDeployer) Clear() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build builds the archive with mandatory files to deploy a swarm service.
|
||||||
|
//
|
||||||
|
// After the build, the path of the local archive built is set in
|
||||||
|
// the `archivePath` field.
|
||||||
func (sd *SwarmDeployer) Build() error {
|
func (sd *SwarmDeployer) Build() error {
|
||||||
sd.processing.Store(true)
|
sd.processing.Store(true)
|
||||||
defer sd.processing.Store(false)
|
defer sd.processing.Store(false)
|
||||||
|
|||||||
@ -14,6 +14,11 @@ type IClient interface {
|
|||||||
|
|
||||||
var ErrDockerClientSave = errors.New("unable to save image into tar")
|
var ErrDockerClientSave = errors.New("unable to save image into tar")
|
||||||
|
|
||||||
|
// Client is a simple Docker client wrapping the local Docker daemon.
|
||||||
|
// It does not use the Docker API but instead shell command and collect the output.
|
||||||
|
//
|
||||||
|
// NOTE: for now, it's ok, it only needs one command so, no need to add a fat dedicated
|
||||||
|
// library with full Docker client API.
|
||||||
type Client struct{}
|
type Client struct{}
|
||||||
|
|
||||||
var _ IClient = (*Client)(nil)
|
var _ IClient = (*Client)(nil)
|
||||||
@ -22,6 +27,8 @@ func NewClient() Client {
|
|||||||
return Client{}
|
return Client{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save saves the `imageName` (tag included) in tar format in the target directory: `dest`.
|
||||||
|
// The `dest` directory must exist with correct permissions.
|
||||||
func (c *Client) Save(imageName, dest string) (string, error) {
|
func (c *Client) Save(imageName, dest string) (string, error) {
|
||||||
destInfo, err := os.Stat(dest)
|
destInfo, err := os.Stat(dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
5
main.go
5
main.go
@ -11,12 +11,13 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"gitea.thegux.fr/hmdeploy/deployers"
|
"gitea.thegux.fr/hmdeploy/deployers"
|
||||||
"gitea.thegux.fr/hmdeploy/docker"
|
"gitea.thegux.fr/hmdeploy/docker"
|
||||||
"gitea.thegux.fr/hmdeploy/models"
|
"gitea.thegux.fr/hmdeploy/models"
|
||||||
"gitea.thegux.fr/hmdeploy/scheduler"
|
"gitea.thegux.fr/hmdeploy/scheduler"
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@ -19,6 +19,7 @@ type (
|
|||||||
HMLXC map[string]*HMNetInfo
|
HMLXC map[string]*HMNetInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HMMap handles all the informations of your home server instances.
|
||||||
type HMMap struct {
|
type HMMap struct {
|
||||||
*HMNetInfo
|
*HMNetInfo
|
||||||
VM HMVM `json:"vm,omitempty"`
|
VM HMVM `json:"vm,omitempty"`
|
||||||
|
|||||||
@ -47,6 +47,7 @@ func getFileInfo(baseDir, filePath string) (fs.FileInfo, error) {
|
|||||||
return fInf, nil
|
return fInf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Project handles the details and file informations of your project.
|
||||||
type Project struct {
|
type Project struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Dir string
|
Dir string
|
||||||
@ -89,6 +90,10 @@ func (p *Project) validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectFromDir instantiates a new project from a directory path.
|
||||||
|
//
|
||||||
|
// The directory path must refers to the path including the `.homeserver` dir not
|
||||||
|
// the `.homeserver` path itself.
|
||||||
func ProjectFromDir(dir string) (Project, error) {
|
func ProjectFromDir(dir string) (Project, error) {
|
||||||
var p Project
|
var p Project
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,7 @@ const (
|
|||||||
|
|
||||||
type FnJob func() error
|
type FnJob func() error
|
||||||
|
|
||||||
|
// taskStore is a thread safe `Task` store.
|
||||||
type taskStore struct {
|
type taskStore struct {
|
||||||
l sync.RWMutex
|
l sync.RWMutex
|
||||||
tasks map[string]*Task
|
tasks map[string]*Task
|
||||||
@ -62,6 +63,9 @@ func (ts *taskStore) len() int {
|
|||||||
return len(ts.tasks)
|
return len(ts.tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Task represents an execution unit handle by the scheduler.
|
||||||
|
//
|
||||||
|
// Next field links to next executable tasks (tree kind).
|
||||||
type Task struct {
|
type Task struct {
|
||||||
Name string
|
Name string
|
||||||
Job FnJob
|
Job FnJob
|
||||||
@ -78,6 +82,8 @@ func NewTask(name string, job FnJob, next ...*Task) *Task {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scheduler is a simple scheduler.
|
||||||
|
// Handling tasks and executes them, that's all.
|
||||||
type Scheduler struct {
|
type Scheduler struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
fnCancel context.CancelFunc
|
fnCancel context.CancelFunc
|
||||||
@ -90,6 +96,10 @@ type Scheduler struct {
|
|||||||
tasks taskStore
|
tasks taskStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScheduler instantiates a new `Scheduler`.
|
||||||
|
//
|
||||||
|
// If you want to run tasks immediately after the scheduler creation, you can pass a list of
|
||||||
|
// `Task` with `tasks` argument.
|
||||||
func NewScheduler(ctx context.Context, capacity uint32, workers uint8, tasks ...*Task) *Scheduler {
|
func NewScheduler(ctx context.Context, capacity uint32, workers uint8, tasks ...*Task) *Scheduler {
|
||||||
ctxChild, fnCancel := context.WithCancel(ctx)
|
ctxChild, fnCancel := context.WithCancel(ctx)
|
||||||
s := Scheduler{
|
s := Scheduler{
|
||||||
|
|||||||
@ -37,6 +37,7 @@ func addToArchive(tw *tar.Writer, filename string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateArchive creates a gzip tar archive in the `destDir` path including `files`.
|
||||||
func CreateArchive(destDir, name string, files ...string) (string, error) {
|
func CreateArchive(destDir, name string, files ...string) (string, error) {
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
archivePath := filepath.Join(
|
archivePath := filepath.Join(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user