gossh

package module
v0.0.0-...-740721f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2020 License: GPL-3.0 Imports: 12 Imported by: 0

README

GOSSH

This repo is an experiement with creating a declarative IT automation and configuration management package for Golang. Think Ansible, but no Yaml, just plain Go. WOW - all teh power!

  • Declarative - use rules to check and ensure state on any linux host
  • Agentless - all work is done on remote hosts by issuing commands via SSH
  • Efficient - leverage ready-made rules to kick-start your IT automation

The project is in a super-early state. I am looking for API/usage/naming convention input and ideas in general on how to approach this problem. Have a look at examples to get a feel for what I currently think it would look like to use the package. If you have any ideas please reach out through a GH issue.

Building blocks

The package has only a handful main concepts or building blocks.

Rules

The base building block of the declarative mindset baked into this experiment is the notion of a Rule. A rule is an interface with a single Ensure function. Ensure does what it sounds like: Ensure ensures the rule is adhered to on the target.

Ensuring is a two-step process - check and enforce. Enforcement is only done if the check was not successful.

An example of a rule is apt.Package. Check verifies if the apt package is installed or not, and enforcement is done by (un)installs the package.

Rules are made up of imperative code/logic, other declarative rules or a combination of both. Rules can be nested infinitely.

Rules are applied to Targets.

Implemented/example rules (just to show some ideas):

  • file.Exists - creates an empty file if it does not exists
  • apt.Package - install/uninstall apt packages
  • base.Cmd - run shell commands as Check and Ensure. Check depends on the ExitStatus code.
  • base.Meta - for constructing meta-rules on the fly. This is where imperative mode kicks in.
Target

A Target is a bare-metal server, virtual machine or container. It can be localhost, a remote host (SSH) or a docker container on localhost.

(Current) Requirements

  • Running Linux
  • Bash shell available
  • Sudo installed
  • SSH'able (remote)
Inventories

An Inventory is a list of Hosts.

Usage - give it a spin using docker

Please remeber that this is very experimental

Prerequisites:

  • Go
  • Docker

This is what you do:

  1. Clone this repo
  2. Build and run a SSH enabled Ubuntu container by running make docker
  3. Cd over to examples/random and try running it with go run main.go
  4. Have a look at the output
  5. Modify the example script however you like and run again.
  6. Kill and remove the container using make docker-down

Motivation

I've recently listened to Pulumi: Infrastructure as Code with Joe Duffy on Software Engineering Daily. The vision and ideas behind Pulumi really resonated with me. The promise of no YAML or DSL - and just using a progamming language and tooling I allready enjoy - was very appealing. Combining a full-fledged programming language (with package management) with a declarative structural representation of the state sounds powerful and like something I would like to have.

Ansible has been my favorite CM tool for a while. It's awesome! But if I'm honest, I'm not really fond of all the YAML. I also find that I ofted need to do quite a lot of imperative things in the playbooks (register & when, I'm looking at you), which is awkward. What I do love about Ansible though, it it's simplicy and low learing curve and that it is agentless and does all it's work over SSH.

In essence, the experiment aims to take all the things I love about Ansible and bring all the nice things that Pulumi promises, but for configuration, not provisioning.

I think the Go language, typechecking, compile-time checks, standard library, package manager and simplicity makes it perfect starting point for nice configuration management tool.

Docs

SUDO

Gossh building blocks allows commands and rules to run as other users. It is done using Sudo.

References

Early feedback Reddit threads

Inspiration

This project is heavily inspired by

  • Pulumi
  • Puppet Bolt
  • Ansible
  • GOSS

Licence

GNU General Public License v3.0

Documentation

Index

Constants

View Source
const BlockedByValidate int = 81549300

BlockedByValidate is an ExitCode used to indicate that the command was not run, but rather blocked because the target does not allow any modifications. The intended use for this is when validating rules.

Variables

This section is empty.

Functions

This section is empty.

Types

type Fact

type Fact int

Fact is a key

const (
	// OS is the operating system
	OS Fact = iota
	// OSFamily is the family of operating systems
	OSFamily
	// OSVersion is the os version
	OSVersion
)

func (Fact) String

func (i Fact) String() string

type Facts

type Facts struct {
	// contains filtered or unexported fields
}

Facts are gathered from the machine

func (*Facts) Gather

func (f *Facts) Gather(m *Host) error

Gather gathers facts about the machine

type Host

type Host struct {

	// AllowChange controls if it is allowed to do any changes on the host
	AllowChange bool
	// contains filtered or unexported fields
}

Host is where we do all the things

func New

func New(target target.Target) *Host

New returns a host based on a target

func NewLocalHost

