Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cli improvements #587

Merged
merged 3 commits into from May 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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