Skip to content

Commit

Permalink
Fetch respective metadata (cluster name, cluster location, or instanc…
Browse files Browse the repository at this point in the history
…e zone) (#16)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
brettcurtis and coderabbitai[bot] authored Jun 29, 2024
1 parent d647128 commit 3448908
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 71 deletions.
39 changes: 19 additions & 20 deletions cmd/http/main.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package main

import (
"fmt"
"log"
"net/http"
"os"

"gke-info/internal/metadata"

// "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
// "gopkg.in/DataDog/dd-trace-go.v1/profiler"

// httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"
"fmt"
"log"
"net/http"
"os"

"gke-info/internal/metadata"
// "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
// "gopkg.in/DataDog/dd-trace-go.v1/profiler"
// httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"
)

// func main() {
Expand All @@ -30,7 +28,7 @@ import (
// defer profiler.Stop()

// mux := httptrace.NewServeMux()
// mux.HandleFunc("/gke-info", metadata.GetMetadata)
// mux.HandleFunc("/metadata", metadata.MetadataHandler)

// port := "8080"
// if envPort := os.Getenv("PORT"); envPort != "" {
Expand All @@ -43,14 +41,15 @@ import (
// }

func main() {
http.HandleFunc("/gke-info", metadata.GetMetadata)
http.HandleFunc("/metadata", metadata.MetadataHandler)

port := "8080"
if envPort := os.Getenv("PORT"); envPort != "" {
port = envPort
}
port := "8080"
if envPort := os.Getenv("PORT"); envPort != "" {
port = envPort
}

if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
log.Printf("Starting server on port %s...\n", port)
if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}
135 changes: 84 additions & 51 deletions internal/metadata/main.go
Original file line number Diff line number Diff line change
@@ -1,57 +1,90 @@
package metadata

import (
"fmt"
"io"
"net/http"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
)

func GetMetadata(w http.ResponseWriter, r *http.Request) {
// Extract the path parameter from the URL
metadataType := r.URL.Path[len("/gke-info/"):]

var metadataURL string

// Only allow fetching the cluster name for security reasons
if metadataType == "cluster-name" {
} else {
http.Error(w, "Request not allowed", http.StatusForbidden)
return
}

// Construct the metadata URL dynamically
metadataURL = fmt.Sprintf("http://metadata.google.internal/computeMetadata/v1/instance/attributes/%s", metadataType)

// Set the metadata request headers
req, err := http.NewRequest("GET", metadataURL, nil)
if err != nil {
http.Error(w, fmt.Sprintf("Error creating request: %v", err), http.StatusInternalServerError)
return
}
req.Header.Set("Metadata-Flavor", "Google")

// Send the request to the metadata server
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
http.Error(w, fmt.Sprintf("Error retrieving metadata: %v", err), http.StatusInternalServerError)
return
}
defer resp.Body.Close()

// Check the response status code
if resp.StatusCode != http.StatusOK {
http.Error(w, fmt.Sprintf("Error retrieving metadata, status code: %d", resp.StatusCode), http.StatusInternalServerError)
return
}

// Set the Content-Type header to JSON
w.Header().Set("Content-Type", "application/json")

// Copy the response from the metadata server to the output
_, err = io.Copy(w, resp.Body)
if err != nil {
http.Error(w, fmt.Sprintf("Error writing response: %v", err), http.StatusInternalServerError)
return
}
// Metadata server URLs
const (
clusterNameURL = "http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-name"
clusterLocationURL = "http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-location"
instanceZoneURL = "http://metadata.google.internal/computeMetadata/v1/instance/zone"
)

// fetchMetadata fetches metadata from the provided URL
func fetchMetadata(url string) (string, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}

// Adding the metadata flavor header as required by GCP metadata server
req.Header.Add("Metadata-Flavor", "Google")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to get metadata from %s, status code: %d", url, resp.StatusCode)
}

body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}

return string(body), nil
}

// metadataHandler handles the /metadata/* endpoint
func MetadataHandler(w http.ResponseWriter, r *http.Request) {
pathParts := strings.Split(r.URL.Path, "/")
if len(pathParts) < 3 {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}

metadataType := pathParts[2]
var url string

switch metadataType {
case "cluster-name":
url = clusterNameURL
case "cluster-location":
url = clusterLocationURL
case "instance-zone":
url = instanceZoneURL
default:
http.Error(w, "Unknown metadata type", http.StatusBadRequest)
return
}

metadata, err := fetchMetadata(url)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// If instance zone, extract just the zone from the full zone URL
if metadataType == "instance-zone" {
instanceZoneParts := strings.Split(metadata, "/")
if len(instanceZoneParts) > 0 {
metadata = instanceZoneParts[len(instanceZoneParts)-1]
}
}

response := map[string]string{metadataType: metadata}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
}
}

0 comments on commit 3448908

Please sign in to comment.