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

WIP: Move to tofu controller #878

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
0726993
Moving to tofu-controller
laszlocph Sep 18, 2024
088dd10
Databases editor
laszlocph Sep 21, 2024
74ed3e5
WIP
laszlocph Sep 24, 2024
23e023f
Merge branch 'main' into move-to-tofu-controller
laszlocph Sep 25, 2024
b9b169e
Merge remote-tracking branch 'origin/main' into move-to-tofu-controller
laszlocph Sep 26, 2024
edb6ebc
Helm UI css improvements
laszlocph Sep 26, 2024
9d28d66
removed excess css
laszlocph Sep 26, 2024
99734ba
experimenting with helm ui
laszlocph Sep 26, 2024
b437932
schema preps
laszlocph Sep 26, 2024
413588d
minor thing
laszlocph Sep 26, 2024
6c46ba2
wip
laszlocph Sep 26, 2024
f4779cc
dependencies inner state
laszlocph Sep 26, 2024
c032c41
combobox with module title
laszlocph Sep 26, 2024
a4389d1
module selector done
laszlocph Sep 26, 2024
3b5f38d
wip
laszlocph Sep 26, 2024
81fd58d
add and remove dependencies
laszlocph Sep 27, 2024
b0be881
populating depenencies
laszlocph Sep 27, 2024
fccaf9e
Pod names shown
laszlocph Sep 27, 2024
cf4bd06
rendering plain modules
laszlocph Sep 27, 2024
a888d10
rendering plain modules
laszlocph Sep 27, 2024
4b4fbf3
unused
laszlocph Sep 30, 2024
e365cd7
modelling belongsTo relationship
laszlocph Sep 30, 2024
2b33049
Merge remote-tracking branch 'origin/main' into move-to-tofu-controller
laszlocph Oct 9, 2024
5c86c21
Fix
laszlocph Oct 9, 2024
752ad10
monkeypatch podLogs call that was deployment based to take a faked de…
laszlocph Oct 10, 2024
5b03440
PlainSpec
laszlocph Oct 10, 2024
c88d0ba
unified deps
laszlocph Oct 13, 2024
fb670a1
Catalog
laszlocph Oct 14, 2024
b2afbe1
Baby steps
laszlocph Oct 14, 2024
bfa7958
model change
laszlocph Oct 14, 2024
dc499b5
chart.repository to contain git urls
laszlocph Oct 14, 2024
8001b53
Iteration
laszlocph Oct 14, 2024
3031a89
Iteration
laszlocph Oct 14, 2024
df6f302
Updating catalog
laszlocph Oct 15, 2024
bba0cc1
Terraform resources
laszlocph Oct 16, 2024
c62d3ed
Refactoring prop stuffing
laszlocph Oct 16, 2024
4e3fa6b
Refactoring intermediate model
laszlocph Oct 16, 2024
0d8088d
Terraform state streaming
laszlocph Oct 16, 2024
cbb93a6
Navigate to footer
laszlocph Oct 16, 2024
8c19ecb
Fixing ellipsis
laszlocph Oct 17, 2024
867d3dd
Refactor describe
laszlocph Oct 17, 2024
983556f
Describing tf resourece
laszlocph Oct 17, 2024
862aff4
Describing tf resourece
laszlocph Oct 17, 2024
675f07b
TF reconciling state
laszlocph Oct 18, 2024
48240c1
..
laszlocph Oct 19, 2024
ae49dab
Prevent duplicates
laszlocph Oct 19, 2024
422eafc
More robust org token manager
laszlocph Nov 7, 2024
11ee5a8
More robust local dev experience
laszlocph Nov 12, 2024
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
220 changes: 113 additions & 107 deletions cmd/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import (
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -237,30 +237,28 @@ func serverCommunication(
go sendState(kubeEnv, config.Host, config.AgentKey)
// go sendEvents(kubeEnv, config.Host, config.AgentKey)
case "podLogs":
go podLogs(
kubeEnv,
e["namespace"].(string),
e["deploymentName"].(string),
messages,
runningLogStreams,
)
var namespace, deploymentName, podName, containerName string
namespace = e["namespace"].(string)
if val, ok := e["deploymentName"]; ok {
deploymentName = val.(string)
}
if val, ok := e["podName"]; ok {
podName = val.(string)
}
if val, ok := e["containerName"]; ok {
containerName = val.(string)
}
go podLogs(kubeEnv, namespace, deploymentName, podName, containerName, messages, runningLogStreams)
case "stopPodLogs":
namespace := e["namespace"].(string)
deployment := e["deploymentName"].(string)
go runningLogStreams.Stop(namespace, deployment)
case "deploymentDetails":
go deploymentDetails(
kubeEnv,
e["namespace"].(string),
e["deploymentName"].(string),
config.Host,
config.AgentKey,
)
case "podDetails":
go podDetails(
case "describe":
go describeResource(
kubeEnv,
e["resource"].(string),
e["namespace"].(string),
e["podName"].(string),
e["name"].(string),
config.Host,
config.AgentKey,
)
Expand Down Expand Up @@ -305,7 +303,7 @@ func serverCommunication(
}

func sendState(kubeEnv *agent.KubeEnv, gimletHost string, agentKey string) {
stacks, err := kubeEnv.Services("")
stacks, err := kubeEnv.Services()
if err != nil {
logrus.Errorf("could not get state from k8s apiServer: %v", err)
return
Expand Down Expand Up @@ -357,7 +355,7 @@ func sendFluxState(kubeEnv *agent.KubeEnv, gimletHost string, agentKey string) {
}

func sendEvents(kubeEnv *agent.KubeEnv, gimletHost string, agentKey string) {
events, err := kubeEnv.WarningEvents("")
events, err := kubeEnv.WarningEvents()
if err != nil {
logrus.Errorf("could not get events from k8s apiServer: %v", err)
return
Expand Down Expand Up @@ -399,31 +397,48 @@ func podLogs(
kubeEnv *agent.KubeEnv,
namespace string,
deploymentName string,
podName string,
containerName string,
messages chan *streaming.WSMessage,
runningLogStreams *runningLogStreams,
) {
deployment, err := kubeEnv.Client.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, meta_v1.GetOptions{})
if err != nil {
logrus.Errorf("could not get deployments: %v", err)
return
}

podsInNamespace, err := kubeEnv.Client.CoreV1().Pods(namespace).List(context.TODO(), meta_v1.ListOptions{})
if err != nil {
logrus.Errorf("could not get pods: %v", err)
return
}
if podName != "" {
if containerName != "" {
go streamPodLogs(kubeEnv, namespace, podName, containerName, deploymentName, messages, runningLogStreams)
} else {
pod, err := kubeEnv.Client.CoreV1().Pods(namespace).Get(context.TODO(), podName, meta_v1.GetOptions{})
if err != nil {
logrus.Errorf("could not get pod %s: %v", podName, err)
return
}

for _, pod := range podsInNamespace.Items {
if labelsMatchSelectors(pod.ObjectMeta.Labels, deployment.Spec.Selector.MatchLabels) {
containers := agent.PodContainers(pod.Spec)
for _, container := range containers {
go streamPodLogs(kubeEnv, namespace, pod.Name, container.Name, deploymentName, messages, runningLogStreams)
}
}
}
} else {
deployment, err := kubeEnv.Client.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, meta_v1.GetOptions{})
if err != nil {
logrus.Errorf("could not get deployments: %v", err)
return
}

logrus.Debug("pod logs sent")
podsInNamespace, err := kubeEnv.Client.CoreV1().Pods(namespace).List(context.TODO(), meta_v1.ListOptions{})
if err != nil {
logrus.Errorf("could not get pods: %v", err)
return
}

for _, pod := range podsInNamespace.Items {
if labelsMatchSelectors(pod.ObjectMeta.Labels, deployment.Spec.Selector.MatchLabels) {
containers := agent.PodContainers(pod.Spec)
for _, container := range containers {
go streamPodLogs(kubeEnv, namespace, pod.Name, container.Name, deploymentName, messages, runningLogStreams)
}
}
}
}
}

func labelsMatchSelectors(labels map[string]string, selectors map[string]string) bool {
Expand All @@ -440,39 +455,89 @@ func labelsMatchSelectors(labels map[string]string, selectors map[string]string)
return true
}

func deploymentDetails(
func describeResource(
kubeEnv *agent.KubeEnv,
resource string,
namespace string,
name string,
gimletHost string,
agentKey string,
) {
describer, ok := describe.DescriberFor(schema.GroupKind{Group: appsv1.GroupName, Kind: "Deployment"}, kubeEnv.Config)
var gvr schema.GroupVersionResource
var gvk schema.GroupVersionKind
switch resource {
case "Deployment":
gvr = schema.GroupVersionResource{
Group: "apps",
Version: "v1",
Resource: "deployments",
}
gvk = schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
}
case "Pod":
gvr = schema.GroupVersionResource{
Group: "",
Version: "v1",
Resource: "pods",
}
gvk = schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "Pod",
}
case "Terraform":
gvr = schema.GroupVersionResource{
Group: "infra.contrib.fluxcd.io",
Version: "v1alpha2",
Resource: "terraforms",
}
gvk = schema.GroupVersionKind{
Group: "infra.contrib.fluxcd.io",
Version: "v1alpha2",
Kind: "Terraform",
}
}

describer, ok := describe.GenericDescriberFor(
&meta.RESTMapping{
Resource: gvr,
GroupVersionKind: gvk,
Scope: meta.RESTScopeNamespace,
},
kubeEnv.Config,
)
if !ok {
logrus.Errorf("could not get describer for deployment")
logrus.Errorf("could not get describer for %s", resource)
return
}

output, err := describer.Describe(namespace, name, describe.DescriberSettings{ShowEvents: true, ChunkSize: 500})
output, err := describer.Describe(
namespace, name,
describe.DescriberSettings{ShowEvents: true, ChunkSize: 500},
)
if err != nil {
logrus.Errorf("could not get output of describer: %s", err)
return
}

deployment := api.Deployment{
result := api.DesrcribeResult{
Resource: resource,
Namespace: namespace,
Name: name,
Details: output,
Result: output,
}

deploymentString, err := json.Marshal(deployment)
resultString, err := json.Marshal(result)
if err != nil {
logrus.Errorf("could not serialize deployment: %v", err)
logrus.Errorf("could not serialize describe result: %v", err)
return
}

reqUrl := fmt.Sprintf("%s/agent/deploymentDetails", gimletHost)
req, err := http.NewRequest("POST", reqUrl, bytes.NewBuffer(deploymentString))
reqUrl := fmt.Sprintf("%s/agent/describeResult", gimletHost)
req, err := http.NewRequest("POST", reqUrl, bytes.NewBuffer(resultString))
if err != nil {
logrus.Errorf("could not create http request: %v", err)
return
Expand All @@ -483,18 +548,16 @@ func deploymentDetails(
client := httpClient()
resp, err := client.Do(req)
if err != nil {
logrus.Errorf("could not send deployment details: %s", err)
logrus.Errorf("could not send describe result: %s", err)
return
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
body, _ := ioutil.ReadAll(resp.Body)
logrus.Errorf("could not send deployment details: %d - %v", resp.StatusCode, string(body))
logrus.Errorf("could not send describe result: %d - %v", resp.StatusCode, string(body))
return
}

logrus.Debug("deployment details sent")
}

func reconcile(
Expand All @@ -507,63 +570,6 @@ func reconcile(
reconcileCommand.Run(kubeEnv.Config, namespace, name)
}

func podDetails(
kubeEnv *agent.KubeEnv,
namespace string,
name string,
gimletHost string,
agentKey string,
) {
describer, ok := describe.DescriberFor(schema.GroupKind{Group: v1.GroupName, Kind: "Pod"}, kubeEnv.Config)
if !ok {
logrus.Errorf("could not get describer for pod")
return
}

output, err := describer.Describe(namespace, name, describe.DescriberSettings{ShowEvents: true, ChunkSize: 500})
if err != nil {
logrus.Errorf("could not get output of describer: %s", err)
return
}

pod := api.Pod{
Namespace: namespace,
Name: name,
Details: output,
}

podString, err := json.Marshal(pod)
if err != nil {
logrus.Errorf("could not serialize pod: %v", err)
return
}

reqUrl := fmt.Sprintf("%s/agent/podDetails", gimletHost)
req, err := http.NewRequest("POST", reqUrl, bytes.NewBuffer(podString))
if err != nil {
logrus.Errorf("could not create http request: %v", err)
return
}
req.Header.Set("Authorization", "BEARER "+agentKey)
req.Header.Set("Content-Type", "application/json")

client := httpClient()
resp, err := client.Do(req)
if err != nil {
logrus.Errorf("could not send deployment details: %s", err)
return
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
body, _ := ioutil.ReadAll(resp.Body)
logrus.Errorf("could not send deployment details: %d - %v", resp.StatusCode, string(body))
return
}

logrus.Debug("deployment details sent")
}

func restartDeployment(kubeEnv *agent.KubeEnv, namespace, name string) {
data := fmt.Sprintf(`{"spec": {"template": {"metadata": {"annotations": {"kubectl.kubernetes.io/restartedAt": "%s"}}}}}`, time.Now().Format(time.RFC3339))
_, err := kubeEnv.Client.AppsV1().Deployments(namespace).Patch(context.TODO(), name, types.StrategicMergePatchType, []byte(data), meta_v1.PatchOptions{})
Expand Down
6 changes: 6 additions & 0 deletions cmd/dashboard/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
)

const DEFAULT_CHARTS = "title=Web application template,description=Deploy any web application. Multiple container image build options available.,name=onechart,repo=https://chart.onechart.dev,version=0.70.0;title=static website template,description=If your build generates static files%2C we will host it in an Nginx container.,name=static-site,repo=https://chart.onechart.dev,version=0.70.0"
const DEFAULT_PLAIN_MODULES_URL = "https://raw.githubusercontent.com/gimlet-io/gimlet/refs/heads/move-to-tofu-controller/dependency-catalog.yaml"

// LoadConfig returns the static config from the environment.
func LoadConfig() (*Config, error) {
Expand All @@ -35,6 +36,9 @@ func defaults(c *Config) {
if c.DefaultCharts == nil {
c.DefaultCharts.Decode(DEFAULT_CHARTS)
}
if c.DependencyCatalogURL == "" {
c.DependencyCatalogURL = DEFAULT_PLAIN_MODULES_URL
}
if c.GitSSHAddressFormat == "" {
c.GitSSHAddressFormat = "[email protected]:%s.git"
}
Expand Down Expand Up @@ -118,6 +122,8 @@ type Config struct {

Instance string `envconfig:"INSTANCE"`
License string `envconfig:"LICENSE"`

DependencyCatalogURL string `envconfig:"DEPENDENCY_CATALOG_URL"`
}

// Logging provides the logging configuration.
Expand Down
12 changes: 6 additions & 6 deletions cmd/dashboard/initBuiltInEnv.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/gimlet-io/gimlet/pkg/dashboard/model"
"github.com/gimlet-io/gimlet/pkg/dashboard/server"
"github.com/gimlet-io/gimlet/pkg/dashboard/store"
"github.com/gimlet-io/gimlet/pkg/git/nativeGit"
"github.com/gimlet-io/gimlet/pkg/git/gogit"
"github.com/gimlet-io/gimlet/pkg/gitops"
"github.com/gimlet-io/gimlet/pkg/server/token"
"github.com/go-git/go-git/v5"
Expand Down Expand Up @@ -78,7 +78,7 @@ func bootstrapBuiltInEnv(
return fmt.Errorf("cannot get repo: %s", err)
}

headBranch, err := nativeGit.HeadBranch(repo)
headBranch, err := gogit.HeadBranch(repo)
if err != nil {
return fmt.Errorf("cannot get head branch: %s", err)
}
Expand Down Expand Up @@ -166,11 +166,11 @@ func initRepo(url string) (*git.Repository, string, error) {
return nil, tmpPath, fmt.Errorf("cannot init empty repo: %s", err)
}

err = nativeGit.StageFile(w, "", "README.md")
err = gogit.StageFile(w, "", "README.md")
if err != nil {
return nil, tmpPath, fmt.Errorf("cannot init empty repo: %s", err)
}
_, err = nativeGit.Commit(repo, "Init")
_, err = gogit.Commit(repo, "Init")
if err != nil {
return nil, tmpPath, fmt.Errorf("cannot init empty repo: %s", err)
}
Expand Down Expand Up @@ -215,12 +215,12 @@ func stageCommitAndPush(repo *git.Repository, tmpPath string, user string, passw
return err
}

_, err = nativeGit.Commit(repo, msg)
_, err = gogit.Commit(repo, msg)
if err != nil {
return err
}

err = nativeGit.PushWithBasicAuth(repo, user, password)
err = gogit.PushWithBasicAuth(repo, user, password)
if err != nil {
return err
}
Expand Down
Loading
Loading