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

Refactor: credhub service broker asset #1099

Merged
merged 1 commit into from
Apr 6, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions assets/credhub-service-broker/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

import (
"log"
"os"
"strconv"

uuid "github.com/satori/go.uuid"
)

type CredhubConfig struct {
API string
Client string
Secret string
}

type Config struct {
Port int

ServiceName string
ServiceUUID string
PlanUUID string

Credhub CredhubConfig
}

func LoadConfig() Config {
cfg := Config{
Port: 8080,
ServiceName: "credhub-read",
ServiceUUID: uuid.NewV4().String(),
PlanUUID: uuid.NewV4().String(),
Credhub: CredhubConfig{
API: os.Getenv("CREDHUB_API"),
Client: os.Getenv("CREDHUB_CLIENT"),
Secret: os.Getenv("CREDHUB_SECRET"),
},
}

if portStr, ok := os.LookupEnv("PORT"); ok {
port, err := strconv.Atoi(portStr)
if err != nil || port < 1 || port > 65535 {
log.Panicf("Invalid value for PORT: %q. Please ensure the PORT environment variable is a valid integer between 1 and 65535.", portStr)
}
cfg.Port = port
}

if serviceName, ok := os.LookupEnv("SERVICE_NAME"); ok {
cfg.ServiceName = serviceName
}

if serviceUUID, ok := os.LookupEnv("SERVICE_UUID"); ok {
cfg.ServiceUUID = serviceUUID
}

if planUUID, ok := os.LookupEnv("PLAN_UUID"); ok {
cfg.PlanUUID = planUUID
}

if cfg.Credhub.API == "" {
log.Panicf("Invalid value for CREDHUB_API: %q. Please ensure the CREDHUB_API environment variable is set to a valid url.", cfg.Credhub.API)
}

if cfg.Credhub.Client == "" {
log.Panicf("Invalid value for CREDHUB_CLIENT: %q. Please ensure the CREDHUB_CLIENT environment variable is set to a valid CredHub client.", cfg.Credhub.Client)
}

if cfg.Credhub.Secret == "" {
log.Panicf("Invalid value for CREDHUB_SECRET: %q. Please ensure the CREDHUB_SECRET environment variable is set to a valid CredHub secret for the provided client.", cfg.Credhub.Secret)
}

return cfg
}
107 changes: 107 additions & 0 deletions assets/credhub-service-broker/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package main

import (
"os"
"testing"
)

func TestLoadConfig(t *testing.T) {
os.Setenv("CREDHUB_API", "https://example.com")
os.Setenv("CREDHUB_CLIENT", "test-client")
os.Setenv("CREDHUB_SECRET", "test-secret")

tests := []struct {
name string
setup func()
teardown func()

expectPort int
expectServiceName string
expectPanic bool
}{
{
name: "default",
expectPort: 8080,
expectServiceName: "credhub-read",
},
{
name: "custom port and service name",
setup: func() {
os.Setenv("PORT", "9000")
os.Setenv("SERVICE_NAME", "my-service")
},
teardown: func() {
os.Unsetenv("PORT")
},
expectPort: 9000,
expectServiceName: "my-service",
},
{
name: "invalid port",
setup: func() {
os.Setenv("PORT", "invalid")
},
teardown: func() {
os.Unsetenv("PORT")
},
expectPanic: true,
},
{
name: "credhub api not set",
setup: func() {
os.Unsetenv("CREDHUB_API")
},
teardown: func() {
os.Setenv("CREDHUB_API", "https://example.com")
},
expectPanic: true,
},
{
name: "credhub client not set",
setup: func() {
os.Unsetenv("CREDHUB_CLIENT")
},
teardown: func() {
os.Setenv("CREDHUB_CLIENT", "test-client")
},
expectPanic: true,
},
{
name: "credhub secret not set",
setup: func() {
os.Unsetenv("CREDHUB_SECRET")
},
teardown: func() {
os.Setenv("CREDHUB_SECRET", "test-secret")
},
expectPanic: true,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
if tc.setup != nil {
tc.setup()
}
if tc.teardown != nil {
defer tc.teardown()
}

if tc.expectPanic {
defer func() {
if r := recover(); r == nil {
t.Errorf("LoadConfig() should have panicked")
}
}()
}

got := LoadConfig()
if got.Port != tc.expectPort {
t.Errorf("LoadConfig().Port = %d, want %d", got.Port, tc.expectPort)
}
if got.ServiceName != tc.expectServiceName {
t.Errorf("LoadConfig().ServiceName = %s, want %s", got.ServiceName, tc.expectServiceName)
}
})
}
}
99 changes: 42 additions & 57 deletions assets/credhub-service-broker/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,76 +4,61 @@ import (
"encoding/json"
"log"
"net/http"
"os"
"strconv"
"time"

"code.cloudfoundry.org/credhub-cli/credhub"
"code.cloudfoundry.org/credhub-cli/credhub/credentials/values"
"github.com/go-chi/chi/v5"
uuid "github.com/satori/go.uuid"
)

var (
SERVICE_NAME string
SERVICE_UUID string
PLAN_UUID string
)

func init() {
SERVICE_NAME = os.Getenv("SERVICE_NAME")
if SERVICE_NAME == "" {
SERVICE_NAME = "credhub-read"
}
SERVICE_UUID = uuid.NewV4().String()
PLAN_UUID = uuid.NewV4().String()
}

func catalogHandler(w http.ResponseWriter, r *http.Request) {
// Create a new catalog response
type Plans struct {
Name string `json:"name"`
ID string `json:"id"`
Description string `json:"description"`
}
type Services struct {
Name string `json:"name"`
ID string `json:"id"`
Description string `json:"description"`
Bindable bool `json:"bindable"`
Plans []Plans `json:"plans"`
}
catalog := struct {
Services []Services `json:"services"`
}{
Services: []Services{
{
Name: SERVICE_NAME,
ID: SERVICE_UUID,
Description: "credhub read service for tests",
Bindable: true,
Plans: []Plans{
{
Name: "credhub-read-plan",
ID: PLAN_UUID,
Description: "credhub read plan for tests",
func catalogHandler(cfg Config) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
// Create a new catalog response
type Plans struct {
Name string `json:"name"`
ID string `json:"id"`
Description string `json:"description"`
}
type Services struct {
Name string `json:"name"`
ID string `json:"id"`
Description string `json:"description"`
Bindable bool `json:"bindable"`
Plans []Plans `json:"plans"`
}
catalog := struct {
Services []Services `json:"services"`
}{
Services: []Services{
{
Name: cfg.ServiceName,
ID: cfg.ServiceUUID,
Description: "credhub read service for tests",
Bindable: true,
Plans: []Plans{
{
Name: "credhub-read-plan",
ID: cfg.PlanUUID,
Description: "credhub read plan for tests",
},
},
},
},
},
}
}

// Marshal the catalog response to JSON
catalogJSON, err := json.Marshal(catalog)
if err != nil {
log.Println("Failed to marshal catalog response: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
// Marshal the catalog response to JSON
catalogJSON, err := json.Marshal(catalog)
if err != nil {
log.Println("Failed to marshal catalog response: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
}

// Write the catalog response to the response writer
w.WriteHeader(http.StatusOK)
w.Write(catalogJSON) //nolint:errcheck
// Write the catalog response to the response writer
w.WriteHeader(http.StatusOK)
w.Write(catalogJSON) //nolint:errcheck
}
}

func bindHandler(ch *credhub.CredHub, bindings map[string]string) http.HandlerFunc {
Expand Down
23 changes: 9 additions & 14 deletions assets/credhub-service-broker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"fmt"
"log"
"net/http"
"os"
"strconv"

"code.cloudfoundry.org/credhub-cli/credhub"
"code.cloudfoundry.org/credhub-cli/credhub/auth"
Expand All @@ -15,14 +13,17 @@ import (
)

func main() {
// Load configuration
cfg := LoadConfig()

// Create a new CredHub client
ch, err := credhub.New(
util.AddDefaultSchemeIfNecessary(os.Getenv("CREDHUB_API")),
util.AddDefaultSchemeIfNecessary(cfg.Credhub.API),
credhub.SkipTLSValidation(true),
credhub.Auth(auth.UaaClientCredentials(os.Getenv("CREDHUB_CLIENT"), os.Getenv("CREDHUB_SECRET"))),
credhub.Auth(auth.UaaClientCredentials(cfg.Credhub.Client, cfg.Credhub.Secret)),
)
if err != nil {
log.Fatal("Failed to create CredHub client: ", err)
log.Panic("Failed to create CredHub client: ", err)
}

// Create a map of service binding GUIDs to track the registered service instances
Expand All @@ -32,7 +33,7 @@ func main() {
router := chi.NewRouter()
router.Use(middleware.Recoverer)

router.Get("/v2/catalog", catalogHandler)
router.Get("/v2/catalog", catalogHandler(cfg))
router.Route("/v2/service_instances", func(r chi.Router) {
r.Put("/{service_instance_guid}", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{}"))
Expand All @@ -46,13 +47,7 @@ func main() {
})
})

// Retrieve the port to listen on from the environment
port, err := strconv.Atoi(os.Getenv("PORT"))
if err != nil {
log.Fatal("Failed to parse PORT: ", err)
}

// Start the HTTP server
log.Printf("Server starting, listening on port %d...", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), router))
log.Printf("Server starting, listening on port %d...", cfg.Port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), router))
}