Skip to content

Commit

Permalink
Cli improvements (#587)
Browse files Browse the repository at this point in the history
* .

Signed-off-by: Alan Murtagh <alan.murtagh@vorteil.io>

* Fixes some bugs and adds some cli features.

Signed-off-by: Alan Murtagh <alan.murtagh@vorteil.io>

* 409 conflict fix

Signed-off-by: Alan Murtagh <alan.murtagh@vorteil.io>
  • Loading branch information
alankm committed May 30, 2022
1 parent aad2ed0 commit b1dc183
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 13 deletions.
15 changes: 6 additions & 9 deletions cmd/exec/main.go
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/spf13/viper"
)

const DefaultConfigName = ".direktiv.conf"
const DefaultConfigName = ".direktiv.yaml"

// Flags
var (
Expand All @@ -44,7 +44,7 @@ var (
localAbsPath string
urlPrefix string
urlWorkflow string
urlUpdateWorkflow string
// urlUpdateWorkflow string
)

func main() {
Expand Down Expand Up @@ -161,7 +161,6 @@ func cmdPrepareWorkflow(wfPath string) {

urlPrefix = fmt.Sprintf("%s/api/namespaces/%s", addr, namespace)
urlWorkflow = fmt.Sprintf("%s/tree/%s", urlPrefix, strings.TrimPrefix(path, "/"))
urlUpdateWorkflow = fmt.Sprintf("%s?op=update-workflow", urlWorkflow)
}

var rootCmd = &cobra.Command{
Expand Down Expand Up @@ -207,7 +206,7 @@ Will update the helloworld workflow and set the remote workflow variable 'data.j
if err != nil {
return err
}
if strings.HasSuffix(localPath, ".yaml") {
if (strings.HasSuffix(localPath, ".yaml") || strings.HasSuffix(localPath, ".yml")) && !(strings.Contains(localPath, ".yaml.") || strings.Contains(localPath, ".yml.")) {
pathsToUpdate = append(pathsToUpdate, localPath)
}
return nil
Expand All @@ -222,12 +221,10 @@ Will update the helloworld workflow and set the remote workflow variable 'data.j

cmd.PrintErrf("Found %v Local Workflow/s to update\n", len(pathsToUpdate))
for i, localPath := range pathsToUpdate {
path = filepath.ToSlash(strings.TrimSuffix(strings.TrimPrefix(localPath, filepath.Dir(configPath)), ".yaml"))
urlWorkflow = fmt.Sprintf("%s/tree/%s", urlPrefix, strings.TrimPrefix(path, "/"))
urlUpdateWorkflow = fmt.Sprintf("%s?op=update-workflow", urlWorkflow)
path = filepath.ToSlash(strings.TrimSuffix(strings.TrimSuffix(strings.TrimPrefix(localPath, filepath.Dir(configPath)), ".yaml"), ".yml"))

cmd.PrintErrf("[%v/%v] Updating Namespace: '%s' Workflow: '%s'\n", i+1, len(pathsToUpdate), namespace, path)
err = updateRemoteWorkflow(urlUpdateWorkflow, localPath)
err = updateRemoteWorkflow(path, localPath)
if err != nil {
log.Fatalf("Failed to update remote workflow: %v\n", err)
}
Expand Down Expand Up @@ -278,7 +275,7 @@ Will update the helloworld workflow and set the remote workflow variable 'data.j
instanceStatus := "pending"

cmd.PrintErrf("Updating Namespace: '%s' Workflow: '%s'\n", namespace, path)
err := updateRemoteWorkflow(urlUpdateWorkflow, localAbsPath)
err := updateRemoteWorkflow(path, localAbsPath)
if err != nil {
log.Fatalf("Failed to update remote workflow: %v\n", err)
}
Expand Down
217 changes: 213 additions & 4 deletions cmd/exec/operations.go
Expand Up @@ -9,6 +9,8 @@ import (
"net/http"
"path/filepath"
"strings"

"github.com/direktiv/direktiv/pkg/util"
)

func addAuthHeaders(req *http.Request) {
Expand Down Expand Up @@ -72,16 +74,217 @@ func getLocalWorkflowVariables(absPath string) ([]string, error) {
return varFiles, nil
}

func updateRemoteWorkflow(url string, localPath string) error {
wfData, err := safeLoadFile(localPath)
func recurseMkdirParent(path string) error {

dir, _ := filepath.Split(path)
if dir == "" || dir == "/" {
return nil
}

dir = strings.TrimSuffix(dir, "/")

err := recurseMkdirParent(dir)
if err != nil {
return err
}

urlDir := fmt.Sprintf("%s/tree/%s", urlPrefix, strings.Trim(dir, "/"))
urlMkdir := fmt.Sprintf("%s?op=create-directory", urlDir)

req, err := http.NewRequest(
http.MethodPut,
urlMkdir,
nil,
)
if err != nil {
return fmt.Errorf("failed to create request file: %v", err)
}

addAuthHeaders(req)

resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("failed to send request: %v", err)
}

if resp.StatusCode != 200 && resp.StatusCode != http.StatusConflict {
errBody, err := ioutil.ReadAll(resp.Body)
if err == nil {
return fmt.Errorf("failed to create parent, server responsed with %s\n------DUMPING ERROR BODY ------\n%s", resp.Status, string(errBody))
}

return fmt.Errorf("failed to create parent, server responsed with %s\n------DUMPING ERROR BODY ------\nCould read response body", resp.Status)
}

return err

}

func setWritable(path string) error {

dir, _ := filepath.Split(path)
dir = strings.TrimSuffix(dir, "/")

urlWorkflow = fmt.Sprintf("%s/tree/%s", urlPrefix, strings.TrimPrefix(path, "/"))
urlGetNode := fmt.Sprintf("%s", urlWorkflow)

req, err := http.NewRequest(
http.MethodGet,
urlGetNode,
nil,
)
if err != nil {
return fmt.Errorf("failed to create request file: %v", err)
}

addAuthHeaders(req)

resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("failed to send request: %v", err)
}

if resp.StatusCode != 200 {
if resp.StatusCode == http.StatusNotFound {
err = setWritable(dir)
if err != nil {
return err
}
return nil
}

errBody, err := ioutil.ReadAll(resp.Body)
if err == nil {
return fmt.Errorf("failed to get node information, server responsed with %s\n------DUMPING ERROR BODY ------\n%s", resp.Status, string(errBody))
}

return fmt.Errorf("failed to get node information, server responsed with %s\n------DUMPING ERROR BODY ------\nCould read response body", resp.Status)
}

data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response: %v", err)
}

m := make(map[string]interface{})
err = json.Unmarshal(data, &m)
if err != nil {
return fmt.Errorf("failed to unmarshal response: %v", err)
}

x, exists := m["node"]
if !exists {
return fmt.Errorf("unexpected response: %v", string(data))
}

m2, ok := x.(map[string]interface{})
if !ok {
return fmt.Errorf("unexpected response: %v", string(data))
}

x, exists = m2["readOnly"]
if !exists {
return fmt.Errorf("unexpected response: %v", string(data))
}

ro, ok := x.(bool)
if !ok {
return fmt.Errorf("unexpected response: %v", string(data))
}

if ro == false {
return nil
}

x, exists = m2["expandedType"]
if !exists {
return fmt.Errorf("unexpected response: %v", string(data))
}

et, ok := x.(string)
if !ok {
return fmt.Errorf("unexpected response: %v", string(data))
}

switch et {
case util.InodeTypeGit:

urlLockMirror := fmt.Sprintf("%s?op=lock-mirror", urlWorkflow)

req, err := http.NewRequest(
http.MethodPost,
urlLockMirror,
nil,
)
if err != nil {
return fmt.Errorf("failed to create request file: %v", err)
}

addAuthHeaders(req)

resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("failed to send request: %v", err)
}

if resp.StatusCode != 200 {
errBody, err := ioutil.ReadAll(resp.Body)
if err == nil {
return fmt.Errorf("failed to get node information, server responsed with %s\n------DUMPING ERROR BODY ------\n%s", resp.Status, string(errBody))
}

return fmt.Errorf("failed to get node information, server responsed with %s\n------DUMPING ERROR BODY ------\nCould read response body", resp.Status)
}

default:

err = setWritable(dir)
if err != nil {
return err
}

}

return nil

}

func updateRemoteWorkflow(path string, localPath string) error {

err := setWritable(path)
if err != nil {
log.Fatalf("Failed to make writable: %v", err)
}

err = recurseMkdirParent(path)
if err != nil {
log.Fatalf("Failed to create parent directory: %v", err)
}

urlWorkflow = fmt.Sprintf("%s/tree/%s", urlPrefix, strings.TrimPrefix(path, "/"))

urlUpdate := fmt.Sprintf("%s?op=update-workflow", urlWorkflow)
urlCreate := fmt.Sprintf("%s?op=create-workflow", urlWorkflow)

buf, err := safeLoadFile(localPath)
if err != nil {
log.Fatalf("Failed to load workflow file: %v", err)
}
data, err := ioutil.ReadAll(buf)
if err != nil {
log.Fatalf("Failed to load workflow file: %v", err)
}

updateFailed := false
url := urlUpdate
method := http.MethodPost

retry:

req, err := http.NewRequest(
http.MethodPost,
method,
url,
wfData,
bytes.NewReader(data),
)
if err != nil {
return fmt.Errorf("failed to create request file: %v", err)
Expand All @@ -95,6 +298,12 @@ func updateRemoteWorkflow(url string, localPath string) error {
}

if resp.StatusCode != 200 {
if resp.StatusCode == http.StatusNotFound && !updateFailed {
updateFailed = true
url = urlCreate
method = http.MethodPut
goto retry
}
errBody, err := ioutil.ReadAll(resp.Body)
if err == nil {
return fmt.Errorf("failed to update workflow, server responsed with %s\n------DUMPING ERROR BODY ------\n%s", resp.Status, string(errBody))
Expand Down
3 changes: 3 additions & 0 deletions pkg/flow/grpc-nodes.go
Expand Up @@ -437,6 +437,9 @@ func (flow *flow) CreateDirectory(ctx context.Context, req *grpc.CreateDirectory
pino: pino.ino,
path: path,
})
if err != nil {
return nil, err
}

err = tx.Commit()
if err != nil {
Expand Down

0 comments on commit b1dc183

Please sign in to comment.