cmd/create: Implement the create command
The Go version supports specifying the name of the new toolbox container as 'toolbox create NAME', in addition to the existing 'toolbox create --container NAME' form. https://github.com/containers/toolbox/pull/318
This commit is contained in:
parent
49146028bc
commit
8f30d71806
3 changed files with 559 additions and 0 deletions
|
@ -17,10 +17,19 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/containers/toolbox/pkg/podman"
|
||||
"github.com/containers/toolbox/pkg/shell"
|
||||
"github.com/containers/toolbox/pkg/utils"
|
||||
systemd "github.com/coreos/go-systemd/v22/dbus"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -30,6 +39,14 @@ var (
|
|||
image string
|
||||
release string
|
||||
}
|
||||
|
||||
createToolboxShMounts = []struct {
|
||||
containerPath string
|
||||
source string
|
||||
}{
|
||||
{"/etc/profile.d/toolbox.sh", "/etc/profile.d/toolbox.sh"},
|
||||
{"/etc/profile.d/toolbox.sh", "/usr/share/profile.d/toolbox.sh"},
|
||||
}
|
||||
)
|
||||
|
||||
var createCmd = &cobra.Command{
|
||||
|
@ -64,6 +81,326 @@ func init() {
|
|||
}
|
||||
|
||||
func create(cmd *cobra.Command, args []string) error {
|
||||
if utils.IsInsideContainer() {
|
||||
if !utils.IsInsideToolboxContainer() {
|
||||
return errors.New("this is not a toolbox container")
|
||||
}
|
||||
|
||||
if _, err := utils.ForwardToHost(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var container string
|
||||
var containerArg string
|
||||
|
||||
if len(args) != 0 {
|
||||
container = args[0]
|
||||
containerArg = "CONTAINER"
|
||||
} else if createFlags.container != "" {
|
||||
container = createFlags.container
|
||||
containerArg = "--container"
|
||||
}
|
||||
|
||||
if container != "" {
|
||||
if _, err := utils.IsContainerNameValid(container); err != nil {
|
||||
var builder strings.Builder
|
||||
fmt.Fprintf(&builder, "invalid argument for '%s'\n", containerArg)
|
||||
fmt.Fprintf(&builder, "Container names must match '%s'\n", utils.ContainerNameRegexp)
|
||||
fmt.Fprintf(&builder, "Run '%s --help' for usage.", executableBase)
|
||||
|
||||
errMsg := builder.String()
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
var release string
|
||||
if createFlags.release != "" {
|
||||
var err error
|
||||
release, err = utils.ParseRelease(createFlags.release)
|
||||
if err != nil {
|
||||
err := utils.CreateErrorInvalidRelease(executableBase)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
container, image, release, err := utils.ResolveContainerAndImageNames(container,
|
||||
createFlags.image,
|
||||
release)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := createContainer(container, image, release, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createContainer(container, image, release string, showCommandToEnter bool) error {
|
||||
if container == "" {
|
||||
panic("container not specified")
|
||||
}
|
||||
|
||||
if image == "" {
|
||||
panic("image not specified")
|
||||
}
|
||||
|
||||
if release == "" {
|
||||
panic("release not specified")
|
||||
}
|
||||
|
||||
enterCommand := getEnterCommand(container, release)
|
||||
|
||||
logrus.Debugf("Checking if container %s already exists", container)
|
||||
|
||||
if exists, _ := podman.ContainerExists(container); exists {
|
||||
var builder strings.Builder
|
||||
fmt.Fprintf(&builder, "container %s already exists\n", container)
|
||||
fmt.Fprintf(&builder, "Enter with: %s\n", enterCommand)
|
||||
fmt.Fprintf(&builder, "Run '%s --help' for usage.", executableBase)
|
||||
|
||||
errMsg := builder.String()
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
pulled, err := pullImage(image, release)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !pulled {
|
||||
return nil
|
||||
}
|
||||
|
||||
imageFull, err := getFullyQualifiedImageName(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toolboxPath := os.Getenv("TOOLBOX_PATH")
|
||||
toolboxPathEnvArg := "TOOLBOX_PATH=" + toolboxPath
|
||||
toolboxPathMountArg := toolboxPath + ":/usr/bin/toolbox:ro"
|
||||
|
||||
sudoGroup, err := utils.GetGroupForSudo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debug("Checking if 'podman create' supports '--ulimit host'")
|
||||
|
||||
var ulimitHost []string
|
||||
|
||||
if podman.CheckVersion("1.5.0") {
|
||||
logrus.Debug("'podman create' supports '--ulimit host'")
|
||||
ulimitHost = []string{"--ulimit", "host"}
|
||||
}
|
||||
|
||||
dbusSystemSocket, err := getDBusSystemSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbusSystemSocketMountArg := dbusSystemSocket + ":" + dbusSystemSocket
|
||||
|
||||
flatpakHelperMonitorPath, err := utils.CallFlatpakSessionHelper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
flatpakHelperMonitorMountArg := flatpakHelperMonitorPath + ":/run/host/monitor"
|
||||
|
||||
homeDirEvaled, err := filepath.EvalSymlinks(currentUser.HomeDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to canonicalize %s", currentUser.HomeDir)
|
||||
}
|
||||
|
||||
logrus.Debugf("%s canonicalized to %s", currentUser.HomeDir, homeDirEvaled)
|
||||
homeDirMountArg := homeDirEvaled + ":" + homeDirEvaled + ":rslave"
|
||||
|
||||
usrMountFlags := "ro"
|
||||
isUsrReadWrite, err := isUsrReadWrite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isUsrReadWrite {
|
||||
usrMountFlags = "rw"
|
||||
}
|
||||
|
||||
usrMountArg := "/usr:/run/host/usr:" + usrMountFlags + ",rslave"
|
||||
|
||||
xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
||||
xdgRuntimeDirMountArg := xdgRuntimeDir + ":" + xdgRuntimeDir
|
||||
|
||||
var kcmSocketMount []string
|
||||
|
||||
kcmSocket, err := getKCMSocket()
|
||||
if err != nil {
|
||||
logrus.Debug(err)
|
||||
}
|
||||
if kcmSocket != "" {
|
||||
kcmSocketMountArg := kcmSocket + ":" + kcmSocket
|
||||
kcmSocketMount = []string{"--volume", kcmSocketMountArg}
|
||||
}
|
||||
|
||||
var mediaLink []string
|
||||
var mediaMount []string
|
||||
|
||||
if utils.PathExists("/media") {
|
||||
logrus.Debug("Checking if /media is a symbolic link to /run/media")
|
||||
|
||||
mediaPath, _ := filepath.EvalSymlinks("/media")
|
||||
if mediaPath == "/run/media" {
|
||||
logrus.Debug("/media is a symbolic link to /run/media")
|
||||
mediaLink = []string{"--media-link"}
|
||||
} else {
|
||||
mediaMount = []string{"--volume", "/media:/media:rslave"}
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debug("Checking if /mnt is a symbolic link to /var/mnt")
|
||||
|
||||
var mntLink []string
|
||||
var mntMount []string
|
||||
|
||||
mntPath, _ := filepath.EvalSymlinks("/mnt")
|
||||
if mntPath == "/var/mnt" {
|
||||
logrus.Debug("/mnt is a symbolic link to /var/mnt")
|
||||
mntLink = []string{"--mnt-link"}
|
||||
} else {
|
||||
mntMount = []string{"--volume", "/mnt:/mnt:rslave"}
|
||||
}
|
||||
|
||||
var runMediaMount []string
|
||||
|
||||
if utils.PathExists("/run/media") {
|
||||
runMediaMount = []string{"--volume", "/run/media:/run/media:rslave"}
|
||||
}
|
||||
|
||||
logrus.Debug("Looking for toolbox.sh")
|
||||
|
||||
var toolboxShMount []string
|
||||
|
||||
for _, mount := range createToolboxShMounts {
|
||||
if utils.PathExists(mount.source) {
|
||||
logrus.Debugf("Found %s", mount.source)
|
||||
|
||||
toolboxShMountArg := mount.source + ":" + mount.containerPath + ":ro"
|
||||
toolboxShMount = []string{"--volume", toolboxShMountArg}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debug("Checking if /home is a symbolic link to /var/home")
|
||||
|
||||
var slashHomeLink []string
|
||||
|
||||
slashHomeEvaled, _ := filepath.EvalSymlinks("/home")
|
||||
if slashHomeEvaled == "/var/home" {
|
||||
logrus.Debug("/home is a symbolic link to /var/home")
|
||||
slashHomeLink = []string{"--home-link"}
|
||||
}
|
||||
|
||||
logLevelString := podman.LogLevel.String()
|
||||
|
||||
userShell := os.Getenv("SHELL")
|
||||
if userShell == "" {
|
||||
return errors.New("failed to get the current user's default shell")
|
||||
}
|
||||
|
||||
entryPoint := []string{
|
||||
"toolbox", "--verbose",
|
||||
"init-container",
|
||||
"--home", currentUser.HomeDir,
|
||||
}
|
||||
|
||||
entryPoint = append(entryPoint, slashHomeLink...)
|
||||
entryPoint = append(entryPoint, mediaLink...)
|
||||
entryPoint = append(entryPoint, mntLink...)
|
||||
|
||||
entryPoint = append(entryPoint, []string{
|
||||
"--monitor-host",
|
||||
"--shell", userShell,
|
||||
"--uid", currentUser.Uid,
|
||||
"--user", currentUser.Username,
|
||||
}...)
|
||||
|
||||
createArgs := []string{
|
||||
"--log-level", logLevelString,
|
||||
"create",
|
||||
"--dns", "none",
|
||||
"--env", toolboxPathEnvArg,
|
||||
"--group-add", sudoGroup,
|
||||
"--hostname", "toolbox",
|
||||
"--ipc", "host",
|
||||
"--label", "com.github.containers.toolbox=true",
|
||||
"--label", "com.github.debarshiray.toolbox=true",
|
||||
"--name", container,
|
||||
"--network", "host",
|
||||
"--no-hosts",
|
||||
"--pid", "host",
|
||||
"--privileged",
|
||||
"--security-opt", "label=disable",
|
||||
}
|
||||
|
||||
createArgs = append(createArgs, ulimitHost...)
|
||||
|
||||
createArgs = append(createArgs, []string{
|
||||
"--userns=keep-id",
|
||||
"--user", "root:root",
|
||||
"--volume", "/etc:/run/host/etc",
|
||||
"--volume", "/dev:/dev:rslave",
|
||||
"--volume", "/run:/run/host/run:rslave",
|
||||
"--volume", "/tmp:/run/host/tmp:rslave",
|
||||
"--volume", "/var:/run/host/var:rslave",
|
||||
"--volume", dbusSystemSocketMountArg,
|
||||
"--volume", flatpakHelperMonitorMountArg,
|
||||
"--volume", homeDirMountArg,
|
||||
"--volume", toolboxPathMountArg,
|
||||
"--volume", usrMountArg,
|
||||
"--volume", xdgRuntimeDirMountArg,
|
||||
}...)
|
||||
|
||||
createArgs = append(createArgs, kcmSocketMount...)
|
||||
createArgs = append(createArgs, mediaMount...)
|
||||
createArgs = append(createArgs, mntMount...)
|
||||
createArgs = append(createArgs, runMediaMount...)
|
||||
createArgs = append(createArgs, toolboxShMount...)
|
||||
|
||||
createArgs = append(createArgs, []string{
|
||||
imageFull,
|
||||
}...)
|
||||
|
||||
createArgs = append(createArgs, entryPoint...)
|
||||
|
||||
logrus.Debugf("Creating container %s:", container)
|
||||
logrus.Debug("podman")
|
||||
for _, arg := range createArgs {
|
||||
logrus.Debugf("%s", arg)
|
||||
}
|
||||
|
||||
s := spinner.New(spinner.CharSets[9], 500*time.Millisecond)
|
||||
|
||||
if logLevel := logrus.GetLevel(); logLevel < logrus.DebugLevel {
|
||||
s.Prefix = fmt.Sprintf("Creating container %s: ", container)
|
||||
s.Writer = os.Stdout
|
||||
s.Start()
|
||||
defer s.Stop()
|
||||
}
|
||||
|
||||
if err := shell.Run("podman", nil, nil, nil, createArgs...); err != nil {
|
||||
return fmt.Errorf("failed to create container %s", container)
|
||||
}
|
||||
|
||||
s.Stop()
|
||||
|
||||
if showCommandToEnter {
|
||||
fmt.Printf("Created container: %s\n", container)
|
||||
fmt.Printf("Enter with: %s\n", enterCommand)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -87,3 +424,211 @@ func createHelp(cmd *cobra.Command, args []string) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
func getDBusSystemSocket() (string, error) {
|
||||
logrus.Debug("Resolving path to the D-Bus system socket")
|
||||
|
||||
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
|
||||
if address == "" {
|
||||
address = "unix:path=/var/run/dbus/system_bus_socket"
|
||||
}
|
||||
|
||||
addressSplit := strings.Split(address, "=")
|
||||
if len(addressSplit) != 2 {
|
||||
return "", errors.New("failed to get the path to the D-Bus system socket")
|
||||
}
|
||||
|
||||
path := addressSplit[1]
|
||||
pathEvaled, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
return "", errors.New("failed to resolve the path to the D-Bus system socket")
|
||||
}
|
||||
|
||||
return pathEvaled, nil
|
||||
}
|
||||
|
||||
func getEnterCommand(container, release string) string {
|
||||
var enterCommand string
|
||||
containerNamePrefixDefaultWithRelease := utils.ContainerNamePrefixDefault + "-" + release
|
||||
|
||||
switch container {
|
||||
case utils.ContainerNameDefault:
|
||||
enterCommand = fmt.Sprintf("%s enter", executableBase)
|
||||
case containerNamePrefixDefaultWithRelease:
|
||||
enterCommand = fmt.Sprintf("%s enter --release %s", executableBase, release)
|
||||
default:
|
||||
enterCommand = fmt.Sprintf("%s enter --container %s", executableBase, container)
|
||||
}
|
||||
|
||||
return enterCommand
|
||||
}
|
||||
|
||||
func getFullyQualifiedImageName(image string) (string, error) {
|
||||
logrus.Debugf("Resolving fully qualified name for image %s", image)
|
||||
|
||||
var imageFull string
|
||||
|
||||
if utils.ImageReferenceHasDomain(image) {
|
||||
imageFull = image
|
||||
} else {
|
||||
info, err := podman.Inspect("image", image)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to inspect image %s", image)
|
||||
}
|
||||
|
||||
if info["RepoTags"] == nil {
|
||||
return "", fmt.Errorf("missing RepoTag for image %s", image)
|
||||
}
|
||||
|
||||
repoTags := info["RepoTags"].([]interface{})
|
||||
if len(repoTags) == 0 {
|
||||
return "", fmt.Errorf("empty RepoTag for image %s", image)
|
||||
}
|
||||
|
||||
imageFull = repoTags[0].(string)
|
||||
}
|
||||
|
||||
logrus.Debugf("Resolved image %s to %s", image, imageFull)
|
||||
|
||||
return imageFull, nil
|
||||
}
|
||||
|
||||
func getKCMSocket() (string, error) {
|
||||
logrus.Debug("Resolving path to the KCM socket")
|
||||
|
||||
connection, err := systemd.NewSystemConnection()
|
||||
if err != nil {
|
||||
return "", errors.New("failed to connect to the D-Bus system instance")
|
||||
}
|
||||
|
||||
defer connection.Close()
|
||||
|
||||
properties, err := connection.GetAllProperties("sssd-kcm.socket")
|
||||
if err != nil {
|
||||
return "", errors.New("failed to get the properties of sssd-kcm.socket")
|
||||
}
|
||||
|
||||
value := properties["Listen"]
|
||||
if value == nil {
|
||||
return "", errors.New("failed to find the Listen property of sssd-kcm.socket")
|
||||
}
|
||||
|
||||
sockets := value.([][]interface{})
|
||||
for _, socket := range sockets {
|
||||
if socket[0] == "Stream" {
|
||||
path := socket[1].(string)
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
continue
|
||||
}
|
||||
|
||||
pathEvaled, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
return pathEvaled, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("failed to find a SOCK_STREAM socket for sssd-kcm.socket")
|
||||
}
|
||||
|
||||
func isUsrReadWrite() (bool, error) {
|
||||
logrus.Debug("Checking if /usr is mounted read-only or read-write")
|
||||
|
||||
mountPoint, err := utils.GetMountPoint("/usr")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get the mount-point of /usr: %s", err)
|
||||
}
|
||||
|
||||
logrus.Debugf("Mount-point of /usr is %s", mountPoint)
|
||||
|
||||
mountFlags, err := utils.GetMountOptions(mountPoint)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get the mount options of %s: %s", mountPoint, err)
|
||||
}
|
||||
|
||||
logrus.Debugf("Mount flags of /usr on the host are %s", mountFlags)
|
||||
|
||||
if !strings.Contains(mountFlags, "ro") {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func pullImage(image, release string) (bool, error) {
|
||||
if _, err := utils.ImageReferenceCanBeID(image); err == nil {
|
||||
logrus.Debugf("Looking for image %s", image)
|
||||
|
||||
if _, err := podman.ImageExists(image); err == nil {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
hasDomain := utils.ImageReferenceHasDomain(image)
|
||||
|
||||
if !hasDomain {
|
||||
imageLocal := "localhost/" + image
|
||||
logrus.Debugf("Looking for image %s", imageLocal)
|
||||
|
||||
if _, err := podman.ImageExists(imageLocal); err == nil {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
var imageFull string
|
||||
|
||||
if hasDomain {
|
||||
imageFull = image
|
||||
} else {
|
||||
imageFull = fmt.Sprintf("registry.fedoraproject.org/f%s/%s", release, image)
|
||||
}
|
||||
|
||||
logrus.Debugf("Looking for image %s", imageFull)
|
||||
|
||||
if _, err := podman.ImageExists(imageFull); err == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
domain := utils.ImageReferenceGetDomain(imageFull)
|
||||
if domain == "" {
|
||||
panicMsg := fmt.Sprintf("failed to get domain from %s", imageFull)
|
||||
panic(panicMsg)
|
||||
}
|
||||
|
||||
promptForDownload := true
|
||||
var shouldPullImage bool
|
||||
|
||||
if rootFlags.assumeYes || domain == "localhost" {
|
||||
promptForDownload = false
|
||||
shouldPullImage = true
|
||||
}
|
||||
|
||||
if promptForDownload {
|
||||
fmt.Println("Image required to create toolbox container.")
|
||||
|
||||
prompt := fmt.Sprintf("Download %s (500MB)? [y/N]:", imageFull)
|
||||
shouldPullImage = utils.AskForConfirmation(prompt)
|
||||
}
|
||||
|
||||
if !shouldPullImage {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
logrus.Debugf("Pulling image %s", imageFull)
|
||||
|
||||
if logLevel := logrus.GetLevel(); logLevel < logrus.DebugLevel {
|
||||
s := spinner.New(spinner.CharSets[9], 500*time.Millisecond)
|
||||
s.Prefix = fmt.Sprintf("Pulling %s: ", imageFull)
|
||||
s.Writer = os.Stdout
|
||||
s.Start()
|
||||
defer s.Stop()
|
||||
}
|
||||
|
||||
if err := podman.Pull(imageFull); err != nil {
|
||||
return false, fmt.Errorf("failed to pull image %s", imageFull)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ go 1.13
|
|||
require (
|
||||
github.com/HarryMichal/go-version v1.0.0
|
||||
github.com/acobaugh/osrelease v0.0.0-20181218015638-a93a0a55a249
|
||||
github.com/briandowns/spinner v1.10.0
|
||||
github.com/coreos/go-systemd/v22 v22.0.0
|
||||
github.com/godbus/dbus/v5 v5.0.3
|
||||
github.com/sirupsen/logrus v1.5.0
|
||||
github.com/spf13/cobra v0.0.6
|
||||
|
|
12
src/go.sum
12
src/go.sum
|
@ -10,18 +10,25 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
|||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/briandowns/spinner v1.10.0 h1:753NIJC2NHmPyVoPVWS+wh9eDx5umqe2U+JgX+KoTag=
|
||||
github.com/briandowns/spinner v1.10.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
|
@ -57,6 +64,10 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
|
@ -120,6 +131,7 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
Loading…
Reference in a new issue