func NewLocalHost(sudopass string) (*Host, error)

NewLocalHost returns a new host that is pointing to localhost

func NewRemoteHost

func NewRemoteHost(addr string, user string, sudopass string, hostkeycallback ssh.HostKeyCallback, auths ...ssh.AuthMethod) (*Host, error)

NewRemoteHost returns a new remote host

func (*Host) Apply

func (h *Host) Apply(name string, r Rule) (Status, error)

Apply applies Rule r on m, i.e. runs Check and conditionally runs Ensure Id must be unique string. //TODO - how to explain this

func (*Host) Log

func (h *Host) Log(msg string, keyAndValues ...string)

Log is logging

func (*Host) RunChange

func (h *Host) RunChange(cmd string, stdin string, user string) (Response, error)

RunChange are used to run cmd's that RunChanges the state on m

func (*Host) RunCheck

func (h *Host) RunCheck(cmd string, stdin string, user string) (Response, error)

RunCheck are used to run cmd's that does not modify anything on m

func (*Host) String

func (h *Host) String() string

String implements io.Stringer for a Host

type Inventory

type Inventory []*Host

Inventory is a list of Hosts

func (*Inventory) Add

func (i *Inventory) Add(m *Host)

Add adds m to i

type Response

type Response struct {
	Stdout     string
	Stderr     string
	ExitStatus int
}

Response contains the response from a remotely run cmd

func (Response) Success

func (r Response) Success() bool

Success is a convenience method to check if an exit code is either 0 or BlockedByValidate. It is provided as a form of syntactic sugar.

type Rule

type Rule interface {
	Ensure(h *Host) (status Status, err error)
}

Rule is an interface that wraps the Ensure method

Ensure runs commands on Target t to check and enforce that a declared state is adhered to.

If anything goes wrong, error err is returned. Otherwise err is nil.

type Status

type Status int

Status indicates the status of a Rule.

const (
	// StatusUndefined is set as the zero-value. Should only be used when error is returned, but consider using StatusFailed instead.
	StatusUndefined Status = iota

	// StatusSkipped means that the rule is skipped.
	// Useful for conditional (e.g. os-specific) rules.
	StatusSkipped

	// StatusSatisfied means rule was allready adhered to and no changes had to be made.
	StatusSatisfied

	// StatusNotSatisfied means that a check was done, and it was not ok.
	// The only use for this status is when changes are blocked on the target - when Rules are applied in check-only mode.
	StatusNotSatisfied

	// StatusEnforced means that the rule did changes to the target to ensure that the declared rule was satisfied.
	// The changes was successful.
	StatusEnforced

	// StatusFailed means someting went wrong. Usually returned when error is also returned.
	StatusFailed
)

func (Status) OK

func (s Status) OK() bool

OK reports if the status should be considered as OK. Returns true if status is one of StatusSkipped, StatusSatisfied, StatusNotSatisfied, StatusEnforced

func (Status) String

func (i Status) String() string

type SuperTarget

type SuperTarget interface {
	target.Target

	// Apply checks and ensures that the Target adheres to Rule r.
	// String name should be unique within the immediate context, short and descriptive.
	Apply(name string, r Rule) (Status, error)

	// AllowChange reports if the target allows changes to be done or not.
	// False will be returned if target is in check-only mode.
	//
	// The function can be used by Rule implementers in cases where it makes more sense than running RunCheck and getting a blocked response.
	AllowChange() bool

	// RunChange runs the command cmd on the Target.
	//
	// RunChange does the same as RunCheck, but must ONLY be used for cmd's that modify state on the Target.
	//
	// Callers must handle a returned Response with ExitStatus BlockedByValidate, indicating that changes cannot be done to the target.
	// When BlockedByValidate is returned, stdout and stderr will be empty string and err will be nil.
	//
	// If user is not the connected user, sudo/su will be applied to the command.
	// Empty user means connected user. '-' is interpreted as 'root'.
	//
	// Stdin can be used to add stdin to the commmand.
	RunChange(cmd string, stdin string, user string) (Response, error)

	// RunCheck runs the command cmd on the Target.
	//
	// RunCheck does the same as RunChange, but must ONLY be used for cmd's that doesn't modify any state on the Target.
	//
	// If user is not the connected user, sudo/su will be applied to the command.
	// Empty user means connected user. '-' is interpreted as 'root'.
	//
	// Stdin can be used to add stdin to the commmand.
	RunCheck(cmd string, stdin string, user string) (Response, error)
}

SuperTarget is a target for commands and rules

SuperTargets can be in a validate state, that does not allow for commands that RunChange the state of the system to run.

Directories

Path Synopsis
examples
modules
rules
rmt
sh
testing

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL