Skip to content

Commit

Permalink
Factored into modules
Browse files Browse the repository at this point in the history
  • Loading branch information
laszlocph committed Oct 22, 2023
1 parent d7a49fe commit 61ad403
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 169 deletions.
173 changes: 4 additions & 169 deletions cmd/capacitor/main.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,23 @@
package main

import (
"context"
"encoding/json"
"flag"
"fmt"
"net/http"
"os"
"os/signal"
"strings"
"syscall"

kustomizationv1 "github.com/fluxcd/kustomize-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/gimlet-io/capacitor/pkg/api"
"github.com/gimlet-io/capacitor/pkg/controllers"
"github.com/gimlet-io/capacitor/pkg/streaming"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
)

func main() {
fmt.Println("Capacitor starting..")

fmt.Println("Connecting to Kubernetes..")

var kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
flag.Parse()

Expand All @@ -39,61 +27,21 @@ func main() {
panic(err.Error())
}

fmt.Println("--- Flux custom resources ---")
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
panic(err.Error())
}

fluxState, err := getFluxState(dynamicClient)
if err != nil {
panic(err.Error())
}
fluxStateBytes, err := json.Marshal(fluxState)
if err != nil {
panic(err.Error())
}
fmt.Println(string(fluxStateBytes))

var gitRepositoryResource = schema.GroupVersionResource{
Group: "source.toolkit.fluxcd.io",
Version: "v1",
Resource: "gitrepositories",
}

stopCh := make(chan struct{})
defer close(stopCh)

clientHub := streaming.NewClientHub()
go clientHub.Run()

ctrl := controllers.NewDynamicController(
"gitrepositories.source.toolkit.fluxcd.io",
dynamicClient,
gitRepositoryResource,
func(informerEvent controllers.Event, objectMeta metav1.ObjectMeta, obj interface{}) error {
switch informerEvent.EventType {
case "create":
fallthrough
case "update":
fallthrough
case "delete":
fmt.Printf("Changes in %s\n", objectMeta.Name)
fluxState, err := getFluxState(dynamicClient)
if err != nil {
panic(err.Error())
}
fluxStateBytes, err := json.Marshal(fluxState)
if err != nil {
panic(err.Error())
}
clientHub.Broadcast <- fluxStateBytes
}
return nil
})
go ctrl.Run(1, stopCh)
gitRepositoryController := controllers.GitRepositoryController(dynamicClient, clientHub)
go gitRepositoryController.Run(1, stopCh)

r := setupRouter(dynamicClient, clientHub)
r := api.SetupRouter(dynamicClient, clientHub)
go func() {
err = http.ListenAndServe(":9000", r)
if err != nil {
Expand All @@ -118,116 +66,3 @@ func main() {
<-done
logrus.Info("Exiting")
}

type fluxState struct {
GitRepositories []sourcev1.GitRepository `json:"gitRepositories"`
Kustomizations []kustomizationv1.Kustomization `json:"kustomizations"`
}

func getFluxState(dc *dynamic.DynamicClient) (*fluxState, error) {
fluxState := &fluxState{
GitRepositories: []sourcev1.GitRepository{},
Kustomizations: []kustomizationv1.Kustomization{},
}

gitRepositories, err := dc.Resource(schema.GroupVersionResource{
Group: "source.toolkit.fluxcd.io",
Version: "v1",
Resource: "gitrepositories",
}).
Namespace("").
List(context.TODO(), metav1.ListOptions{})
if err != nil {
return nil, err
}

for _, repo := range gitRepositories.Items {
unstructured := repo.UnstructuredContent()
var gitRepository sourcev1.GitRepository
err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &gitRepository)
if err != nil {
return nil, err
}
fluxState.GitRepositories = append(fluxState.GitRepositories, gitRepository)
}

kustomizations, err := dc.Resource(schema.GroupVersionResource{
Group: "kustomize.toolkit.fluxcd.io",
Version: "v1",
Resource: "kustomizations",
}).
Namespace("").
List(context.TODO(), metav1.ListOptions{})
if err != nil {
return nil, err
}
for _, k := range kustomizations.Items {
unstructured := k.UnstructuredContent()
var kustomization kustomizationv1.Kustomization
err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &kustomization)
if err != nil {
return nil, err
}
fluxState.Kustomizations = append(fluxState.Kustomizations, kustomization)
}

return fluxState, nil
}

func setupRouter(
dynamicClient *dynamic.DynamicClient,
clientHub *streaming.ClientHub,
) *chi.Mux {
r := chi.NewRouter()
r.Use(middleware.WithValue("dynamicClient", dynamicClient))

r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
r.Get("/api/fluxState", fluxStateHandler)
r.Get("/ws/", func(w http.ResponseWriter, r *http.Request) {
streaming.ServeWs(clientHub, w, r)
})

filesDir := http.Dir("./web/build")
fileServer(r, "/", filesDir)

return r
}

