forked from openshift/installer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
exec.go
126 lines (107 loc) · 3.01 KB
/
exec.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
// Package exec is glue between the vendored terraform codebase and installer.
package exec
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/signal"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/logutils"
"github.com/hashicorp/terraform/command"
"github.com/hashicorp/terraform/helper/logging"
"github.com/mitchellh/cli"
)
type cmdFunc func(command.Meta) cli.Command
var commands = map[string]cmdFunc{
"apply": func(meta command.Meta) cli.Command {
return &command.ApplyCommand{Meta: meta}
},
"destroy": func(meta command.Meta) cli.Command {
return &command.ApplyCommand{Meta: meta, Destroy: true}
},
"init": func(meta command.Meta) cli.Command {
return &command.InitCommand{Meta: meta}
},
}
func runner(cmd string, dir string, args []string, stdout, stderr io.Writer) int {
lf := ioutil.Discard
if level := logging.LogLevel(); level != "" {
lf = &logutils.LevelFilter{
Levels: logging.ValidLevels,
MinLevel: logutils.LogLevel(level),
Writer: stdout,
}
}
log.SetOutput(lf)
defer log.SetOutput(os.Stderr)
// Make sure we clean up any managed plugins at the end of this
defer plugin.CleanupClients()
sdCh, cancel := makeShutdownCh()
defer cancel()
pluginDirs, err := globalPluginDirs(dir)
if err != nil {
fmt.Fprintf(stderr, "Error discovering plugin directories for Terraform: %v", err)
return 1
}
meta := command.Meta{
Color: false,
GlobalPluginDirs: pluginDirs,
Ui: &cli.BasicUi{
Writer: stdout,
ErrorWriter: stderr,
},
OverrideDataDir: dir,
ShutdownCh: sdCh,
}
f := commands[cmd]
oldStderr := os.Stderr
outR, outW, err := os.Pipe()
if err != nil {
fmt.Fprintf(stderr, "error creating Pipe: %v", err)
return 1
}
os.Stderr = outW
go func() {
scanner := bufio.NewScanner(outR)
for scanner.Scan() {
fmt.Fprintf(lf, "%s\n", scanner.Bytes())
}
}()
defer func() {
outW.Close()
os.Stderr = oldStderr
}()
return f(meta).Run(args)
}
// Apply is wrapper around `terraform apply` subcommand.
func Apply(datadir string, args []string, stdout, stderr io.Writer) int {
return runner("apply", datadir, args, stdout, stderr)
}
// Destroy is wrapper around `terraform destroy` subcommand.
func Destroy(datadir string, args []string, stdout, stderr io.Writer) int {
return runner("destroy", datadir, args, stdout, stderr)
}
// Init is wrapper around `terraform init` subcommand.
func Init(datadir string, args []string, stdout, stderr io.Writer) int {
return runner("init", datadir, args, stdout, stderr)
}
// makeShutdownCh creates an interrupt listener and returns a channel.
// A message will be sent on the channel for every interrupt received.
func makeShutdownCh() (<-chan struct{}, func()) {
resultCh := make(chan struct{})
signalCh := make(chan os.Signal, 4)
handle := []os.Signal{}
handle = append(handle, ignoreSignals...)
handle = append(handle, forwardSignals...)
signal.Notify(signalCh, handle...)
go func() {
for {
<-signalCh
resultCh <- struct{}{}
}
}()
return resultCh, func() { signal.Reset(handle...) }
}