-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcurl.go
More file actions
130 lines (107 loc) · 3.73 KB
/
curl.go
File metadata and controls
130 lines (107 loc) · 3.73 KB
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
// Copyright (c) Codesphere Inc.
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"context"
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"
"time"
io_pkg "github.com/codesphere-cloud/cs-go/pkg/io"
"github.com/spf13/cobra"
)
// DefaultCommandExecutor uses os/exec to run commands
type DefaultCommandExecutor struct{}
func (e *DefaultCommandExecutor) Execute(ctx context.Context, name string, args []string, stdout, stderr io.Writer) error {
cmd := exec.CommandContext(ctx, name, args...)
cmd.Stdout = stdout
cmd.Stderr = stderr
return cmd.Run()
}
type CurlOptions struct {
*GlobalOptions
Timeout time.Duration
Executor CommandExecutor // Injectable for testing
}
type CurlCmd struct {
cmd *cobra.Command
Opts CurlOptions
}
func (c *CurlCmd) RunE(_ *cobra.Command, args []string) error {
client, err := NewClient(*c.Opts.GlobalOptions)
if err != nil {
return fmt.Errorf("failed to create Codesphere client: %w", err)
}
wsId, err := c.Opts.GetWorkspaceId()
if err != nil {
return fmt.Errorf("failed to get workspace ID: %w", err)
}
token, err := c.Opts.Env.GetApiToken()
if err != nil {
return fmt.Errorf("failed to get API token: %w", err)
}
path := "/"
var curlArgs []string
if len(args) > 0 {
if strings.HasPrefix(args[0], "/") {
path = args[0]
curlArgs = args[1:]
} else {
curlArgs = args
}
}
return c.CurlWorkspace(client, wsId, token, path, curlArgs)
}
func AddCurlCmd(rootCmd *cobra.Command, opts *GlobalOptions) {
curl := CurlCmd{
cmd: &cobra.Command{
Use: "curl [path] [-- curl-args...]",
Short: "Send authenticated HTTP requests to workspace dev domain",
Long: `Send authenticated HTTP requests to a workspace's development domain using curl-like syntax.`,
Example: io_pkg.FormatExampleCommands("curl", []io_pkg.Example{
{Cmd: "/ -w 1234", Desc: "GET request to workspace root"},
{Cmd: "/api/health -w 1234", Desc: "GET request to health endpoint"},
{Cmd: "/api/data -w 1234 -- -XPOST -d '{\"key\":\"value\"}'", Desc: "POST request with data"},
{Cmd: "/api/endpoint -w 1234 -- -v", Desc: "verbose output"},
{Cmd: "-w 1234 -- -v", Desc: "verbose request to workspace root"},
{Cmd: "/ -- -k", Desc: "skip TLS verification"}, {Cmd: "/ -- -I", Desc: "HEAD request using workspace from env var"},
}),
Args: cobra.ArbitraryArgs,
},
Opts: CurlOptions{
GlobalOptions: opts,
Executor: &DefaultCommandExecutor{},
},
}
curl.cmd.Flags().DurationVar(&curl.Opts.Timeout, "timeout", 30*time.Second, "Timeout for the request")
rootCmd.AddCommand(curl.cmd)
curl.cmd.RunE = curl.RunE
}
func (c *CurlCmd) CurlWorkspace(client Client, wsId int, token string, path string, curlArgs []string) error {
workspace, err := client.GetWorkspace(wsId)
if err != nil {
return fmt.Errorf("failed to get workspace: %w", err)
}
// Get the dev domain from the workspace
if workspace.DevDomain == nil || *workspace.DevDomain == "" {
return fmt.Errorf("workspace %d does not have a dev domain configured", wsId)
}
// Use the workspace's dev domain
devDomain := *workspace.DevDomain
url := fmt.Sprintf("https://%s%s", devDomain, path)
log.Printf("Sending request to workspace %d (%s) at %s\n", wsId, workspace.Name, url)
ctx, cancel := context.WithTimeout(context.Background(), c.Opts.Timeout)
defer cancel()
// Build curl command with authentication header and -L to follow redirects
cmdArgs := []string{"curl", "-L", "-H", fmt.Sprintf("X-CS-Authorization: Bearer %s", token)}
cmdArgs = append(cmdArgs, curlArgs...)
cmdArgs = append(cmdArgs, url)
err = c.Opts.Executor.Execute(ctx, cmdArgs[0], cmdArgs[1:], os.Stdout, os.Stderr)
if err != nil && err == context.DeadlineExceeded {
return fmt.Errorf("timeout exceeded while requesting workspace %d", wsId)
}
return err
}