Skip to content

Instantly share code, notes, and snippets.

@jedipunkz
Last active January 3, 2023 22:52
Show Gist options
  • Save jedipunkz/ff3e0a3ba1aeee3f2d619f84c852f4c3 to your computer and use it in GitHub Desktop.
Save jedipunkz/ff3e0a3ba1aeee3f2d619f84c852f4c3 to your computer and use it in GitHub Desktop.
get ecs metadata
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
)
const (
ecsMetadataUriEnvV4 = "ECS_CONTAINER_METADATA_URI_V4"
)
type Client struct {
HTTPClient *http.Client
endpoint string
}
type TaskMetadata struct {
Cluster string `json:"Cluster"`
TaskARN string `json:"TaskARN"`
Family string `json:"Family"`
Revision string `json:"Revision"`
DesiredStatus string `json:"DesiredStatus"`
KnownStatus string `json:"KnownStatus"`
AvailabilityZone string `json:"AvailabilityZone"`
LaunchType string `json:"LaunchType"`
Containers []struct {
DockerID string `json:"DockerId"`
Name string `json:"Name"`
DockerName string `json:"DockerName"`
Image string `json:"Image"`
ImageID string `json:"ImageID"`
Labels map[string]string `json:"Labels"`
DesiredStatus string `json:"DesiredStatus"`
KnownStatus string `json:"KnownStatus"`
Type string `json:"Type"`
ContainerARN string `json:"ContainerARN"`
} `json:"Containers"`
}
type StatsMetadata struct {
CPUStats struct {
CPUUsage struct {
TotalUsage int `json:"total_usage"`
PerCPUUsage []int `json:"percpu_usage"`
UsageInKernelmode int `json:"usage_in_kernelmode"`
UsageInUsermode int `json:"usage_in_usermode"`
} `json:"cpu_usage"`
SystemCPUUsage int `json:"system_cpu_usage"`
OnlineCPUs int `json:"online_cpus"`
ThrottlingData struct {
Periods int `json:"periods"`
ThrottledPeriods int `json:"throttled_periods"`
ThrottledTime int `json:"throttled_time"`
} `json:"throttling_data"`
} `json:"cpu_stats"`
PreCPUStats struct {
CPUUsage struct {
TotalUsage int `json:"total_usage"`
PerCPUUsage []int `json:"percpu_usage"`
UsageInKernelmode int `json:"usage_in_kernelmode"`
UsageInUsermode int `json:"usage_in_usermode"`
} `json:"cpu_usage"`
SystemCPUUsage int `json:"system_cpu_usage"`
OnlineCPUs int `json:"online_cpus"`
ThrottlingData struct {
Periods int `json:"periods"`
ThrottledPeriods int `json:"throttled_periods"`
ThrottledTime int `json:"throttled_time"`
} `json:"throttling_data"`
} `json:"precpu_stats"`
}
// NewClient retrurns a new ECS client and endpoint
func NewClient(endpoint string) *Client {
return &Client{
HTTPClient: &http.Client{},
endpoint: endpoint,
}
}
// NewClientToMetadataEndpoint returns a new ECS client and endpoint
func NewClientToMetadataEndpoint() (*Client, error) {
const endpointURI = "ECS_CONTAINER_METADATA_URI_V4"
endpoint := os.Getenv(endpointURI)
if endpoint == "" {
return nil, fmt.Errorf("environment variable %s not set", endpointURI)
}
_, err := url.Parse(endpoint)
if err != nil {
return nil, fmt.Errorf("invalid endpoint: %s", err)
}
return NewClient(endpoint), nil
}
func (c *Client) request(ctx context.Context, uri string, out interface{}) error {
req, err := http.NewRequest("GET", uri, nil)
if err != nil {
return err
}
req = req.WithContext(ctx)
resp, err := c.HTTPClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return json.Unmarshal(body, out)
}
func (c *Client) RetriveTaskMetadata(ctx context.Context) (TaskMetadata, error) {
var output TaskMetadata
err := c.request(ctx, c.endpoint+"/task", &output)
return output, err
}
func (c *Client) RetriveStatsMetadata(ctx context.Context) (map[string]StatsMetadata, error) {
output := make(map[string]StatsMetadata)
err := c.request(ctx, c.endpoint+"/task/stats", &output)
return output, err
}
func main() {
ctx := context.Background()
client, err := NewClientToMetadataEndpoint()
if err != nil {
log.Printf("error creating client: %s", err)
}
taskMetadata, err := client.RetriveTaskMetadata(ctx)
if err != nil {
log.Printf("error retrieving task metadata: %s", err)
}
statsMetadata, err := client.RetriveStatsMetadata(ctx)
if err != nil {
log.Printf("error retrieving task stats metadata: %s", err)
}
for _, container := range taskMetadata.Containers {
s := statsMetadata[container.DockerID]
if &s == nil {
log.Printf("Could not find stats for container %s", container.DockerID)
continue
}
log.Printf("Total CPU Usage: %d", s.CPUStats.CPUUsage.TotalUsage)
log.Printf("CPU Usage: %f", (float64(s.CPUStats.CPUUsage.TotalUsage)-float64(s.PreCPUStats.CPUUsage.TotalUsage))/
(float64(s.CPUStats.SystemCPUUsage)-float64(s.PreCPUStats.SystemCPUUsage))*
float64(s.CPUStats.OnlineCPUs)*100)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment