Skip to content

Commit

Permalink
Request kube apiserver directly from frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
momom-i committed Feb 24, 2022
1 parent ba06325 commit d02f3d8
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 46 deletions.
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ services:
- PORT=1212
- KUBE_SCHEDULER_SIMULATOR_ETCD_URL=http://simulator-etcd:2379
- FRONTEND_URL=http://localhost:3000
- KUBE_API_HOST=0.0.0.0
- KUBE_API_PORT=3131
ports:
- "1212:1212"
- "3131:3131"
restart: always
tty: true
networks:
Expand Down
8 changes: 5 additions & 3 deletions k8sapiserver/k8sapiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import (
)

// StartAPIServer starts API server, and it make panic when a error happen.
func StartAPIServer(kubeAPIServerURL string, etcdURL string) (*restclient.Config, func(), error) {
func StartAPIServer(kubeAPIServerURL, etcdURL, frontendURL string) (*restclient.Config, func(), error) {
h := &APIServerHolder{Initialized: make(chan struct{})}
handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
<-h.Initialized
Expand All @@ -61,7 +61,7 @@ func StartAPIServer(kubeAPIServerURL string, etcdURL string) (*restclient.Config
s.Start()
klog.Info("kube-apiserver is started on :", s.URL)

c := NewControlPlaneConfigWithOptions(s.URL, etcdURL)
c := NewControlPlaneConfigWithOptions(s.URL, etcdURL, frontendURL)

_, _, closeFn, err := startAPIServer(c, s, h)
if err != nil {
Expand Down Expand Up @@ -103,7 +103,7 @@ func defaultOpenAPIConfig() *openapicommon.Config {
}

//nolint:funlen
func NewControlPlaneConfigWithOptions(serverURL, etcdURL string) *controlplane.Config {
func NewControlPlaneConfigWithOptions(serverURL, etcdURL, frontendURL string) *controlplane.Config {
etcdOptions := options.NewEtcdOptions(storagebackend.NewDefaultConfig(uuid.New().String(), nil))
etcdOptions.StorageConfig.Transport.ServerList = []string{etcdURL}

Expand All @@ -130,6 +130,8 @@ func NewControlPlaneConfigWithOptions(serverURL, etcdURL string) *controlplane.C

genericConfig.SecureServing = &genericapiserver.SecureServingInfo{Listener: fakeLocalhost443Listener{}}

genericConfig.CorsAllowedOriginList = []string{frontendURL}

err = etcdOptions.ApplyWithStorageFactoryTo(storageFactory, genericConfig)
if err != nil {
panic(err)
Expand Down
2 changes: 1 addition & 1 deletion simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func startSimulator() error {
return xerrors.Errorf("get config: %w", err)
}

restclientCfg, apiShutdown, err := k8sapiserver.StartAPIServer(cfg.KubeAPIServerURL, cfg.EtcdURL)
restclientCfg, apiShutdown, err := k8sapiserver.StartAPIServer(cfg.KubeAPIServerURL, cfg.EtcdURL, cfg.FrontendURL)
if err != nil {
return xerrors.Errorf("start API server: %w", err)
}
Expand Down
23 changes: 23 additions & 0 deletions web/api/v1/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,26 @@ export const instance = axios.create({
baseURL,
withCredentials: true,
});

const namespace = "default";
export const namespaceURL = "namespaces/" + namespace;

export const k8sBaseURL = process.env.KUBE_API_SERVER_URL + "/api/v1/";
export const k8sInstance = axios.create({
baseURL: k8sBaseURL,
withCredentials: true,
});

export const k8sSchedulingBaseURL =
process.env.KUBE_API_SERVER_URL + "/apis/scheduling.k8s.io/v1/";
export const k8sSchedulingInstance = axios.create({
baseURL: k8sSchedulingBaseURL,
withCredentials: true,
});

export const k8sStorageBaseURL =
process.env.KUBE_API_SERVER_URL + "/apis/storage.k8s.io/v1/";
export const k8sStorageInstance = axios.create({
baseURL: k8sStorageBaseURL,
withCredentials: true,
});
36 changes: 30 additions & 6 deletions web/api/v1/node.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,50 @@
import { V1Node, V1NodeList } from "@kubernetes/client-node";
import { instance } from "@/api/v1/index";
import { k8sInstance } from "@/api/v1/index";

export const applyNode = async (req: V1Node, onError: (_: string) => void) => {
try {
const res = await instance.post<V1Node>(`/nodes`, req);
if (!req.metadata?.name) {
throw onError("metadata.name is not provided");
}
const res = await k8sInstance.patch<V1Node>(
`/nodes/${req.metadata.name}?fieldManager=simulator`,
req,
{ headers: { "Content-Type": "application/strategic-merge-patch+json" } }
);
return res.data;
} catch (e: any) {
onError(e);
try {
const res = await createNode(req, onError);
return res;
} catch (e: any) {
onError(e);
}
}
};

export const listNode = async () => {
const res = await instance.get<V1NodeList>(`/nodes`, {});
const res = await k8sInstance.get<V1NodeList>(`/nodes`, {});
return res.data;
};

export const getNode = async (name: string) => {
const res = await instance.get<V1Node>(`/nodes/${name}`, {});
const res = await k8sInstance.get<V1Node>(`/nodes/${name}`, {});
return res.data;
};

export const deleteNode = async (name: string) => {
const res = await instance.delete(`/nodes/${name}`, {});
const res = await k8sInstance.delete(`/nodes/${name}`, {});
return res.data;
};

const createNode = async (req: V1Node, onError: (_: string) => void) => {
try {
const res = await k8sInstance.post<V1Node>(
`/nodes?fieldManager=simulator`,
req
);
return res.data;
} catch (e: any) {
onError(e);
}
};
39 changes: 33 additions & 6 deletions web/api/v1/pod.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,53 @@
import { V1Pod, V1PodList } from "@kubernetes/client-node";
import { instance } from "@/api/v1/index";
import { k8sInstance, namespaceURL } from "@/api/v1/index";

export const applyPod = async (req: V1Pod, onError: (_: string) => void) => {
try {
const res = await instance.post<V1Pod>(`/pods`, req);
if (!req.metadata?.name) {
throw onError("metadata.name is not provided");
}
const res = await k8sInstance.patch<V1Pod>(
namespaceURL + `/pods/${req.metadata.name}?fieldManager=simulator`,
req,
{ headers: { "Content-Type": "application/strategic-merge-patch+json" } }
);
return res.data;
} catch (e: any) {
onError(e);
try {
const res = await createPod(req, onError);
return res;
} catch (e: any) {
onError(e);
}
}
};

export const listPod = async () => {
const res = await instance.get<V1PodList>(`/pods`, {});
const res = await k8sInstance.get<V1PodList>(namespaceURL + `/pods`, {});
return res.data;
};

export const getPod = async (name: string) => {
const res = await instance.get<V1Pod>(`/pods/${name}`, {});
const res = await k8sInstance.get<V1Pod>(namespaceURL + `/pods/${name}`, {});
return res.data;
};

export const deletePod = async (name: string) => {
const res = await instance.delete(`/pods/${name}`, {});
const res = await k8sInstance.delete(
namespaceURL + `/pods/${name}?gracePeriodSeconds=0`,
{}
);
return res.data;
};

const createPod = async (req: V1Pod, onError: (_: string) => void) => {
try {
const res = await k8sInstance.post<V1Pod>(
namespaceURL + `/pods?fieldManager=simulator`,
req
);
return res.data;
} catch (e: any) {
onError(e);
}
};
45 changes: 39 additions & 6 deletions web/api/v1/priorityclass.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,65 @@
import { V1PriorityClass, V1PriorityClassList } from "@kubernetes/client-node";
import { instance } from "@/api/v1/index";
import { k8sSchedulingInstance } from "@/api/v1/index";

export const applyPriorityClass = async (
req: V1PriorityClass,
onError: (_: string) => void
) => {
try {
const res = await instance.post<V1PriorityClass>(`/priorityclasses`, req);
if (!req.metadata?.name) {
throw onError("metadata.name is not provided");
}
const res = await k8sSchedulingInstance.patch<V1PriorityClass>(
`/priorityclasses/${req.metadata.name}?fieldManager=simulator`,
req,
{ headers: { "Content-Type": "application/strategic-merge-patch+json" } }
);
return res.data;
} catch (e: any) {
onError(e);
try {
const res = await createPriorityClass(req, onError);
return res;
} catch (e: any) {
onError(e);
}
}
};

export const listPriorityClass = async () => {
const res = await instance.get<V1PriorityClassList>(`/priorityclasses`, {});
const res = await k8sSchedulingInstance.get<V1PriorityClassList>(
`/priorityclasses`,
{}
);
return res.data;
};

export const getPriorityClass = async (name: string) => {
const res = await instance.get<V1PriorityClass>(
const res = await k8sSchedulingInstance.get<V1PriorityClass>(
`/priorityclasses/${name}`,
{}
);
return res.data;
};

export const deletePriorityClass = async (name: string) => {
const res = await instance.delete(`/priorityclasses/${name}`, {});
const res = await k8sSchedulingInstance.delete(
`/priorityclasses/${name}`,
{}
);
return res.data;
};

const createPriorityClass = async (
req: V1PriorityClass,
onError: (_: string) => void
) => {
try {
const res = await k8sSchedulingInstance.post<V1PriorityClass>(
`/priorityclasses?fieldManager=simulator`,
req
);
return res.data;
} catch (e: any) {
onError(e);
}
};
40 changes: 32 additions & 8 deletions web/api/v1/pv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,64 @@ import {
V1PersistentVolume,
V1PersistentVolumeList,
} from "@kubernetes/client-node";
import { instance } from "@/api/v1/index";
import { k8sInstance } from "@/api/v1/index";

export const applyPersistentVolume = async (
req: V1PersistentVolume,
onError: (_: string) => void
) => {
try {
const res = await instance.post<V1PersistentVolume>(
`/persistentvolumes`,
req
if (!req.metadata?.name) {
throw onError("metadata.name is not provided");
}
const res = await k8sInstance.patch<V1PersistentVolume>(
`/persistentvolumes/${req.metadata.name}?fieldManager=simulator`,
req,
{ headers: { "Content-Type": "application/strategic-merge-patch+json" } }
);
return res.data;
} catch (e: any) {
onError(e);
try {
const res = await createPersistentvolumes(req, onError);
return res;
} catch (e: any) {
onError(e);
}
}
};

export const listPersistentVolume = async () => {
const res = await instance.get<V1PersistentVolumeList>(
const res = await k8sInstance.get<V1PersistentVolumeList>(
`/persistentvolumes`,
{}
);
return res.data;
};

export const getPersistentVolume = async (name: string) => {
const res = await instance.get<V1PersistentVolume>(
const res = await k8sInstance.get<V1PersistentVolume>(
`/persistentvolumes/${name}`,
{}
);
return res.data;
};

export const deletePersistentVolume = async (name: string) => {
const res = await instance.delete(`/persistentvolumes/${name}`, {});
const res = await k8sInstance.delete(`/persistentvolumes/${name}`, {});
return res.data;
};

const createPersistentvolumes = async (
req: V1PersistentVolume,
onError: (_: string) => void
) => {
try {
const res = await k8sInstance.post<V1PersistentVolume>(
`/persistentvolumes?fieldManager=simulator`,
req
);
return res.data;
} catch (e: any) {
onError(e);
}
};
Loading

0 comments on commit d02f3d8

Please sign in to comment.