github.com/profzone/eden-framework@v1.0.10/internal/generator/k8s_generator.go (about)

     1  package generator
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"github.com/profzone/eden-framework/internal/generator/files"
     7  	"github.com/profzone/eden-framework/internal/project"
     8  	"github.com/profzone/eden-framework/pkg/courier/transport_grpc"
     9  	"github.com/profzone/eden-framework/pkg/courier/transport_http"
    10  	"github.com/profzone/eden-framework/pkg/reflectx"
    11  	"github.com/sirupsen/logrus"
    12  	appsv1 "k8s.io/api/apps/v1"
    13  	apiv1 "k8s.io/api/core/v1"
    14  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    15  	"k8s.io/apimachinery/pkg/runtime/serializer/json"
    16  	"k8s.io/apimachinery/pkg/types"
    17  	"k8s.io/apimachinery/pkg/util/intstr"
    18  	"path"
    19  	"reflect"
    20  	"strings"
    21  )
    22  
    23  type K8sGenerator struct {
    24  	config []interface{}
    25  }
    26  
    27  func NewK8sGenerator(config []interface{}) *K8sGenerator {
    28  	return &K8sGenerator{
    29  		config: config,
    30  	}
    31  }
    32  
    33  func (d *K8sGenerator) Load(cwd string) {
    34  }
    35  
    36  func (d *K8sGenerator) Pick() {
    37  }
    38  
    39  func (d *K8sGenerator) Output(outputPath string) Outputs {
    40  	outputs := Outputs{}
    41  
    42  	serverPorts := findServerPorts(d.config)
    43  
    44  	// Deployment config file
    45  	deploymentConfig := &appsv1.Deployment{
    46  		TypeMeta: metav1.TypeMeta{
    47  			Kind:       "Deployment",
    48  			APIVersion: "apps/v1",
    49  		},
    50  		ObjectMeta: metav1.ObjectMeta{
    51  			Name:      files.EnvVar(project.EnvKeyProjectName),
    52  			Namespace: files.EnvVar(project.EnvKeyProjectGroup),
    53  		},
    54  		Spec: appsv1.DeploymentSpec{
    55  			Replicas: int2Ptr(1),
    56  			Selector: &metav1.LabelSelector{
    57  				MatchLabels: map[string]string{
    58  					"workload.user.cattle.io/workloadselector": files.EnvVar(project.EnvKeyProjectSelector),
    59  				},
    60  			},
    61  			Template: apiv1.PodTemplateSpec{
    62  				ObjectMeta: metav1.ObjectMeta{
    63  					Labels: map[string]string{
    64  						"workload.user.cattle.io/workloadselector": files.EnvVar(project.EnvKeyProjectSelector),
    65  					},
    66  				},
    67  				Spec: apiv1.PodSpec{
    68  					Containers: []apiv1.Container{
    69  						{
    70  							Name: files.EnvVar(project.EnvKeyProjectName),
    71  							Image: fmt.Sprintf("%s/%s/%s:%s",
    72  								files.EnvVar(project.EnvKeyDockerRegistryKey),
    73  								files.EnvVar(project.EnvKeyProjectGroup),
    74  								files.EnvVar(project.EnvKeyProjectName),
    75  								files.EnvVar(project.EnvKeyProjectVersion),
    76  							),
    77  							ImagePullPolicy: apiv1.PullAlways,
    78  							Ports:           []apiv1.ContainerPort{},
    79  						},
    80  					},
    81  					RestartPolicy: apiv1.RestartPolicyAlways,
    82  				},
    83  			},
    84  		},
    85  	}
    86  
    87  	// Service config file
    88  	serviceConfig := &apiv1.Service{
    89  		TypeMeta: metav1.TypeMeta{
    90  			Kind:       "Deployment",
    91  			APIVersion: "apps/v1",
    92  		},
    93  		ObjectMeta: metav1.ObjectMeta{
    94  			Name:      files.EnvVar(project.EnvKeyProjectName),
    95  			Namespace: files.EnvVar(project.EnvKeyProjectGroup),
    96  			OwnerReferences: []metav1.OwnerReference{
    97  				{
    98  					APIVersion: "apps/v1beta2",
    99  					Kind:       "Deployment",
   100  					Name:       files.EnvVar(project.EnvKeyProjectName),
   101  					UID:        types.UID(files.EnvVar(project.EnvKeyDeploymentUID)),
   102  				},
   103  			},
   104  		},
   105  		Spec: apiv1.ServiceSpec{
   106  			Selector: map[string]string{
   107  				"workload.user.cattle.io/workloadselector": files.EnvVar(project.EnvKeyProjectSelector),
   108  			},
   109  			Ports: []apiv1.ServicePort{},
   110  		},
   111  	}
   112  
   113  	for _, port := range serverPorts {
   114  		deploymentConfig.Spec.Template.Spec.Containers[0].Ports = append(deploymentConfig.Spec.Template.Spec.Containers[0].Ports, apiv1.ContainerPort{
   115  			Name:          fmt.Sprintf("tcp%d", port),
   116  			ContainerPort: port,
   117  			Protocol:      apiv1.ProtocolTCP,
   118  		})
   119  		serviceConfig.Spec.Ports = append(serviceConfig.Spec.Ports, apiv1.ServicePort{
   120  			Name:       fmt.Sprintf("tcp%d", port),
   121  			Protocol:   apiv1.ProtocolTCP,
   122  			Port:       port,
   123  			TargetPort: intstr.FromInt(int(port)),
   124  		})
   125  	}
   126  
   127  	serializer := json.NewSerializerWithOptions(json.DefaultMetaFactory, nil, nil, json.SerializerOptions{
   128  		Yaml:   true,
   129  		Pretty: true,
   130  		Strict: true,
   131  	})
   132  	deploymentBuffer := bytes.NewBuffer([]byte{})
   133  	err := serializer.Encode(deploymentConfig, deploymentBuffer)
   134  	if err != nil {
   135  		logrus.Panic(err)
   136  	}
   137  	serviceBuffer := bytes.NewBuffer([]byte{})
   138  	err = serializer.Encode(serviceConfig, serviceBuffer)
   139  	if err != nil {
   140  		logrus.Panic(err)
   141  	}
   142  
   143  	outputs.Add(path.Join(outputPath, "build/deploy.default.yml"), deploymentBuffer.String())
   144  	outputs.Add(path.Join(outputPath, "build/service.default.yml"), serviceBuffer.String())
   145  	return outputs
   146  }
   147  
   148  func findServerPorts(config []interface{}) (ports []int32) {
   149  	for _, c := range config {
   150  		val := reflect.ValueOf(c)
   151  
   152  		exampleNames := exampleServerFullTypeName()
   153  		EachFieldValue(val.Elem(), func(field reflect.Value) bool {
   154  			fullName := reflectx.FullTypeName(reflectx.FromRType(field.Type()))
   155  			for _, name := range exampleNames {
   156  				if strings.HasSuffix(fullName, name) {
   157  					field = reflectx.Indirect(field)
   158  					portVal := field.FieldByName("Port")
   159  					if !reflectx.IsEmptyValue(portVal) {
   160  						ports = append(ports, int32(portVal.Int()))
   161  					}
   162  				}
   163  			}
   164  
   165  			return true
   166  		})
   167  	}
   168  	return
   169  }
   170  
   171  func exampleServerFullTypeName() (names []string) {
   172  	exampleHttpServer := transport_http.ServeHTTP{}
   173  	exampleGrpcServer := transport_grpc.ServeGRPC{}
   174  
   175  	httpTyp := reflect.TypeOf(exampleHttpServer)
   176  	names = append(names, httpTyp.PkgPath()+"."+httpTyp.Name())
   177  	grpcTyp := reflect.TypeOf(exampleGrpcServer)
   178  	names = append(names, grpcTyp.PkgPath()+"."+grpcTyp.Name())
   179  	return
   180  }
   181  
   182  func EachFieldValue(val reflect.Value, walker func(value reflect.Value) bool) {
   183  	for i := 0; i < val.NumField(); i++ {
   184  		field := val.Field(i)
   185  		if !walker(field) {
   186  			break
   187  		}
   188  	}
   189  }