package smartconfig import ( "context" "fmt" "os" "strings" "time" clientv3 "go.etcd.io/etcd/client/v3" ) // EtcdResolver retrieves values from etcd. // Usage: ${ETCD:/myapp/config/key} // Requires ETCD_ENDPOINTS environment variable or defaults to localhost:2379 type EtcdResolver struct{} // Resolve retrieves the value from etcd. func (r *EtcdResolver) Resolve(value string) (string, error) { // Default to localhost:2379 if ETCD_ENDPOINTS is not set endpoints := strings.Split(os.Getenv("ETCD_ENDPOINTS"), ",") if len(endpoints) == 1 && endpoints[0] == "" { endpoints = []string{"localhost:2379"} } cli, err := clientv3.New(clientv3.Config{ Endpoints: endpoints, DialTimeout: 5 * time.Second, }) if err != nil { return "", fmt.Errorf("failed to create etcd client: %w", err) } defer func() { _ = cli.Close() }() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() resp, err := cli.Get(ctx, value) if err != nil { return "", fmt.Errorf("failed to get key %s from etcd: %w", value, err) } if len(resp.Kvs) == 0 { return "", fmt.Errorf("key %s not found in etcd", value) } return string(resp.Kvs[0].Value), nil }