import "github.com/digitalrebar/provision/backend"
backend contains the backend code for DigitalRebar Provision. It has the responsibility for saving and loading all the data we need to the backing store, making sure that said models are valid and remain consistent, making sure that all the links between objects remain consistent, and providing any optimizations needed to make things perform at scale.
bootenv.go conncache.go conncache_linux.go dataTracker.go dhcpUtils.go doc.go errors.go event.go fs.go interface_resolver.go interfaces.go jobs.go jwt-utils.go lease.go machines.go param.go plugins.go preference.go profiles.go renderData.go requestTracker.go reservation.go stage.go subnet.go task.go template.go user.go workflow.go
const ( ValidationError = "ValidationError" TemplateRenderError = "TemplateRenderError" StillInUseError = "StillInUseError" )
AddToCache adds a new remote -> local IP address mapping to the connection cache. If the remote address is already in the cache, its corresponding local address is updates and the timeout is bumped. Mappings that have not been accessed with LocalFor or updated with AddToCache will be evicted if not used for more than 10 minutes.
DefaultIP figures out the IP address of the interface that has the default route. It is used as a fallback IP address when we don't have --static-ip set and we cannot find a local -> remote mapping in the cache.
LocalFor returns the local IP address that has responded to TFTP or HTTP requests for the given remote IP. It also bumps the timeout.
func SetLogPublisher(l *logger.Buffer, pubs *Publishers)
func ValidateDataTrackerStore(fileRoot string, backend store.Store, logger logger.Logger) (hard, soft error)
This must be locked with ALL locks on the source datatracker from the caller.
BootEnv encapsulates the machine-agnostic information needed by the provisioner to set up a boot environment.
swagger:model
func (b *BootEnv) Render(rt *RequestTracker, m *Machine, e models.ErrorAdder) renderers
type Claim struct { Scope string `json:"scope"` Action string `json:"action"` Specific string `json:"specific"` }
Claim is an individial specifier for something we are allowed access to.
Match tests to see if this claim allows access for the specified scope, action, and specific item.
If the Claim has `*` for any field, it matches all possible values for that field.
type DataTracker struct { logger.Logger FileRoot string LogRoot string OurAddress string ForceOurAddress bool StaticPort, ApiPort int FS *FileSystem Backend store.Store GlobalProfileName string // contains filtered or unexported fields }
DataTracker represents everything there is to know about acting as a dataTracker.
func NewDataTracker(backend store.Store, fileRoot, logRoot, addr string, forceAddr bool, staticPort, apiPort int, logger logger.Logger, defaultPrefs map[string]string, publishers *Publishers) *DataTracker
Create a new DataTracker that will use passed store to save all operational data
func (p *DataTracker) Backup() ([]byte, error)
func (dt *DataTracker) GetInterfaces() ([]*models.Interface, error)
func (p *DataTracker) GetToken(tokenString string) (*DrpCustomClaims, error)
func (p *DataTracker) LocalIP(remote net.IP) string
func (p *DataTracker) LogFor(s string) logger.Logger
func (p *DataTracker) Pref(name string) (string, error)
func (p *DataTracker) Prefs() map[string]string
func (p *DataTracker) RenderUnknown(rt *RequestTracker) error
func (p *DataTracker) ReplaceBackend(rt *RequestTracker, st store.Store) (hard, soft error)
Assumes that all locks are held
func (p *DataTracker) Request(l logger.Logger, locks ...string) *RequestTracker
func (p *DataTracker) SealClaims(claims *DrpCustomClaims) (string, error)
func (p *DataTracker) SetPrefs(rt *RequestTracker, prefs map[string]string) error
type DrpCustomClaims struct { DrpClaims []Claim `json:"drp_claims"` GrantorClaims GrantorClaims `json:"grantor_claims"` jwt.StandardClaims }
DrpCustomClaims is a JWT token that contains a list of all the things this token allows access to.
func NewClaim(user, grantor string, ttl time.Duration) *DrpCustomClaims
NewClaim creates a new, unsigned Token that doesn't allow access to anything. You must call Seal() to turn this into a signed JWT token.
func (d *DrpCustomClaims) Add(scope, action, specific string) *DrpCustomClaims
Add adds a discrete Claim to our custom Token class.
func (d *DrpCustomClaims) AddMachine(uuid string) *DrpCustomClaims
Set the specific secrets
func (d *DrpCustomClaims) AddSecrets(user, grantor, machine string) *DrpCustomClaims
Set the specific secrets
func (d *DrpCustomClaims) GrantorId() string
func (d *DrpCustomClaims) HasGrantorId() bool
func (d *DrpCustomClaims) HasMachineUuid() bool
func (d *DrpCustomClaims) HasUserId() bool
func (d *DrpCustomClaims) MachineUuid() string
func (d *DrpCustomClaims) Match(scope, action, specific string) bool
Match tests all the claims in this Token to find one that matches.
func (d *DrpCustomClaims) Seal(m *JwtManager) (string, error)
Seal turns our custom Token class into a signed JWT Token.
func (d *DrpCustomClaims) UserId() string
func (d *DrpCustomClaims) ValidateSecrets(grantor, user, machine string) bool
FileSystem provides the routines to allow the static HTTP and TFTP services to render templates on demand..
func NewFS(backingFSPath string, logger logger.Logger) *FileSystem
NewFS creates a new initialized filesystem that will fall back to serving files from backingFSPath if there is not a template to be rendered.
AddDynamicFile adds a lookaside that handles rendering a file that should be generated on the fly. fsPath is the path where the dynamic lookaside lives, and the passed-in function will be called with the IP address of the system making the request.
AddDynamicTree adds a lookaside responsible for wholesale impersonation of a directory tree. fsPath indicates where AddDynamicTree will start handling all read requests, and the passed-in function will be called with the full path to whatever was being requested.
func (fs *FileSystem) DelDynamicFile(fsPath string)
DelDynamicFile removes a lookaside registered for fsPath, if any.
func (fs *FileSystem) DelDynamicTree(fsPath string)
DelDynamicTree removes a lookaside responsible for wholesale impersonation of a directory tree.
Open tests for the existence of a lookaside for file read request. The returned Reader amd error contains the results of running the lookaside function if one is present. If both the reader and error are nil, FileSystem should fall back to serving a static file.
func (fs *FileSystem) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler for the FileSystem.
TftpResponder returns a function that allows the TFTP midlayer to serve files from the FileSystem.
type GrantorClaims struct { GrantorId string `json:"grantor_id"` GrantorSecret string `json:"grantor_secret"` UserId string `json:"user_id"` UserSecret string `json:"user_secret"` MachineUuid string `json:"machine_uuid"` MachineSecret string `json:"machine_secret"` }
Grantor Claims allow for the token to be validated against the granting user, the current user, and the machine. Each of those object can have a secret that if changed on the user object will invalid the token.
This allows for mass revocation at a machine, grantor, or user level.
func (gc *GrantorClaims) Validate(grantor, user, machine string) bool
If present, we should validate them.
Job represents a task that is running (or has run) on a machine. The job create workflow I envision works like this:
* POST to api/v3/jobs with a body containing {"Machine":
"a-machine-uuid"} If there is no current job, or the current job is "failed", a new job is created for the Task indexed by CurrentTask. If the current job is "finished", the machine CurrentTask is incremented. If that causes CurrentTask to go past the end of the Tasks list for the machine, no job is created and the API returns a 204. If the current job is in the imcomplete state, that job is returned with a 202. Otherwise a new job is created and is returned with a 201. If there is a current job that is neither "incomplete", "failed", nor "finished", the POST fails. The new job will be created with its Previous value set to the machine's CurrentJob, and the machine's CurrentJob is updated with the UUID of the new job.
* When a new Job is created, it makes a RenderData for the
templates contained in the Task the job was created against. The client will be able to retrieve the rendered templates via GET from api/v3/jobs/:job-id/templates.
* The client will place or execute the templates based on whether
there is a Path associated with the expanded Template in the order that the jobs/:id/templates API endpoint returns them in. As it does so, it will log its progress via POST to jobs/:id/log.
* If any job operation fails, the client will update the job status to "failed".
* If all job operations succeed, the client will update the job status to "finished"
* On provisioner startup, all machine CurrentJobs are set to "failed" if they are not "finished"
swagger:model
func (j *Job) LogPath(rt *RequestTracker) string
type JwtConfig struct { // digital signing method, defaults to jwt.SigningMethodHS256 (SHA256) Method jwt.SigningMethod }
Config configures a Manager.
type JwtManager struct {
// contains filtered or unexported fields
}
Manager is a JSON Web Token (JWT) Provider which create or retrieves tokens with a particular signing key and options.
func NewJwtManager(key []byte, configs ...JwtConfig) *JwtManager
New creates a new Manager which provides JWTs using the given signing key. Defaults to signing with SHA256 HMAC (jwt.SigningMethodHS256)
Lease models a DHCP Lease swagger:model
func FakeLeaseFor(rt *RequestTracker, strat, token string, via []net.IP) (lease *Lease, subnet *Subnet, reservation *Reservation)
FakeLeaseFor returns a lease that has zero duration and that should not be saved. It is intended for use when we are acting as a proxy DHCP server or we are acting as a BINL server.
func FindLease(rt *RequestTracker, strat, token string, req net.IP) (lease *Lease, subnet *Subnet, reservation *Reservation, err error)
FindLease finds an appropriate matching Lease. If a non-nil error is returned, the DHCP system must NAK the response. If lease and error are nil, the DHCP system must not respond to the request. Otherwise, the lease will be returned with its ExpireTime updated and the Lease saved.
This function should be called in response to a DHCPREQUEST.
func FindOrCreateLease(rt *RequestTracker, strat, token string, req net.IP, via []net.IP) (lease *Lease, subnet *Subnet, reservation *Reservation, fresh bool)
FindOrCreateLease will return a lease for the passed information, creating it if it can. If a non-nil Lease is returned, it has been saved and the DHCP system can offer it. If the returned lease is nil, then the DHCP system should not respond.
This function should be called for DHCPDISCOVER.
func (l *Lease) Reservation(rt *RequestTracker) *Reservation
func (l *Lease) Subnet(rt *RequestTracker) *Subnet
LeaseNAK is the error that shall be returned when we cannot give a system the IP address it requested. If FindLease or FindOrCreateLease return this as their error, then the DHCP midlayer must NAK the request.
Machine represents a single bare-metal system that the provisioner should manage the boot environment for. swagger:model
HexAddress returns Address in raw hexadecimal format, suitable for pxelinux and elilo usage.
Param represents metadata about a Parameter or a Preference. Specifically, it contains a description of what the information is for, detailed documentation about the param, and a JSON schema that the param must match to be considered valid. swagger:model
type Paramer interface { models.Model GetParams(Stores, bool) map[string]interface{} SetParams(Stores, map[string]interface{}) error GetParam(Stores, string, bool) (interface{}, bool) SetParam(Stores, string, interface{}) error }
Plugin represents a single instance of a running plugin. This contains the configuration need to start this plugin instance. swagger:model
Pref tracks a global DigitalRebar Provision preference -- things like the bootenv to use for unknown systems trying to PXE boot to us, the default bootenv for known systems, etc.
Profile represents a set of key/values to use in template expansion.
There is one special profile named 'global' that acts as a global set of parameters for the system.
These can be assigned to a machine's profile list. swagger:model
* NOTE: CRUCIAL: CRITICAL: This could be bad if not adhered. * The Publish, release, and reserve routines must not call loggers * that publish events!
type Publishers struct {
// contains filtered or unexported fields
}
func NewPublishers(logger *log.Logger) *Publishers
func (p *Publishers) Add(pp Publisher)
func (p *Publishers) List() []Publisher
func (p *Publishers) Remove(pp Publisher)
type RenderData struct { Machine *rMachine // The Machine that the template is being rendered for. Env *rBootEnv // The boot environment that provided the template. Task *rTask Stage *rStage // contains filtered or unexported fields }
RenderData is the struct that is passed to templates as a source of parameters and useful methods.
func (r *RenderData) ApiURL() string
func (r *RenderData) BootParams() (string, error)
BootParams is a helper function that expands the BootParams template from the boot environment.
func (r *RenderData) CallTemplate(name string, data interface{}) (ret interface{}, err error)
func (r *RenderData) GenerateInfiniteToken() string
func (r *RenderData) GenerateProfileToken(profile string, duration int) string
func (r *RenderData) GenerateToken() string
func (r *RenderData) InstallRepos() []*Repo
func (r *RenderData) MachineRepos() []*Repo
func (r *RenderData) Param(key string) (interface{}, error)
Param is a helper function for extracting a parameter from Machine.Params
func (r *RenderData) ParamAsJSON(key string) (string, error)
func (r *RenderData) ParamAsYAML(key string) (string, error)
func (r *RenderData) ParamExists(key string) bool
ParamExists is a helper function for determining the existence of a machine parameter.
func (r *RenderData) ParseUrl(segment, rawUrl string) (string, error)
func (r *RenderData) ProvisionerAddress() string
func (r *RenderData) ProvisionerURL() string
func (r *RenderData) Repos(tags ...string) []*Repo
type Repo struct { Tag string `json:"tag"` OS []string `json:"os"` URL string `json:"url"` PackageType string `json:"packageType"` RepoType string `json:"repoType"` InstallSource bool `json:"installSource"` SecuritySource bool `json:"securitySource"` Distribution string `json:"distribution"` Components []string `json:"components"` // contains filtered or unexported fields }
func (rd *Repo) R() *RenderData
func (rt *RequestTracker) AllLocked(thunk func(Stores))
func (rt *RequestTracker) ApiURL(remoteIP net.IP) string
func (rt *RequestTracker) Do(thunk func(Stores))
func (rt *RequestTracker) FileURL(remoteIP net.IP) string
func (rt *RequestTracker) Find(prefix, key string) models.Model
func (rt *RequestTracker) GetParam(obj models.Paramer, key string, aggregate bool) (interface{}, bool)
func (rt *RequestTracker) Index(name string) *index.Index
func (rt *RequestTracker) MachineForMac(mac string) *Machine
func (rt *RequestTracker) Patch(obj models.Model, key string, patch jsonpatch2.Patch) (models.Model, error)
func (rt *RequestTracker) Publish(prefix, action, key string, ref interface{}) error
func (rt *RequestTracker) PublishEvent(e *models.Event) error
func (rt *RequestTracker) SealClaims(claims *DrpCustomClaims) (string, error)
type Reservation struct { *models.Reservation // contains filtered or unexported fields }
Reservation tracks persistent DHCP IP address reservations.
swagger:model
func AsReservation(o models.Model) *Reservation
func AsReservations(o []models.Model) []*Reservation
func (r *Reservation) BeforeSave() error
func (l *Reservation) Indexes() map[string]index.Maker
func (r *Reservation) Locks(action string) []string
func (r *Reservation) New() store.KeySaver
func (r *Reservation) OnChange(oldThing store.KeySaver) error
func (r *Reservation) OnCreate() error
func (r *Reservation) OnLoad() error
func (obj *Reservation) SaveClean() store.KeySaver
func (obj *Reservation) SetReadOnly(b bool)
func (r *Reservation) Validate()
Stage encapsulates tasks we want to run a machine
swagger:model
func (s *Stage) Render(rt *RequestTracker, m *Machine, e models.ErrorAdder) renderers
dtobjs is an in-memory cache of all the objects we could reference. The implementation of this may need to change from storing a slice of things to a more elaborate datastructure at some point in time. Since that point in time is when the slices are forced out of CPU cache, I am not terribly concerned for now. Until that point is reached, sorting and searching slices is fantastically efficient.
Subnet represents a DHCP Subnet
swagger:model
Task is a thing that can run on a Machine.
swagger:model
Template represents a template that will be associated with a boot environment.
swagger:model
User is an API user of DigitalRebar Provision swagger:model
func (u *User) ChangePassword(rt *RequestTracker, newPass string) error
Path | Synopsis |
---|---|
index |
Package backend imports 44 packages (graph) and is imported by 3 packages. Updated 2018-04-27. Refresh now. Tools for package owners.