pkiadm/cmd/pkiadmd/location.go

219 lines
5.4 KiB
Go

package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"time"
"github.com/gibheer/pkiadm"
)
const (
ENoPathGiven = Error("no path given")
)
type (
Location struct {
ID string
PreCommand string
PostCommand string
Path string
Dependencies []pkiadm.ResourceName
Interval Interval
}
)
func NewLocation(id, path, preCom, postCom string, res []pkiadm.ResourceName,
interval Interval) (*Location, error) {
if id == "" {
return nil, ENoIDGiven
}
if path == "" {
return nil, ENoPathGiven
}
l := &Location{
ID: id,
Path: path,
Dependencies: res,
Interval: interval,
}
return l, nil
}
func (l *Location) Name() pkiadm.ResourceName {
return pkiadm.ResourceName{l.ID, pkiadm.RTLocation}
}
// Refresh writes all resources into the single file.
func (l *Location) Refresh(lookup *Storage) error {
raw := []byte{}
for _, rn := range l.DependsOn() {
r, err := lookup.Get(rn)
if err != nil {
return err
}
output, err := r.Pem()
if err != nil {
return err
}
raw = append(raw, output...)
}
if l.PreCommand != "" {
log.Printf("location '%s' is updating '%s' - pre '%s'", l.ID, l.Path, l.PreCommand)
cmd := exec.Command(l.PreCommand, l.Path)
if err := cmd.Run(); err != nil {
return err
}
}
log.Printf("location '%s' is updating '%s'", l.ID, l.Path)
if err := ioutil.WriteFile(l.Path, raw, 0600); err != nil {
log.Printf("could not write location '%s': %s", l.ID, err)
return err
}
if l.PostCommand != "" {
log.Printf("location '%s' is updating '%s' - post '%s'", l.ID, l.Path, l.PostCommand)
cmd := exec.Command(l.PostCommand, l.Path)
if err := cmd.Run(); err != nil {
return err
}
}
l.Interval.LastRefresh = time.Now()
return nil
}
func (l *Location) RefreshInterval() Interval {
return l.Interval
}
func (l *Location) DependsOn() []pkiadm.ResourceName { return l.Dependencies }
// Pem is not used by location, as it does not contain any data.
func (l *Location) Pem() ([]byte, error) { return []byte{}, nil }
// Checksum is not used by Location, as it does not contain any data.
func (l *Location) Checksum() []byte { return []byte{} }
func (s *Server) CreateLocation(inLoc pkiadm.Location, res *pkiadm.Result) error {
s.lock()
defer s.unlock()
deps := []pkiadm.ResourceName{}
for _, dep := range inLoc.Dependencies {
deps = append(deps, pkiadm.ResourceName{ID: dep.ID, Type: dep.Type})
}
loc, err := NewLocation(inLoc.ID, inLoc.Path, inLoc.PreCommand, inLoc.PostCommand, deps, NoInterval)
if err != nil {
res.SetError(err, "Could not create location '%s'", inLoc.ID)
return nil
}
if err := s.storage.AddLocation(loc); err != nil {
res.SetError(err, "Could not add location '%s'", inLoc.ID)
return nil
}
return s.store(res)
}
func (s *Server) SetLocation(changeset pkiadm.LocationChange, res *pkiadm.Result) error {
s.lock()
defer s.unlock()
changed := changeset.Location
locName := pkiadm.ResourceName{changed.ID, pkiadm.RTLocation}
loc, err := s.storage.GetLocation(locName)
if err != nil {
res.SetError(err, "could not find location '%s'", changeset.Location.ID)
return nil
}
for _, field := range changeset.FieldList {
switch field {
case "path":
// TODO remove old file?
loc.Path = changed.Path
case "pre-cmd":
loc.PreCommand = changed.PreCommand
case "post-cmd":
loc.PostCommand = changed.PostCommand
case "resources":
loc.Dependencies = changed.Dependencies
default:
res.SetError(fmt.Errorf("unknown field"), "unknown field '%s'", field)
return nil
}
}
if err := s.storage.Update(locName); err != nil {
log.Printf("could not update location '%s': %s", loc.ID, err)
res.SetError(err, "Could not update location '%s'", loc.ID)
return nil
}
return s.store(res)
}
func (s *Server) DeleteLocation(inLoc pkiadm.Location, res *pkiadm.Result) error {
s.lock()
defer s.unlock()
loc, err := s.storage.GetLocation(pkiadm.ResourceName{inLoc.ID, pkiadm.RTLocation})
if err != nil {
res.SetError(err, "could not find location '%s'", inLoc.ID)
return nil
}
if err := os.Remove(loc.Path); err != nil {
res.SetError(err, "Could not remove file '%s' for location '%s'", loc.Path, loc.ID)
return nil
}
if err := s.storage.Remove(loc); err != nil {
res.SetError(err, "Could not remove location '%s'", loc.ID)
return nil
}
if loc.PostCommand != "" {
cmd := exec.Command(loc.PostCommand, loc.Path)
if err := cmd.Run(); err != nil {
res.SetError(err, "Could not run post command after deleting '%s'", loc.ID)
return nil
}
}
return s.store(res)
}
func (s *Server) ShowLocation(inLoc pkiadm.PrivateKey, res *pkiadm.ResultLocations) error {
s.lock()
defer s.unlock()
loc, err := s.storage.GetLocation(pkiadm.ResourceName{inLoc.ID, pkiadm.RTLocation})
if err != nil {
res.Result.SetError(err, "Could not find location '%s'", inLoc.ID)
return nil
}
res.Locations = []pkiadm.Location{pkiadm.Location{
ID: loc.ID,
Path: loc.Path,
PreCommand: loc.PreCommand,
PostCommand: loc.PostCommand,
Dependencies: loc.Dependencies,
}}
return nil
}
func (s *Server) ListLocation(filter pkiadm.Filter, res *pkiadm.ResultLocations) error {
s.lock()
defer s.unlock()
for _, loc := range s.storage.Locations {
res.Locations = append(res.Locations, pkiadm.Location{
ID: loc.ID,
Path: loc.Path,
PreCommand: loc.PreCommand,
PostCommand: loc.PostCommand,
Dependencies: loc.Dependencies,
})
}
return nil
}