Skip to content

Commit f1b768f

Browse files
authored
V0.0.1 alpha release (#106)
* add v1alpha release * updates * update for release * update cli
1 parent 4c30581 commit f1b768f

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

cli/commands/proxy.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package commands
2+
3+
import (
4+
"bz/pkg/proxy"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var (
10+
proxyCmd = &cobra.Command{
11+
Use: "proxy",
12+
Short: "bz proxy - port-forward baaz control plane locally",
13+
RunE: func(cmd *cobra.Command, args []string) error {
14+
proxy.Run()
15+
return nil
16+
},
17+
}
18+
)
19+
20+
func init() {
21+
rootCmd.AddCommand(proxyCmd)
22+
}

cli/pkg/proxy/proxy.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package proxy
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"net/http"
8+
"os"
9+
"strings"
10+
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/client-go/kubernetes"
13+
restclient "k8s.io/client-go/rest"
14+
"k8s.io/client-go/tools/clientcmd"
15+
"k8s.io/client-go/tools/portforward"
16+
"k8s.io/client-go/transport/spdy"
17+
)
18+
19+
func Run() {
20+
namespace := "baaz"
21+
serviceName := "baaz"
22+
localPort := "8000"
23+
svcPort := "8000"
24+
25+
// Initialize Kubernetes client
26+
config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
27+
if err != nil {
28+
fmt.Printf("Error building Kubernetes client config: %v\n", err)
29+
os.Exit(1)
30+
}
31+
32+
clientset, err := kubernetes.NewForConfig(config)
33+
if err != nil {
34+
fmt.Printf("Error creating Kubernetes client: %v\n", err)
35+
os.Exit(1)
36+
}
37+
38+
// Check if the service exists
39+
service, err := clientset.CoreV1().Services(namespace).Get(context.TODO(), serviceName, metav1.GetOptions{})
40+
if err != nil {
41+
if strings.Contains(err.Error(), "not found") {
42+
fmt.Printf("Service %s not found in namespace %s\n", serviceName, namespace)
43+
} else {
44+
fmt.Printf("Error retrieving service: %v\n", err)
45+
}
46+
os.Exit(1)
47+
}
48+
49+
// Check if the service has the correct ports
50+
if len(service.Spec.Ports) == 0 {
51+
fmt.Printf("Service %s has no ports defined\n", serviceName)
52+
os.Exit(1)
53+
}
54+
55+
// Port-forward service
56+
podName, err := getFirstRunningPod(clientset, namespace)
57+
if err != nil {
58+
fmt.Printf("Error finding running pod for service: %v\n", err)
59+
os.Exit(1)
60+
}
61+
62+
err = forwardServicePort(config, namespace, podName, localPort, svcPort)
63+
if err != nil {
64+
fmt.Printf("Error port-forwarding: %v\n", err)
65+
os.Exit(1)
66+
}
67+
68+
fmt.Printf("Service %s is now accessible on localhost:%s\n", serviceName, localPort)
69+
}
70+
71+
// Get the first running pod in the namespace (since port-forward needs a pod)
72+
func getFirstRunningPod(clientset *kubernetes.Clientset, namespace string) (string, error) {
73+
pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{
74+
FieldSelector: "status.phase=Running",
75+
})
76+
if err != nil {
77+
return "", fmt.Errorf("error listing pods: %w", err)
78+
}
79+
if len(pods.Items) == 0 {
80+
return "", fmt.Errorf("no running pods found in namespace %s", namespace)
81+
}
82+
return pods.Items[0].Name, nil
83+
}
84+
85+
// Set up port forwarding using client-go portforward package
86+
func forwardServicePort(config *restclient.Config, namespace, podName, localPort, svcPort string) error {
87+
// Create spdy roundtripper for port forwarding
88+
path := fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/portforward", namespace, podName)
89+
hostIP := strings.TrimLeft(config.Host, "htps:/")
90+
91+
transport, upgrader, err := spdy.RoundTripperFor(config)
92+
if err != nil {
93+
return fmt.Errorf("error creating round tripper: %w", err)
94+
}
95+
96+
// Create the request for port forwarding
97+
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", config.Host, path), nil)
98+
if err != nil {
99+
return fmt.Errorf("error creating port forward request: %w", err)
100+
}
101+
102+
req.Header.Add("Host", hostIP)
103+
104+
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", req.URL)
105+
stopChan := make(chan struct{}, 1)
106+
readyChan := make(chan struct{}, 1)
107+
out := io.Discard // Change this to os.Stdout if you want to see output
108+
errOut := os.Stderr
109+
110+
ports := []string{fmt.Sprintf("%s:%s", localPort, svcPort)}
111+
112+
pf, err := portforward.New(dialer, ports, stopChan, readyChan, out, errOut)
113+
if err != nil {
114+
return fmt.Errorf("error creating port forwarder: %w", err)
115+
}
116+
117+
go func() {
118+
<-readyChan // Block until the port forward is ready
119+
fmt.Println("Port forwarding is ready")
120+
}()
121+
122+
// Start the port forwarding process
123+
if err := pf.ForwardPorts(); err != nil {
124+
return fmt.Errorf("error forwarding ports: %w", err)
125+
}
126+
127+
return nil
128+
}

0 commit comments

Comments
 (0)