forked from getporter/porter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
credentials.go
183 lines (162 loc) · 5.05 KB
/
credentials.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package porter
import (
"fmt"
"os"
"sort"
"time"
"github.com/deislabs/porter/pkg/context"
"github.com/deislabs/porter/pkg/credentialsgenerator"
"github.com/deislabs/porter/pkg/printer"
dtprinter "github.com/carolynvs/datetime-printer"
credentials "github.com/deislabs/cnab-go/credentials"
"github.com/pkg/errors"
yaml "gopkg.in/yaml.v2"
)
// CredentialsFile represents a CNAB credentials file and corresponding metadata
type CredentialsFile struct {
Name string
Modified time.Time
}
// CredentialsFileList is a slice of CredentialsFiles
type CredentialsFileList []CredentialsFile
func (l CredentialsFileList) Len() int {
return len(l)
}
func (l CredentialsFileList) Swap(i, j int) {
l[i], l[j] = l[j], l[i]
}
func (l CredentialsFileList) Less(i, j int) bool {
return l[i].Modified.Before(l[j].Modified)
}
// fetchCredentials fetches all credentials from the designated credentials dir
func (p *Porter) fetchCredentials() (*CredentialsFileList, error) {
credsDir, err := p.Config.GetCredentialsDir()
if err != nil {
return &CredentialsFileList{}, errors.Wrap(err, "unable to determine credentials directory")
}
credentialsFiles := CredentialsFileList{}
if ok, _ := p.Context.FileSystem.DirExists(credsDir); ok {
p.Context.FileSystem.Walk(credsDir, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
credSet := &credentials.CredentialSet{}
data, err := p.Context.FileSystem.ReadFile(path)
if err != nil {
if p.Debug {
fmt.Fprintf(p.Err, "unable to load credential set from %s: %s\n", path, err)
}
return nil
}
if err = yaml.Unmarshal(data, credSet); err != nil {
if p.Debug {
fmt.Fprintf(p.Err, "unable to unmarshal credential set from file %s: %s\n", info.Name(), err)
}
return nil
}
credentialsFiles = append(credentialsFiles,
CredentialsFile{Name: credSet.Name, Modified: info.ModTime()})
}
return nil
})
sort.Sort(sort.Reverse(credentialsFiles))
}
return &credentialsFiles, nil
}
// ListCredentials lists credentials using the provided printer.PrintOptions
func (p *Porter) ListCredentials(opts printer.PrintOptions) error {
credentialsFiles, err := p.fetchCredentials()
if err != nil {
return errors.Wrap(err, "unable to fetch credentials")
}
switch opts.Format {
case printer.FormatJson:
return printer.PrintJson(p.Out, *credentialsFiles)
case printer.FormatYaml:
return printer.PrintYaml(p.Out, *credentialsFiles)
case printer.FormatTable:
// have every row use the same "now" starting ... NOW!
now := time.Now()
tp := dtprinter.DateTimePrinter{
Now: func() time.Time { return now },
}
printCredRow :=
func(v interface{}) []interface{} {
cr, ok := v.(CredentialsFile)
if !ok {
return nil
}
return []interface{}{cr.Name, tp.Format(cr.Modified)}
}
return printer.PrintTable(p.Out, *credentialsFiles, printCredRow,
"NAME", "MODIFIED")
default:
return fmt.Errorf("invalid format: %s", opts.Format)
}
}
type CredentialOptions struct {
sharedOptions
DryRun bool
Silent bool
}
// Validate prepares for an action and validates the options.
// For example, relative paths are converted to full paths and then checked that
// they exist and are accessible.
func (g *CredentialOptions) Validate(args []string, cxt *context.Context) error {
err := g.validateCredName(args)
if err != nil {
return err
}
err = g.validateBundlePath(cxt)
if err != nil {
return err
}
return nil
}
func (g *CredentialOptions) validateCredName(args []string) error {
if len(args) == 1 {
g.Name = args[0]
} else if len(args) > 1 {
return errors.Errorf("only one positional argument may be specified, the credential name, but multiple were received: %s", args)
}
return nil
}
func (p *Porter) GenerateCredentials(opts CredentialOptions) error {
//TODO make this work for either porter.yaml OR a bundle
bundle, err := p.CNAB.LoadBundle(opts.File, opts.Insecure)
if err != nil {
return err
}
name := opts.Name
if name == "" {
name = bundle.Name
}
genOpts := credentialsgenerator.GenerateOptions{
Name: name,
Credentials: bundle.Credentials,
Silent: opts.Silent,
}
fmt.Fprintf(p.Out, "Generating new credential %s from bundle %s\n", genOpts.Name, bundle.Name)
fmt.Fprintf(p.Out, "==> %d credentials required for bundle %s\n", len(genOpts.Credentials), bundle.Name)
cs, err := credentialsgenerator.GenerateCredentials(genOpts)
if err != nil {
return errors.Wrap(err, "unable to generate credentials")
}
//write the credential out to PORTER_HOME with Porter's Context
data, err := yaml.Marshal(cs)
if err != nil {
return errors.Wrap(err, "unable to generate credentials YAML")
}
if opts.DryRun {
fmt.Fprintf(p.Out, "%v", string(data))
return nil
}
dest, err := p.Config.GetCredentialPath(genOpts.Name)
if err != nil {
return errors.Wrap(err, "unable to determine credentials directory")
}
fmt.Fprintf(p.Out, "Saving credential to %s\n", dest)
err = p.Context.FileSystem.WriteFile(dest, data, 0600)
if err != nil {
return errors.Wrapf(err, "couldn't write credential file %s", dest)
}
return nil
}