forked from purpleidea/mgmt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
deploy.go
154 lines (136 loc) · 4.44 KB
/
deploy.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
// Mgmt
// Copyright (C) 2013-2018+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package lib
import (
"fmt"
"log"
"os"
"github.com/purpleidea/mgmt/etcd"
etcdfs "github.com/purpleidea/mgmt/etcd/fs"
"github.com/purpleidea/mgmt/gapi"
// these imports are so that GAPIs register themselves in init()
_ "github.com/purpleidea/mgmt/lang"
_ "github.com/purpleidea/mgmt/puppet"
_ "github.com/purpleidea/mgmt/yamlgraph"
"github.com/google/uuid"
errwrap "github.com/pkg/errors"
"github.com/urfave/cli"
git "gopkg.in/src-d/go-git.v4"
)
const (
// MetadataPrefix is the etcd prefix where all our fs superblocks live.
MetadataPrefix = etcd.NS + "/fs"
// StoragePrefix is the etcd prefix where all our fs data lives.
StoragePrefix = etcd.NS + "/storage"
)
// deploy is the cli target to manage deploys to our cluster.
func deploy(c *cli.Context, name string, gapiObj gapi.GAPI) error {
program, version := c.App.Name, c.App.Version
var flags Flags
if val, exists := c.App.Metadata["flags"]; exists {
if f, ok := val.(Flags); ok {
flags = f
}
}
hello(program, version, flags) // say hello!
var hash, pHash string
if !c.GlobalBool("no-git") {
wd, err := os.Getwd()
if err != nil {
return errwrap.Wrapf(err, "could not get current working directory")
}
repo, err := git.PlainOpen(wd)
if err != nil {
return errwrap.Wrapf(err, "could not open git repo")
}
head, err := repo.Head()
if err != nil {
return errwrap.Wrapf(err, "could not read git HEAD")
}
hash = head.Hash().String() // current commit id
log.Printf("Deploy: Hash: %s", hash)
lo := &git.LogOptions{
From: head.Hash(),
}
commits, err := repo.Log(lo)
if err != nil {
return errwrap.Wrapf(err, "could not read git log")
}
if _, err := commits.Next(); err != nil { // skip over HEAD
return errwrap.Wrapf(err, "could not read HEAD in git log") // weird!
}
commit, err := commits.Next()
if err == nil { // errors are okay, we might be empty
pHash = commit.Hash.String() // previous commit id
}
log.Printf("Deploy: Previous deploy hash: %s", pHash)
if c.GlobalBool("force") {
pHash = "" // don't check this :(
}
if hash == "" {
return errwrap.Wrapf(err, "could not get git deploy hash")
}
}
uniqueid := uuid.New() // panic's if it can't generate one :P
etcdClient := &etcd.ClientEtcd{
Seeds: c.GlobalStringSlice("seeds"), // endpoints
}
if err := etcdClient.Connect(); err != nil {
return errwrap.Wrapf(err, "client connection error")
}
defer etcdClient.Destroy()
// TODO: this was all implemented super inefficiently, fix up for perf!
deploys, err := etcd.GetDeploys(etcdClient) // get previous deploys
if err != nil {
return errwrap.Wrapf(err, "error getting previous deploys")
}
// find the latest id
var max uint64
for i := range deploys {
if i > max {
max = i
}
}
var id = max + 1 // next id
log.Printf("Deploy: Previous deploy id: %d", max)
etcdFs := &etcdfs.Fs{
Client: etcdClient.GetClient(),
// TODO: using a uuid is meant as a temporary measure, i hate them
Metadata: MetadataPrefix + fmt.Sprintf("/deploy/%d-%s", id, uniqueid),
DataPrefix: StoragePrefix,
}
deploy, err := gapiObj.Cli(c, etcdFs)
if err != nil {
return errwrap.Wrapf(err, "cli parse error")
}
if deploy == nil { // not used
return fmt.Errorf("not enough information specified")
}
// redundant
deploy.Noop = c.GlobalBool("noop")
deploy.Sema = c.GlobalInt("sema")
str, err := deploy.ToB64()
if err != nil {
return errwrap.Wrapf(err, "encoding error")
}
// this nominally checks the previous git hash matches our expectation
if err := etcd.AddDeploy(etcdClient, id, hash, pHash, &str); err != nil {
return errwrap.Wrapf(err, "could not create deploy id `%d`", id)
}
log.Printf("Deploy: Success, id: %d", id)
return nil
}