Skip to content
This repository was archived by the owner on Nov 5, 2021. It is now read-only.

Commit 80cf0e2

Browse files
committed
Break out separate pkg package
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <[email protected]>
1 parent 98963ae commit 80cf0e2

File tree

3 files changed

+338
-330
lines changed

3 files changed

+338
-330
lines changed

cmd/run.go

+4-328
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,13 @@
44
package cmd
55

66
import (
7-
"context"
8-
"fmt"
9-
"io/ioutil"
10-
"log"
11-
"os"
12-
"strconv"
13-
"strings"
14-
"time"
15-
16-
"github.com/docker/docker/api/types"
17-
"github.com/docker/docker/api/types/filters"
18-
"github.com/docker/docker/api/types/mount"
19-
"github.com/docker/docker/api/types/swarm"
20-
"github.com/docker/docker/client"
21-
7+
jswarm "github.com/alexellis/jaas/pkg/swarm"
8+
jtypes "github.com/alexellis/jaas/pkg/types"
229
"github.com/spf13/cobra"
2310
)
2411

2512
var (
26-
taskRequest TaskRequest
13+
taskRequest jtypes.TaskRequest
2714
verbose bool
2815
)
2916

@@ -57,317 +44,6 @@ var runCmd = &cobra.Command{
5744
}
5845

