-
Notifications
You must be signed in to change notification settings - Fork 477
/
commands.go
113 lines (97 loc) · 4.48 KB
/
commands.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
/*******************************************************************************
* Copyright 2019 Dell Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*******************************************************************************/
package executor
import (
"encoding/json"
"fmt"
"strings"
"github.com/edgexfoundry/edgex-go/internal/system"
)
const inspect = "inspect"
// messageExecutorCommandFailed returns a text error message and exists to support unit testing.
func messageExecutorCommandFailed(operationPrefix string, result string, errorMessage string) string {
return fmt.Sprintf("%s: %s (%s)", operationPrefix, errorMessage, strings.Replace(result, "\n", " ", -1))
}
// messageExecutorInspectFailed returns a text error message and exists to support unit testing.
func messageExecutorInspectFailed(operationPrefix string, errorMessage string) string {
return fmt.Sprintf("%s: %s", operationPrefix, errorMessage)
}
// messageServiceIsNotRunningButShouldBe returns a text error message and exists to support unit testing.
func messageServiceIsNotRunningButShouldBe(operationPrefix string) string {
return fmt.Sprintf("%s: service is not running but should be", operationPrefix)
}
// messageServiceIsRunningButShouldNotBe returns a text error message and exists to support unit testing.
func messageServiceIsRunningButShouldNotBe(operationPrefix string) string {
return fmt.Sprintf("%s: service is running but shouldn't be", operationPrefix)
}
// messageContainerNotFound returns a text error message and exists to support unit testing.
func messageContainerNotFound(serviceName string) string {
return fmt.Sprintf("container %s not found", serviceName)
}
// messageMoreThanOneContainerFound returns a text error message and exists to support unit testing.
func messageMoreThanOneContainerFound(serviceName string) string {
return fmt.Sprintf("multiple containers found with name %s", serviceName)
}
// isContainerRunning delegates service status inspection to the executor and interprets the result to determine and
// return whether a specific service has one and only one running instance.
func isContainerRunning(service string, executor CommandExecutor) (bool, string) {
// check the status of the container using the json format - include all
// containers as the container we want to check may be Exited
stringOutput, err := executor(inspect, service)
if err != nil {
return false, err.Error()
}
var containerStatus []struct {
State struct {
Running bool
}
}
jsonOutput := json.NewDecoder(strings.NewReader(string(stringOutput)))
if err = jsonOutput.Decode(&containerStatus); err != nil {
return false, err.Error()
}
switch {
case len(containerStatus) < 1:
return false, messageContainerNotFound(service)
case len(containerStatus) > 1:
return false, messageMoreThanOneContainerFound(service)
default:
return containerStatus[0].State.Running, ""
}
}
// executeACommand handles start/stop/restart operation requests by delegating the command to the executor,
// subsequently verifying the state of the service's container is as expected, and returning an appropriate Result
// value.
func executeACommand(
operation string,
service string,
executor CommandExecutor,
operationPrefix string,
shouldBeRunning bool) system.Result {
if output, err := executor(operation, service); err != nil {
return system.Failure(service, operation, executorType, messageExecutorCommandFailed(operationPrefix, string(output), err.Error()))
}
isRunning, errorMessage := isContainerRunning(service, executor)
switch {
case len(errorMessage) > 0:
return system.Failure(service, operation, executorType, messageExecutorInspectFailed(operationPrefix, errorMessage))
case isRunning != shouldBeRunning:
if isRunning {
return system.Failure(service, operation, executorType, messageServiceIsRunningButShouldNotBe(operationPrefix))
}
return system.Failure(service, operation, executorType, messageServiceIsNotRunningButShouldBe(operationPrefix))
default:
return system.Success(service, operation, executorType)
}
}