Newer
Older
nucleus "code.fbi.h-da.de/danet/gosdn/nucleus/errors"
"github.com/spf13/viper"
appv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// GRPC defines the grpc port used by the deployment
const GRPC = 55055
// HTTP defines the http port used by the deployment
const HTTP = 8080
var service *corev1.Service
var deployment *appv1.Deployment
var config *corev1.ConfigMap
kubeconfig, err := clientcmd.BuildConfigFromFlags("https://api.ocp.fbi.h-da.de:6443", "")
kubeconfig.BearerToken = os.Getenv("K8S_DEPLOY_TOKEN")
clientset, err := kubernetes.NewForConfig(kubeconfig)
if err != nil {
log.Fatal(err)
}
var tag string
switch os.Getenv("CI_COMMIT_BRANCH") {
tag = "latest"
case "develop":
tag = "develop"
default:
tag = os.Getenv("CI_COMMIT_SHA")
}
if err := create(clientset, tag); err != nil {
log.Fatal(err)
if err := remove(clientset, tag); err != nil {
log.Fatal(err)
case "getenv":
if err := getenv(clientset, tag); err != nil {
log.Fatal(err)
}
func getenv(clientset *kubernetes.Clientset, tag string) error {
env := "gosdn-" + tag
opts := metav1.GetOptions{}
ctx := context.Background()
service, err := clientset.CoreV1().Services("cocsn").Get(ctx, env, opts)
if err != nil {
return err
}
var ip string
for _, ingress := range service.Status.LoadBalancer.Ingress {
ip = ingress.IP
}
var port string
for _, p := range service.Spec.Ports {
if p.Name == "grpc" {
port = strconv.Itoa(int(p.NodePort))
}
}
log.WithFields(log.Fields{
"ip": ip,
"port": port,
}).Info(env)
viper.Set("GOSDN_TEST_API_ENDPOINT", ip+":"+port)
return viper.SafeWriteConfigAs(".k8s.toml")
}
func create(clientset *kubernetes.Clientset, tag string) error {
env := "gosdn-" + tag
deployment = createDeployment(env, tag)
opts := metav1.CreateOptions{}
ctx := context.Background()
_, err := clientset.AppsV1().Deployments("cocsn").Create(ctx, deployment, opts)
if err != nil {
switch err.(type) {
case *errors.StatusError:
if err.(*errors.StatusError).ErrStatus.Code == 409 {
if err := update(clientset, deployment, env); err != nil {
log.Error(err)
log.Printf("deployment %v created", deployment.Name)
deployment, err = clientset.AppsV1().Deployments("cocsn").Get(ctx, env, metav1.GetOptions{})
config = createConfigMap(env)
_, err = clientset.CoreV1().ConfigMaps("cocsn").Create(ctx, config, opts)
if err != nil {
switch err.(type) {
case *errors.StatusError:
if err.(*errors.StatusError).ErrStatus.Code == 409 {
if err := update(clientset, config, env); err != nil {
log.Error(err)
}
} else {
log.Error(err)
} else {
log.Printf("configMap %v created", config.Name)
service = createService(env)
_, err = clientset.CoreV1().Services("cocsn").Create(ctx, service, opts)
if err != nil {
switch err.(type) {
case *errors.StatusError:
if err.(*errors.StatusError).ErrStatus.Code == 409 {
if err := update(clientset, service, env); err != nil {
return err
log.Printf("service %v created", service.Name)
}
func update(clientset *kubernetes.Clientset, resource metav1.Common, env string) error {
opts := metav1.UpdateOptions{}
getOpts := metav1.GetOptions{}
ctx := context.Background()
s, err := clientset.CoreV1().Services("cocsn").Get(ctx, env, getOpts)
if err != nil {
return err
}
s.DeepCopyInto(service)
_, err = clientset.CoreV1().Services("cocsn").Update(ctx, service, opts)
if err != nil {
return err
}
c, err := clientset.CoreV1().ConfigMaps("cocsn").Get(ctx, env+"-config", getOpts)
if err != nil {
return err
}
c.DeepCopyInto(config)
_, err = clientset.CoreV1().ConfigMaps("cocsn").Update(ctx, config, opts)
if err != nil {
return err
}
d, err := clientset.AppsV1().Deployments("cocsn").Get(ctx, env, getOpts)
if err != nil {
return err
}
d.DeepCopyInto(deployment)
_, err = clientset.AppsV1().Deployments("cocsn").Update(ctx, deployment, opts)
if err != nil {
return err
}
log.Printf("deployment %v updated", deployment.Name)
default:
return &nucleus.ErrInvalidParameters{}
}
return nil
}
func remove(clientset *kubernetes.Clientset, tag string) error {
env := "gosdn-" + tag
opts := metav1.DeleteOptions{}
ctx := context.Background()
err := clientset.CoreV1().Services("cocsn").Delete(ctx, env, opts)
if err != nil {
log.Error(err)
} else {
log.Printf("service %v deleted", env)
}
err = clientset.CoreV1().ConfigMaps("cocsn").Delete(ctx, env+"-config", opts)
if err != nil {
log.Error(err)
} else {
log.Printf("config %v deleted", env+"-config")
}
err = clientset.AppsV1().Deployments("cocsn").Delete(ctx, env, opts)
if err != nil {
log.Error(err)
} else {
log.Printf("deployment %v deleted", env)
}
return err
}
func createService(environment string) *corev1.Service {
return &corev1.Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: environment,
Namespace: "cocsn",
Labels: map[string]string{"run": environment},
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: "v1",
Kind: "Deployment",
Name: environment,
UID: deployment.GetUID(),
},
},
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "http",
Port: HTTP,
TargetPort: intstr.IntOrString{IntVal: HTTP},
Port: GRPC,
TargetPort: intstr.IntOrString{IntVal: GRPC},
Selector: map[string]string{"run": environment},
Type: "LoadBalancer",
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
},
}
}
func createDeployment(environment, hash string) *appv1.Deployment {
return &appv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: environment,
},
Spec: appv1.DeploymentSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"run": environment},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"run": environment},
},
Spec: corev1.PodSpec{
Volumes: []corev1.Volume{
{
Name: "gosdn-config-volume",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
},
},
},
},
},
Containers: []corev1.Container{
{
Name: "gosdn",
Image: "registry.code.fbi.h-da.de/danet/gosdn:" + hash,
Command: nil,
Args: nil,
WorkingDir: "",
Ports: []corev1.ContainerPort{
{
Name: "grpc",
ContainerPort: GRPC,
ContainerPort: HTTP,
},
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "gosdn-config-volume",
MountPath: "/usr/local/etc/gosdn/gosdn.toml",
},
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/livez",
Port: intstr.IntOrString{IntVal: HTTP},
PeriodSeconds: 2,
},
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/readyz",
Port: intstr.IntOrString{IntVal: HTTP},
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
PeriodSeconds: 2,
},
ImagePullPolicy: "Always",
},
},
ImagePullSecrets: []corev1.LocalObjectReference{
{Name: "k8s-gosdn-test"},
},
},
},
Strategy: appv1.DeploymentStrategy{
Type: "RollingUpdate",
RollingUpdate: &appv1.RollingUpdateDeployment{},
},
},
}
}
func createConfigMap(env string) *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: env + "-config",
OwnerReferences: []metav1.OwnerReference{
APIVersion: "v1",
Kind: "Deployment",
Name: env,
UID: deployment.GetUID(),
Data: map[string]string{"gosdn.toml": "#empty"},