mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 17:08:53 +00:00
Refactor Deb functionality into packaging package
This commit is contained in:
parent
117708aa7b
commit
967d812bc2
3 changed files with 254 additions and 236 deletions
|
|
@ -1,34 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/fleetdm/orbit/pkg/constant"
|
||||
"github.com/fleetdm/orbit/pkg/update"
|
||||
"github.com/fleetdm/orbit/pkg/update/filestore"
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/goreleaser/nfpm/v2/deb"
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"github.com/fleetdm/orbit/pkg/packaging"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type packageOptions struct {
|
||||
FleetURL string
|
||||
EnrollSecret string
|
||||
StartService bool
|
||||
Insecure bool
|
||||
}
|
||||
|
||||
func main() {
|
||||
var opt packageOptions
|
||||
var opt packaging.Options
|
||||
log.Logger = log.Output(
|
||||
zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339Nano},
|
||||
)
|
||||
|
|
@ -74,227 +58,10 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
return buildLinux(opt)
|
||||
return packaging.BuildDeb(opt)
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
log.Fatal().Err(err).Msg("package failed")
|
||||
}
|
||||
}
|
||||
|
||||
func buildLinux(opt packageOptions) error {
|
||||
// Initialize directories
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "orbit-package")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create temp dir")
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
log.Debug().Str("path", tmpDir).Msg("created temp dir")
|
||||
|
||||
filesystemRoot := filepath.Join(tmpDir, "filesystem")
|
||||
if err := os.MkdirAll(filesystemRoot, constant.DefaultDirMode); err != nil {
|
||||
return errors.Wrap(err, "create filesystem dir")
|
||||
}
|
||||
orbitRoot := filepath.Join(filesystemRoot, "var", "lib", "fleet", "orbit")
|
||||
if err := os.MkdirAll(orbitRoot, constant.DefaultDirMode); err != nil {
|
||||
return errors.Wrap(err, "create orbit dir")
|
||||
}
|
||||
|
||||
// Write files
|
||||
|
||||
if err := writeSystemdUnit(opt, filesystemRoot); err != nil {
|
||||
return errors.Wrap(err, "write systemd unit")
|
||||
}
|
||||
|
||||
if err := writeEnvFile(opt, filesystemRoot); err != nil {
|
||||
return errors.Wrap(err, "write env file")
|
||||
}
|
||||
|
||||
postInstallPath := filepath.Join(tmpDir, "postinstall.sh")
|
||||
if err := writePostInstall(opt, postInstallPath); err != nil {
|
||||
return errors.Wrap(err, "write postinstall script")
|
||||
}
|
||||
|
||||
// Initialize autoupdate metadata
|
||||
|
||||
localStore, err := filestore.New(filepath.Join(orbitRoot, "tuf-metadata.json"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create local metadata store")
|
||||
}
|
||||
updateOpt := update.DefaultOptions
|
||||
updateOpt.RootDirectory = orbitRoot
|
||||
updateOpt.ServerURL = "https://tuf.fleetctl.com"
|
||||
updateOpt.LocalStore = localStore
|
||||
updateOpt.Platform = "linux"
|
||||
|
||||
updater, err := update.New(updateOpt)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to init updater")
|
||||
}
|
||||
if err := updater.UpdateMetadata(); err != nil {
|
||||
return errors.Wrap(err, "failed to update metadata")
|
||||
}
|
||||
osquerydPath, err := updater.Get("osqueryd", "stable")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get osqueryd")
|
||||
}
|
||||
log.Debug().Str("path", osquerydPath).Msg("got osqueryd")
|
||||
|
||||
// Pick up all file contents
|
||||
|
||||
contents := files.Contents{
|
||||
&files.Content{
|
||||
Source: filepath.Join(filesystemRoot, "**"),
|
||||
Destination: "/",
|
||||
},
|
||||
&files.Content{
|
||||
Source: "orbit",
|
||||
Destination: "/var/lib/fleet/orbit/orbit",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
Mode: constant.DefaultExecutableMode,
|
||||
},
|
||||
},
|
||||
&files.Content{
|
||||
Source: "/var/lib/fleet/orbit/orbit",
|
||||
Destination: "/usr/local/bin/orbit",
|
||||
Type: "symlink",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
// TODO follow up on nfpm not respecting this
|
||||
// https://github.com/goreleaser/nfpm/issues/286
|
||||
Mode: constant.DefaultExecutableMode | os.ModeSymlink,
|
||||
},
|
||||
},
|
||||
}
|
||||
contents, err = files.ExpandContentGlobs(contents, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "glob contents")
|
||||
}
|
||||
for _, c := range contents {
|
||||
log.Debug().Interface("file", c).Msg("added file")
|
||||
}
|
||||
|
||||
// Build package
|
||||
|
||||
info := &nfpm.Info{
|
||||
Name: "orbit-osquery",
|
||||
Version: "0.0.1",
|
||||
Description: "Osquery launcher and autoupdater",
|
||||
Arch: "amd64",
|
||||
Maintainer: "FleetDM Engineers <engineering@fleetdm.com>",
|
||||
Homepage: "https://github.com/fleetdm/orbit",
|
||||
Overridables: nfpm.Overridables{
|
||||
Contents: contents,
|
||||
EmptyFolders: []string{
|
||||
"/var/log/osquery",
|
||||
"/var/log/fleet/orbit",
|
||||
},
|
||||
Scripts: nfpm.Scripts{
|
||||
PostInstall: postInstallPath,
|
||||
},
|
||||
},
|
||||
}
|
||||
pkger := deb.Default
|
||||
filename := pkger.ConventionalFileName(info)
|
||||
|
||||
out, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, constant.DefaultFileMode)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "open output file")
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
if err := deb.Default.Package(info, out); err != nil {
|
||||
return errors.Wrap(err, "write deb package")
|
||||
}
|
||||
log.Info().Str("path", filename).Msg("wrote deb package")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeSystemdUnit(optt packageOptions, rootPath string) error {
|
||||
systemdRoot := filepath.Join(rootPath, "usr", "lib", "systemd", "system")
|
||||
if err := os.MkdirAll(systemdRoot, constant.DefaultDirMode); err != nil {
|
||||
return errors.Wrap(err, "create systemd dir")
|
||||
}
|
||||
if err := ioutil.WriteFile(
|
||||
filepath.Join(systemdRoot, "orbit.service"),
|
||||
[]byte(`
|
||||
[Unit]
|
||||
Description=Fleet Orbit osquery
|
||||
After=network.service syslog.service
|
||||
|
||||
[Service]
|
||||
TimeoutStartSec=0
|
||||
EnvironmentFile=/etc/default/orbit
|
||||
ExecStart=/usr/local/bin/orbit
|
||||
Restart=on-failure
|
||||
KillMode=control-group
|
||||
KillSignal=SIGTERM
|
||||
CPUQuota=20%
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`),
|
||||
constant.DefaultFileMode,
|
||||
); err != nil {
|
||||
return errors.Wrap(err, "write file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var envTemplate = template.Must(template.New("env").Parse(`
|
||||
{{- if .Insecure }}ORBIT_INSECURE=true{{ end }}
|
||||
{{ if .FleetURL }}ORBIT_FLEET_URL={{.FleetURL}}{{ end }}
|
||||
{{ if .EnrollSecret }}ORBIT_ENROLL_SECRET={{.EnrollSecret}}{{ end }}
|
||||
`))
|
||||
|
||||
func writeEnvFile(opt packageOptions, rootPath string) error {
|
||||
envRoot := filepath.Join(rootPath, "etc", "default")
|
||||
if err := os.MkdirAll(envRoot, constant.DefaultDirMode); err != nil {
|
||||
return errors.Wrap(err, "create env dir")
|
||||
}
|
||||
|
||||
var contents bytes.Buffer
|
||||
if err := envTemplate.Execute(&contents, opt); err != nil {
|
||||
return errors.Wrap(err, "execute template")
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(
|
||||
filepath.Join(envRoot, "orbit"),
|
||||
contents.Bytes(),
|
||||
constant.DefaultFileMode,
|
||||
); err != nil {
|
||||
return errors.Wrap(err, "write file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var postInstallTemplate = template.Must(template.New("postinstall").Parse(`
|
||||
#!/bin/sh
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# If we have a systemd, daemon-reload away now
|
||||
if [ -x /bin/systemctl ] && pidof systemd ; then
|
||||
/bin/systemctl daemon-reload 2>/dev/null 2>&1
|
||||
{{ if .StartService -}}
|
||||
/bin/systemctl start orbit.service 2>&1
|
||||
{{- end}}
|
||||
fi
|
||||
`))
|
||||
|
||||
func writePostInstall(opt packageOptions, path string) error {
|
||||
var contents bytes.Buffer
|
||||
if err := postInstallTemplate.Execute(&contents, opt); err != nil {
|
||||
return errors.Wrap(err, "execute template")
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path, contents.Bytes(), constant.DefaultFileMode); err != nil {
|
||||
return errors.Wrap(err, "write file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
235
pkg/packaging/deb.go
Normal file
235
pkg/packaging/deb.go
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
package packaging
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
"github.com/fleetdm/orbit/pkg/constant"
|
||||
"github.com/fleetdm/orbit/pkg/update"
|
||||
"github.com/fleetdm/orbit/pkg/update/filestore"
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/goreleaser/nfpm/v2/deb"
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func BuildDeb(opt Options) error {
|
||||
// Initialize directories
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "orbit-package")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create temp dir")
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
log.Debug().Str("path", tmpDir).Msg("created temp dir")
|
||||
|
||||
filesystemRoot := filepath.Join(tmpDir, "filesystem")
|
||||
if err := os.MkdirAll(filesystemRoot, constant.DefaultDirMode); err != nil {
|
||||
return errors.Wrap(err, "create filesystem dir")
|
||||
}
|
||||
orbitRoot := filepath.Join(filesystemRoot, "var", "lib", "fleet", "orbit")
|
||||
if err := os.MkdirAll(orbitRoot, constant.DefaultDirMode); err != nil {
|
||||
return errors.Wrap(err, "create orbit dir")
|
||||
}
|
||||
|
||||
// Write files
|
||||
|
||||
if err := writeSystemdUnit(opt, filesystemRoot); err != nil {
|
||||
return errors.Wrap(err, "write systemd unit")
|
||||
}
|
||||
|
||||
if err := writeEnvFile(opt, filesystemRoot); err != nil {
|
||||
return errors.Wrap(err, "write env file")
|
||||
}
|
||||
|
||||
postInstallPath := filepath.Join(tmpDir, "postinstall.sh")
|
||||
if err := writePostInstall(opt, postInstallPath); err != nil {
|
||||
return errors.Wrap(err, "write postinstall script")
|
||||
}
|
||||
|
||||
// Initialize autoupdate metadata
|
||||
|
||||
localStore, err := filestore.New(filepath.Join(orbitRoot, "tuf-metadata.json"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create local metadata store")
|
||||
}
|
||||
updateOpt := update.DefaultOptions
|
||||
updateOpt.RootDirectory = orbitRoot
|
||||
updateOpt.ServerURL = "https://tuf.fleetctl.com"
|
||||
updateOpt.LocalStore = localStore
|
||||
updateOpt.Platform = "linux"
|
||||
|
||||
updater, err := update.New(updateOpt)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to init updater")
|
||||
}
|
||||
if err := updater.UpdateMetadata(); err != nil {
|
||||
return errors.Wrap(err, "failed to update metadata")
|
||||
}
|
||||
osquerydPath, err := updater.Get("osqueryd", "stable")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get osqueryd")
|
||||
}
|
||||
log.Debug().Str("path", osquerydPath).Msg("got osqueryd")
|
||||
|
||||
// Pick up all file contents
|
||||
|
||||
contents := files.Contents{
|
||||
&files.Content{
|
||||
Source: filepath.Join(filesystemRoot, "**"),
|
||||
Destination: "/",
|
||||
},
|
||||
&files.Content{
|
||||
Source: "orbit",
|
||||
Destination: "/var/lib/fleet/orbit/orbit",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
Mode: constant.DefaultExecutableMode,
|
||||
},
|
||||
},
|
||||
&files.Content{
|
||||
Source: "/var/lib/fleet/orbit/orbit",
|
||||
Destination: "/usr/local/bin/orbit",
|
||||
Type: "symlink",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
// TODO follow up on nfpm not respecting this
|
||||
// https://github.com/goreleaser/nfpm/issues/286
|
||||
Mode: constant.DefaultExecutableMode | os.ModeSymlink,
|
||||
},
|
||||
},
|
||||
}
|
||||
contents, err = files.ExpandContentGlobs(contents, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "glob contents")
|
||||
}
|
||||
for _, c := range contents {
|
||||
log.Debug().Interface("file", c).Msg("added file")
|
||||
}
|
||||
|
||||
// Build package
|
||||
|
||||
info := &nfpm.Info{
|
||||
Name: "orbit-osquery",
|
||||
Version: "0.0.1",
|
||||
Description: "Osquery launcher and autoupdater",
|
||||
Arch: "amd64",
|
||||
Maintainer: "FleetDM Engineers <engineering@fleetdm.com>",
|
||||
Homepage: "https://github.com/fleetdm/orbit",
|
||||
Overridables: nfpm.Overridables{
|
||||
Contents: contents,
|
||||
EmptyFolders: []string{
|
||||
"/var/log/osquery",
|
||||
"/var/log/fleet/orbit",
|
||||
},
|
||||
Scripts: nfpm.Scripts{
|
||||
PostInstall: postInstallPath,
|
||||
},
|
||||
},
|
||||
}
|
||||
pkger := deb.Default
|
||||
filename := pkger.ConventionalFileName(info)
|
||||
|
||||
out, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, constant.DefaultFileMode)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "open output file")
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
if err := deb.Default.Package(info, out); err != nil {
|
||||
return errors.Wrap(err, "write deb package")
|
||||
}
|
||||
log.Info().Str("path", filename).Msg("wrote deb package")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeSystemdUnit(opt Options, rootPath string) error {
|
||||
systemdRoot := filepath.Join(rootPath, "usr", "lib", "systemd", "system")
|
||||
if err := os.MkdirAll(systemdRoot, constant.DefaultDirMode); err != nil {
|
||||
return errors.Wrap(err, "create systemd dir")
|
||||
}
|
||||
if err := ioutil.WriteFile(
|
||||
filepath.Join(systemdRoot, "orbit.service"),
|
||||
[]byte(`
|
||||
[Unit]
|
||||
Description=Fleet Orbit osquery
|
||||
After=network.service syslog.service
|
||||
|
||||
[Service]
|
||||
TimeoutStartSec=0
|
||||
EnvironmentFile=/etc/default/orbit
|
||||
ExecStart=/usr/local/bin/orbit
|
||||
Restart=on-failure
|
||||
KillMode=control-group
|
||||
KillSignal=SIGTERM
|
||||
CPUQuota=20%
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`),
|
||||
constant.DefaultFileMode,
|
||||
); err != nil {
|
||||
return errors.Wrap(err, "write file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var envTemplate = template.Must(template.New("env").Parse(`
|
||||
{{- if .Insecure }}ORBIT_INSECURE=true{{ end }}
|
||||
{{ if .FleetURL }}ORBIT_FLEET_URL={{.FleetURL}}{{ end }}
|
||||
{{ if .EnrollSecret }}ORBIT_ENROLL_SECRET={{.EnrollSecret}}{{ end }}
|
||||
`))
|
||||
|
||||
func writeEnvFile(opt Options, rootPath string) error {
|
||||
envRoot := filepath.Join(rootPath, "etc", "default")
|
||||
if err := os.MkdirAll(envRoot, constant.DefaultDirMode); err != nil {
|
||||
return errors.Wrap(err, "create env dir")
|
||||
}
|
||||
|
||||
var contents bytes.Buffer
|
||||
if err := envTemplate.Execute(&contents, opt); err != nil {
|
||||
return errors.Wrap(err, "execute template")
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(
|
||||
filepath.Join(envRoot, "orbit"),
|
||||
contents.Bytes(),
|
||||
constant.DefaultFileMode,
|
||||
); err != nil {
|
||||
return errors.Wrap(err, "write file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var postInstallTemplate = template.Must(template.New("postinstall").Parse(`
|
||||
#!/bin/sh
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# If we have a systemd, daemon-reload away now
|
||||
if [ -x /bin/systemctl ] && pidof systemd ; then
|
||||
/bin/systemctl daemon-reload 2>/dev/null 2>&1
|
||||
{{ if .StartService -}}
|
||||
/bin/systemctl start orbit.service 2>&1
|
||||
{{- end}}
|
||||
fi
|
||||
`))
|
||||
|
||||
func writePostInstall(opt Options, path string) error {
|
||||
var contents bytes.Buffer
|
||||
if err := postInstallTemplate.Execute(&contents, opt); err != nil {
|
||||
return errors.Wrap(err, "execute template")
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path, contents.Bytes(), constant.DefaultFileMode); err != nil {
|
||||
return errors.Wrap(err, "write file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
16
pkg/packaging/packaging.go
Normal file
16
pkg/packaging/packaging.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// package packaging provides tools for buildin Orbit installation packages.
|
||||
package packaging
|
||||
|
||||
// Options are the configurable options provided for the package.
|
||||
type Options struct {
|
||||
// FleetURL is the URL to the Fleet server.
|
||||
FleetURL string
|
||||
// EnrollSecret is the enroll secret used to authenticate to the Fleet
|
||||
// server.
|
||||
EnrollSecret string
|
||||
// StartService is a boolean indicating whether to start a system-specific
|
||||
// background service.
|
||||
StartService bool
|
||||
// Insecure enables insecure TLS connections for the generated package.
|
||||
Insecure bool
|
||||
}
|
||||
Loading…
Reference in a new issue