5946
func runRun(cmd *cobra.Command, args []string) error {
60-
err := runTask(taskRequest)
47+
err := jswarm.RunTask(taskRequest)
6148
return err
6249
}
63-
64-
func validate(taskRequest TaskRequest) error {
65-
if len(taskRequest.Image) == 0 {
66-
return fmt.Errorf("must a valid supply --image")
67-
}
68-
return nil
69-
}
70-
71-
func runTask(taskRequest TaskRequest) error {
72-
if validationErr := validate(taskRequest); validationErr != nil {
73-
return validationErr
74-
}
75-
76-
if verbose {
77-
fmt.Printf("Running.. OK %s\n", taskRequest.Image)
78-
fmt.Printf("Connected to.. OK %s\n", taskRequest.Networks)
79-
fmt.Printf("Constraints: %s\n", taskRequest.Constraints)
80-
fmt.Printf("envVars: %s\n", taskRequest.EnvVars)
81-
fmt.Printf("Secrets: %s\n", taskRequest.Secrets)
82-
}
83-
84-
timeoutVal, parseErr := time.ParseDuration(taskRequest.Timeout)
85-
if parseErr != nil {
86-
return parseErr
87-
}
88-
89-
if verbose {
90-
fmt.Printf("timeout: %s\n", timeoutVal)
91-
}
92-
93-
var c *client.Client
94-
var err error
95-
c, err = client.NewEnvClient()
96-
if err != nil {
97-
98-
return fmt.Errorf("is the Docker Daemon running? Error: %s", err.Error())
99-
}
100-
101-
// Check that experimental mode is enabled on the daemon, fall back to no logging if not
102-
versionInfo, versionErr := c.ServerVersion(context.Background())
103-
if versionErr != nil {
104-
log.Fatal("Is the Docker Daemon running?")
105-
106-
return versionErr
107-
}
108-
109-
if taskRequest.ShowLogs {
110-
apiVersion, parseErr := strconv.ParseFloat(versionInfo.APIVersion, 64)
111-
if parseErr != nil {
112-
apiVersion = 0
113-
}
114-
if apiVersion < 1.29 && versionInfo.Experimental == false {
115-
return fmt.Errorf("experimental daemon or Docker API Version 1.29+ required to display service logs, falling back to no log display")
116-
}
117-
}
118-
119-
spec := makeSpec(taskRequest.Image, taskRequest.EnvVars)
120-
if len(taskRequest.Networks) > 0 {
121-
nets := []swarm.NetworkAttachmentConfig{
122-
swarm.NetworkAttachmentConfig{Target: taskRequest.Networks[0]},
123-
}
124-
spec.Networks = nets
125-
}
126-
127-
createOptions := types.ServiceCreateOptions{}
128-
129-
if len(taskRequest.RegistryAuth) > 0 {
130-
createOptions.EncodedRegistryAuth = taskRequest.RegistryAuth
131-
fmt.Println("Using RegistryAuth")
132-
}
133-
134-
placement := &swarm.Placement{}
135-
if len(taskRequest.Constraints) > 0 {
136-
placement.Constraints = taskRequest.Constraints
137-
spec.TaskTemplate.Placement = placement
138-
}
139-
140-
if len(taskRequest.Command) > 0 {
141-
spec.TaskTemplate.ContainerSpec.Command = strings.Split(taskRequest.Command, " ")
142-
}
143-
144-
if len(taskRequest.EnvFiles) > 0 {
145-
for _, file := range taskRequest.EnvFiles {
146-
envs, err := readEnvs(file)
147-
if err != nil {
148-
fmt.Fprintf(os.Stderr, "%s", err)
149-
os.Exit(1)
150-
}
151-
152-
for _, env := range envs {
153-
spec.TaskTemplate.ContainerSpec.Env = append(spec.TaskTemplate.ContainerSpec.Env, env)
154-
}
155-
}
156-
}
157-
158-
spec.TaskTemplate.ContainerSpec.Mounts = []mount.Mount{}
159-
for _, bindMount := range taskRequest.Mounts {
160-
parts := strings.Split(bindMount, "=")
161-
if len(parts) < 2 || len(parts) > 2 {
162-
fmt.Fprintf(os.Stderr, "Bind-mounts must be specified as: src=dest, i.e. --mount /home/alex/tmp/=/tmp/\n")
163-
os.Exit(1)
164-
}
165-
166-
if len(parts) == 2 {
167-
mountVal := mount.Mount{
168-
Source: parts[0],
169-
Target: parts[1],
170-
}
171-
172-
spec.TaskTemplate.ContainerSpec.Mounts = append(spec.TaskTemplate.ContainerSpec.Mounts, mountVal)
173-
}
174-
}
175-
176-
secretList, err := c.SecretList(context.Background(), types.SecretListOptions{})
177-
178-
spec.TaskTemplate.ContainerSpec.Secrets = []*swarm.SecretReference{}
179-
for _, serviceSecret := range taskRequest.Secrets {
180-
var secretID string
181-
for _, s := range secretList {
182-
if serviceSecret == s.Spec.Annotations.Name {
183-
secretID = s.ID
184-
break
185-
}
186-
}
187-
if secretID == "" {
188-
fmt.Fprintf(os.Stderr, "No existing secret has name that matches %s\n", serviceSecret)
189-
os.Exit(1)
190-
}
191-
192-
secretVal := swarm.SecretReference{
193-
File: &swarm.SecretReferenceFileTarget{
194-
Name: serviceSecret,
195-
UID: "0",
196-
GID: "0",
197-
Mode: os.FileMode(0444), // File can be read by any user inside the container
198-
},
199-
SecretName: serviceSecret,
200-
SecretID: secretID,
201-
}
202-
203-
spec.TaskTemplate.ContainerSpec.Secrets = append(spec.TaskTemplate.ContainerSpec.Secrets, &secretVal)
204-
}
205-
206-
createResponse, _ := c.ServiceCreate(context.Background(), spec, createOptions)
207-
opts := types.ServiceInspectOptions{InsertDefaults: true}
208-
209-
service, _, _ := c.ServiceInspectWithRaw(context.Background(), createResponse.ID, opts)
210-
fmt.Printf("Service created: %s (%s)\n", service.Spec.Name, createResponse.ID)
211-
212-
taskExitCode := pollTask(c, createResponse.ID, timeoutVal, taskRequest.ShowLogs, taskRequest.RemoveService)
213-
os.Exit(taskExitCode)
214-
return nil
215-
}
216-
217-
func makeSpec(image string, envVars []string) swarm.ServiceSpec {
218-
max := uint64(1)
219-
220-
spec := swarm.ServiceSpec{
221-
TaskTemplate: swarm.TaskSpec{
222-
RestartPolicy: &swarm.RestartPolicy{
223-
MaxAttempts: &max,
224-
Condition: swarm.RestartPolicyConditionNone,
225-
},
226-
ContainerSpec: &swarm.ContainerSpec{
227-
Image: image,
228-
Env: envVars,
229-
},
230-
},
231-
}
232-
return spec
233-
}
234-
235-
func readEnvs(file string) ([]string, error) {
236-
var err error
237-
var envs []string
238-
239-
data, readErr := ioutil.ReadFile(file)
240-
if readErr != nil {
241-
return envs, readErr
242-
}
243-
244-
lines := strings.Split(string(data), "\n")
245-
for n, line := range lines {
246-
if len(line) > 0 {
247-
if strings.Index(line, "=") == -1 {
248-
err = fmt.Errorf("no seperator found in line %d of env-file %s", n, file)
249-
break
250-
}
251-
envs = append(envs, line)
252-
}
253-
}
254-
return envs, err
255-
}
256-
257-
const swarmError = -999
258-
const timeoutError = -998
259-
260-
func pollTask(c *client.Client, id string, timeout time.Duration, showlogs, removeService bool) int {
261-
svcFilters := filters.NewArgs()
262-
svcFilters.Add("id", id)
263-
264-
exitCode := swarmError
265-
266-
opts := types.ServiceListOptions{
267-
Filters: svcFilters,
268-
}
269-
270-
list, _ := c.ServiceList(context.Background(), opts)
271-
for _, item := range list {
272-
start := time.Now()
273-
end := start.Add(timeout)
274-
275-
fmt.Println("ID: ", item.ID, " Update at: ", item.UpdatedAt)
276-
for {
277-
time.Sleep(500 * time.Millisecond)
278-
279-
taskExitCode, found := showTasks(c, item.ID, showlogs, removeService)
280-
if found {
281-
exitCode = taskExitCode
282-
break
283-
}
284-
now := time.Now()
285-
if now.After(end) {
286-
fmt.Printf("Timing out after %s.", timeout.String())
287-
return timeoutError
288-
}
289-
}
290-
}
291-
292-
return exitCode
293-
}
294-
295-
func showTasks(c *client.Client, id string, showLogs, removeService bool) (int, bool) {
296-
filters1 := filters.NewArgs()
297-
filters1.Add("service", id)
298-
299-
tasks, _ := c.TaskList(context.Background(), types.TaskListOptions{
300-
Filters: filters1,
301-
})
302-
303-
exitCode := 1
304-
var done bool
305-
stopStates := []swarm.TaskState{
306-
swarm.TaskStateComplete,
307-
swarm.TaskStateFailed,
308-
swarm.TaskStateRejected,
309-
}
310-
311-
for _, task := range tasks {
312-
313-
stop := false
314-
for _, stopState := range stopStates {
315-
if task.Status.State == stopState {
316-
stop = true
317-
break
318-
}
319-
}
320-
321-
if stop {
322-
fmt.Printf("\n\n")
323-
fmt.Printf("Exit code: %d\n", task.Status.ContainerStatus.ExitCode)
324-
fmt.Printf("State: %s\n", task.Status.State)
325-
fmt.Printf("\n\n")
326-
327-
exitCode = task.Status.ContainerStatus.ExitCode
328-
329-
if exitCode == 0 && task.Status.State == swarm.TaskStateRejected {
330-
exitCode = 255 // force non-zero exit for task rejected
331-
}
332-
333-
if showLogs {
334-
fmt.Println("Printing service logs")
335-
}
336-
337-
if showLogs {
338-
logRequest, err := c.ServiceLogs(context.Background(), id, types.ContainerLogsOptions{
339-
Follow: false,
340-
ShowStdout: true,
341-
ShowStderr: true,
342-
Timestamps: true,
343-
Details: false,
344-
Tail: "all",
345-
})
346-
347-
if err != nil {
348-
fmt.Printf("Unable to pull service logs.\nError: %s\n", err)
349-
} else {
350-
defer logRequest.Close()
351-
352-
// , ShowStderr: true, ShowStdout: true})
353-
res, _ := ioutil.ReadAll(logRequest)
354-
355-
fmt.Println(string(res[:]))
356-
}
357-
}
358-
359-
if removeService {
360-
fmt.Println("Removing service...")
361-
if err := c.ServiceRemove(context.Background(), id); err != nil {
362-
fmt.Fprintln(os.Stderr, err)
363-
}
364-
}
365-
366-
done = true
367-
break
368-
} else {
369-
fmt.Printf(".")
370-
}
371-
}
372-
return exitCode, done
373-
}

0 commit comments

Comments
 (0)