/
slo.go
125 lines (103 loc) · 3.36 KB
/
slo.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
package slo
import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
w "github.com/ibmjstart/cf-object-storage/writer"
sg "github.com/ibmjstart/swiftlygo"
"github.com/ibmjstart/swiftlygo/auth"
)
// argVal holds the parsed argument values.
type argVal struct {
SloContainer string
SloName string
source string
flagVals *flagVal
}
// flagVal holds the flag values.
type flagVal struct {
onlyMissingFlag bool
outputFileFlag string
chunkSizeFlag int
numThreadsFlag int
}
// parseArgs parses the arguments provided to make-slo.
func parseArgs(args []string) (*argVal, error) {
sloContainer := args[0]
sloName := args[1]
source := args[2]
flagSet := flag.NewFlagSet("flagSet", flag.ContinueOnError)
// Define flags and set defaults
missing := flagSet.Bool("m", false, "Only upload missing chunks")
output := flagSet.String("o", "", "Destination for log data")
chunkSize := flagSet.Int("s", 1*1000*1000*1000, "Chunk size, in bytes (defaults to create 1GB chunks)")
threads := flagSet.Int("t", runtime.NumCPU(), "Maximum number of uploader threads (defaults to the available number of CPUs")
// Parse optional flags if they have been provided
if len(args) > 3 {
err := flagSet.Parse(args[3:])
if err != nil {
return nil, fmt.Errorf("Failed to parse flags: %s", err)
}
}
flagVals := flagVal{
onlyMissingFlag: bool(*missing),
outputFileFlag: string(*output),
chunkSizeFlag: int(*chunkSize),
numThreadsFlag: int(*threads),
}
argVals := argVal{
SloContainer: sloContainer,
SloName: sloName,
source: source,
flagVals: &flagVals,
}
return &argVals, nil
}
// MakeSlo uploads the given file as an SLO to Object Storage.
func MakeSlo(dest auth.Destination, writer *w.ConsoleWriter, args []string) (string, error) {
writer.SetCurrentStage("Preparing SLO")
argVals, err := parseArgs(args[3:])
// Verify source file exists
file, err := os.Open(argVals.source)
if err != nil {
return "", fmt.Errorf("Failed to open source file: %s", err)
}
defer file.Close()
fileStats, err := file.Stat()
if err != nil {
return "", fmt.Errorf("Failed to obtain file stats: %s", err)
}
if int(fileStats.Size()) < argVals.flagVals.chunkSizeFlag {
argVals.flagVals.chunkSizeFlag = int(fileStats.Size())
}
writer.SetCurrentStage("Uploading SLO")
var output io.Writer
if argVals.flagVals.outputFileFlag == "" {
output = ioutil.Discard
} else {
// Verify output file exists and create it if it does not
output, err = os.OpenFile(argVals.flagVals.outputFileFlag, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
defer file.Close()
if err != nil {
return "", fmt.Errorf("Failed to open output file: %s", err)
}
}
// Create SLO uploader without output file
uploader, err := sg.NewSloUploader(dest, uint(argVals.flagVals.chunkSizeFlag),
argVals.SloContainer, argVals.SloName, file, uint(argVals.flagVals.numThreadsFlag),
argVals.flagVals.onlyMissingFlag, output)
if err != nil {
return "", fmt.Errorf("Failed to create SLO uploader: %s", err)
}
// Provide the console writer with upload status
writer.SetStatus(uploader.Status)
// Upload SLO
err = uploader.Upload()
if err != nil {
return "", fmt.Errorf("Failed to upload SLO: %s", err)
}
return fmt.Sprintf("\r%s%s\n%s\nSuccessfully created SLO %s in container %s\n", w.ClearLine, w.Green("OK"), w.ClearLine, w.Cyan(argVals.SloName), w.Cyan(argVals.SloContainer)), nil
}