-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
handler.go
159 lines (130 loc) · 4.37 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package install
import (
"fmt"
"os"
"path/filepath"
log "github.com/sirupsen/logrus"
"github.com/slimtoolkit/go-update"
"github.com/mintoolkit/mint/pkg/util/errutil"
"github.com/mintoolkit/mint/pkg/util/fsutil"
vinfo "github.com/mintoolkit/mint/pkg/version"
)
const (
dockerCLIPluginDirSuffx = "/.docker/cli-plugins"
masterAppName = "mint"
sensorAppName = "mint-sensor"
binDirName = "/usr/local/bin"
)
// OnCommand implements the 'install' command
func OnCommand(
doDebug bool,
statePath string,
archiveState string,
inContainer bool,
isDSImage bool,
binDir bool,
dockerCLIPlugin bool) {
logger := log.WithFields(log.Fields{"app": "mint", "cmd": "install"})
appPath, err := os.Executable()
errutil.FailOn(err)
appDirPath := filepath.Dir(appPath)
if binDir {
err := installToBinDir(logger, statePath, inContainer, isDSImage, appDirPath)
if err != nil {
fmt.Printf("mint[install]: info=status message='error installing to bin dir'\n")
fmt.Printf("mint[install]: state=exited version=%s\n", vinfo.Current())
return
}
fmt.Printf("mint[install]: state=bin.dir.installed\n")
//use the path from the bin dir, so installing docker CLI plugin symlinks to the right binaries
appDirPath = binDirName
}
if dockerCLIPlugin {
//create a symlink
err := installDockerCLIPlugin(logger, statePath, inContainer, isDSImage, appDirPath)
if err != nil {
fmt.Printf("mint[install]: info=status message='error installing as Docker CLI plugin'\n")
fmt.Printf("mint[install]: state=exited version=%s\n", vinfo.Current())
return
}
fmt.Printf("mint[install]: state=docker.cli.plugin.installed\n")
}
}
func installToBinDir(logger *log.Entry, statePath string, inContainer, isDSImage bool, appDirPath string) error {
if err := installRelease(logger, appDirPath, statePath, binDirName); err != nil {
logger.Debugf("installToBinDir error: %v", err)
return err
}
return nil
}
func symlinkBinaries(logger *log.Entry, appRootPath, symlinkRootPath string) error {
symlinkMasterAppPath := filepath.Join(symlinkRootPath, masterAppName)
symlinkSensorAppPath := filepath.Join(symlinkRootPath, sensorAppName)
targetSensorAppPath := filepath.Join(appRootPath, sensorAppName)
targetMasterAppPath := filepath.Join(appRootPath, masterAppName)
//todo:
//should not symlink the sensor because Docker CLI will treat it as an invalid plugin
//need to improve sensor bin discovery from master app symlink
err := os.Symlink(targetSensorAppPath, symlinkSensorAppPath)
if err != nil {
return err
}
err = os.Symlink(targetMasterAppPath, symlinkMasterAppPath)
if err != nil {
return err
}
return nil
}
func installDockerCLIPlugin(logger *log.Entry, statePath string, inContainer, isDSImage bool, appDirPath string) error {
hd, _ := os.UserHomeDir()
dockerCLIPluginDir := filepath.Join(hd, dockerCLIPluginDirSuffx)
if !fsutil.Exists(dockerCLIPluginDir) {
var dirMode os.FileMode = 0755
err := os.MkdirAll(dockerCLIPluginDir, dirMode)
if err != nil {
return err
}
}
if err := symlinkBinaries(logger, appDirPath, dockerCLIPluginDir); err != nil {
logger.Debugf("installDockerCLIPlugin error: %v", err)
return err
}
return nil
}
func installRelease(logger *log.Entry, appRootPath, statePath, targetRootPath string) error {
targetMasterAppPath := filepath.Join(targetRootPath, masterAppName)
targetSensorAppPath := filepath.Join(targetRootPath, sensorAppName)
srcSensorAppPath := filepath.Join(appRootPath, sensorAppName)
srcMasterAppPath := filepath.Join(appRootPath, masterAppName)
err := updateFile(logger, srcSensorAppPath, targetSensorAppPath)
if err != nil {
return err
}
//will copy the sensor to the state dir if DS is installed in a bad non-shared location on Macs
fsutil.PreparePostUpdateStateDir(statePath)
err = updateFile(logger, srcMasterAppPath, targetMasterAppPath)
if err != nil {
return err
}
return nil
}
// copied from updater
func updateFile(logger *log.Entry, sourcePath, targetPath string) error {
file, err := os.Open(sourcePath)
if err != nil {
return err
}
defer file.Close()
options := update.Options{}
if targetPath != "" {
options.TargetPath = targetPath
}
err = update.Apply(file, options)
if err != nil {
if rerr := update.RollbackError(err); rerr != nil {
logger.Debugf("install.updateFile(%s,%s): Failed to rollback from bad update: %v",
sourcePath, targetPath, rerr)
}
}
return err
}