// static files from a http.FileSystem
func fileServer(r chi.Router, path string, root http.FileSystem) {
if strings.ContainsAny(path, "{}*") {
//TODO: serve all React routes https://github.com/go-chi/chi/issues/403
panic("FileServer does not permit any URL parameters.")
}

if path != "/" && path[len(path)-1] != '/' {
r.Get(path, http.RedirectHandler(path+"/", http.StatusMovedPermanently).ServeHTTP)
path += "/"
}
path += "*"

r.Get(path, func(w http.ResponseWriter, r *http.Request) {
ctx := chi.RouteContext(r.Context())
pathPrefix := strings.TrimSuffix(ctx.RoutePattern(), "/*")
fs := http.StripPrefix(pathPrefix, http.FileServer(root))
fs.ServeHTTP(w, r)
})
}

func fluxStateHandler(w http.ResponseWriter, r *http.Request) {
dynamicClient, _ := r.Context().Value("dynamicClient").(*dynamic.DynamicClient)

fluxState, err := getFluxState(dynamicClient)
if err != nil {
panic(err.Error())
}
fluxStateBytes, err := json.Marshal(fluxState)
if err != nil {
panic(err.Error())
}

w.WriteHeader(http.StatusOK)
w.Write(fluxStateBytes)
}
25 changes: 25 additions & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package api

import (
"encoding/json"
"net/http"

"k8s.io/client-go/dynamic"
"github.com/gimlet-io/capacitor/pkg/flux"
)

func fluxStateHandler(w http.ResponseWriter, r *http.Request) {
dynamicClient, _ := r.Context().Value("dynamicClient").(*dynamic.DynamicClient)

fluxState, err := flux.GetFluxState(dynamicClient)
if err != nil {
panic(err.Error())
}
fluxStateBytes, err := json.Marshal(fluxState)
if err != nil {
panic(err.Error())
}

w.WriteHeader(http.StatusOK)
w.Write(fluxStateBytes)
}
53 changes: 53 additions & 0 deletions pkg/api/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package api

import (
"net/http"
"strings"

"github.com/gimlet-io/capacitor/pkg/streaming"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"k8s.io/client-go/dynamic"
)

func SetupRouter(
dynamicClient *dynamic.DynamicClient,
clientHub *streaming.ClientHub,
) *chi.Mux {
r := chi.NewRouter()
r.Use(middleware.WithValue("dynamicClient", dynamicClient))

r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
r.Get("/api/fluxState", fluxStateHandler)
r.Get("/ws/", func(w http.ResponseWriter, r *http.Request) {
streaming.ServeWs(clientHub, w, r)
})

filesDir := http.Dir("./web/build")
fileServer(r, "/", filesDir)

return r
}

// static files from a http.FileSystem
func fileServer(r chi.Router, path string, root http.FileSystem) {
if strings.ContainsAny(path, "{}*") {
//TODO: serve all React routes https://github.com/go-chi/chi/issues/403
panic("FileServer does not permit any URL parameters.")
}

if path != "/" && path[len(path)-1] != '/' {
r.Get(path, http.RedirectHandler(path+"/", http.StatusMovedPermanently).ServeHTTP)
path += "/"
}
path += "*"

r.Get(path, func(w http.ResponseWriter, r *http.Request) {
ctx := chi.RouteContext(r.Context())
pathPrefix := strings.TrimSuffix(ctx.RoutePattern(), "/*")
fs := http.StripPrefix(pathPrefix, http.FileServer(root))
fs.ServeHTTP(w, r)
})
}
48 changes: 48 additions & 0 deletions pkg/controllers/gitrepositoryController.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package controllers

import (
"encoding/json"
"fmt"

"github.com/gimlet-io/capacitor/pkg/flux"
"github.com/gimlet-io/capacitor/pkg/streaming"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
)

var gitRepositoryResource = schema.GroupVersionResource{
Group: "source.toolkit.fluxcd.io",
Version: "v1",
Resource: "gitrepositories",
}

func GitRepositoryController(
dynamicClient *dynamic.DynamicClient,
clientHub *streaming.ClientHub,
) *Controller {
return NewDynamicController(
"gitrepositories.source.toolkit.fluxcd.io",
dynamicClient,
gitRepositoryResource,
func(informerEvent Event, objectMeta metav1.ObjectMeta, obj interface{}) error {
switch informerEvent.EventType {
case "create":
fallthrough
case "update":
fallthrough
case "delete":
fmt.Printf("Changes in %s\n", objectMeta.Name)
fluxState, err := flux.GetFluxState(dynamicClient)
if err != nil {
panic(err.Error())
}
fluxStateBytes, err := json.Marshal(fluxState)
if err != nil {
panic(err.Error())
}
clientHub.Broadcast <- fluxStateBytes
}
return nil
})
}
Loading

0 comments on commit 61ad403

Please sign in to comment.