Skip to content

Commit dbf0156

Browse files
committed
Add metering command
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <[email protected]>
1 parent 40de12c commit dbf0156

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,17 @@ actuated-cli logs \
108108
server1
109109
```
110110

111+
## View the metering snapshot from a VM
112+
113+
Use the `--id` flag to specify the runner ID.
114+
115+
```bash
116+
actuated-cli metering \
117+
--owner actuated-samples \
118+
--id ea5c285282620927689d90af3cfa3be2d5e2d004 \
119+
server1
120+
```
121+
111122
## Check the logs of the actuated agent service
112123

113124
Show the logs of the actuated agent binary running on your server.

cmd/metering.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"os"
7+
"strings"
8+
9+
"github.com/self-actuated/actuated-cli/pkg"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
func makeMetering() *cobra.Command {
14+
cmd := &cobra.Command{
15+
Use: "metering",
16+
Short: "Fetch metering from a VM",
17+
Long: `Fetch the metering snapshot from a specific VM.`,
18+
19+
Example: `# Get the metering snapshot from a specific VM using its hostname as the --id
20+
actuated-cli metering --owner=OWNER --id=ID HOST
21+
`,
22+
}
23+
24+
cmd.RunE = runMeteringE
25+
26+
cmd.Flags().StringP("owner", "o", "", "List logs owned by this user")
27+
cmd.Flags().String("id", "", "ID variable for a specific runner VM hostname")
28+
29+
return cmd
30+
}
31+
32+
func runMeteringE(cmd *cobra.Command, args []string) error {
33+
if len(args) < 1 {
34+
return fmt.Errorf("specify the host as an argument")
35+
}
36+
host := strings.TrimSpace(args[0])
37+
38+
pat, err := getPat(cmd)
39+
if err != nil {
40+
return err
41+
}
42+
43+
staff, err := cmd.Flags().GetBool("staff")
44+
if err != nil {
45+
return err
46+
}
47+
48+
owner, err := cmd.Flags().GetString("owner")
49+
if err != nil {
50+
return err
51+
}
52+
53+
id, err := cmd.Flags().GetString("id")
54+
if err != nil {
55+
return err
56+
}
57+
58+
if len(host) == 0 {
59+
return fmt.Errorf("host is required")
60+
}
61+
62+
if len(owner) == 0 {
63+
return fmt.Errorf("owner is required")
64+
}
65+
66+
if len(pat) == 0 {
67+
return fmt.Errorf("pat is required")
68+
}
69+
70+
c := pkg.NewClient(http.DefaultClient, os.Getenv("ACTUATED_URL"))
71+
72+
res, status, err := c.GetMetering(pat, owner, host, id, staff)
73+
74+
if err != nil {
75+
return err
76+
}
77+
78+
if status != http.StatusAccepted {
79+
return fmt.Errorf("unexpected status code: %d, body: %s", status, res)
80+
}
81+
82+
fmt.Println(res)
83+
84+
return nil
85+
86+
}

pkg/client.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package pkg
22

33
import (
4+
"bytes"
5+
"encoding/json"
46
"fmt"
57
"io"
68
"log"
@@ -292,6 +294,67 @@ func (c *Client) GetLogs(patStr, owner, host, id string, age time.Duration, staf
292294
return string(body), res.StatusCode, nil
293295
}
294296

297+
func (c *Client) GetMetering(patStr, owner, host, id string, staff bool) (string, int, error) {
298+
299+
u, _ := url.Parse(c.baseURL)
300+
u.Path = "/api/v1/metering"
301+
302+
q := u.Query()
303+
q.Set("owner", owner)
304+
q.Set("host", host)
305+
306+
if len(id) > 0 {
307+
q.Set("id", id)
308+
} else {
309+
return "", http.StatusBadRequest, fmt.Errorf("id is required")
310+
}
311+
312+
if staff {
313+
q.Set("staff", "1")
314+
}
315+
316+
u.RawQuery = q.Encode()
317+
318+
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
319+
if err != nil {
320+
return "", http.StatusBadRequest, err
321+
}
322+
323+
req.Header.Set("Authorization", "Bearer "+patStr)
324+
325+
if os.Getenv("DEBUG") == "1" {
326+
sanitised := http.Header{}
327+
for k, v := range req.Header {
328+
329+
if k == "Authorization" {
330+
v = []string{"redacted"}
331+
}
332+
sanitised[k] = v
333+
}
334+
335+
fmt.Printf("URL %s\nHeaders: %v\n", u.String(), sanitised)
336+
}
337+
338+
res, err := c.httpClient.Do(req)
339+
if err != nil {
340+
return "", http.StatusBadRequest, err
341+
}
342+
343+
var body []byte
344+
if res.Body != nil {
345+
defer res.Body.Close()
346+
body, _ = io.ReadAll(res.Body)
347+
}
348+
349+
var prettyJSON bytes.Buffer
350+
351+
if err = json.Indent(&prettyJSON, []byte(body), "", " "); err != nil {
352+
return "", http.StatusBadRequest, err
353+
}
354+
355+
return prettyJSON.String(), res.StatusCode, nil
356+
}
357+
295358
func (c *Client) GetAgentLogs(patStr, owner, host string, age time.Duration, staff bool) (string, int, error) {
296359

297360
mins := int(age.Minutes())

0 commit comments

Comments
 (0)