[ADD] add new app runtime conversion code

This commit is contained in:
barnett 2018-11-14 23:08:30 +08:00
parent 2935ee9191
commit f178a0e213
21 changed files with 1406 additions and 23 deletions

View File

@ -397,3 +397,9 @@ type AppBackupDao interface {
GetDeleteAppBackup(backupID string) (*model.AppBackup, error)
GetDeleteAppBackups() ([]*model.AppBackup, error)
}
//ServiceSourceDao service source dao
type ServiceSourceDao interface {
Dao
GetServiceSource(serviceID string) ([]*model.ServiceSourceConfig, error)
}

View File

@ -20,6 +20,7 @@ package db
import (
"errors"
"fmt"
"github.com/goodrain/rainbond/db/config"
"github.com/goodrain/rainbond/db/dao"
@ -102,6 +103,7 @@ type Manager interface {
NotificationEventDao() dao.NotificationEventDao
AppBackupDao() dao.AppBackupDao
ServiceSourceDao() dao.ServiceSourceDao
}
var defaultManager Manager
@ -110,11 +112,12 @@ var defaultManager Manager
func CreateManager(config config.Config) (err error) {
if config.DBType == "mysql" || config.DBType == "cockroachdb" {
defaultManager, err = mysql.CreateManager(config)
return err
} else {
//TODO:etcd 插件实现
//defaultManager, err = etcd.CreateManager(config)
}
return
return fmt.Errorf("Db drivers not supported")
}
//CloseManager 关闭

View File

@ -117,3 +117,17 @@ type LocalScheduler struct {
func (t *LocalScheduler) TableName() string {
return "local_scheduler"
}
//ServiceSourceConfig service source config info
//such as deployment、statefulset、configmap
type ServiceSourceConfig struct {
Model
ServiceID string `gorm:"column:service_id;size:32"`
SourceType string `gorm:"column:source_type;size:32"`
SourceBody string `gorm:"column:source_body;size:2000"`
}
//TableName 表名
func (t *ServiceSourceConfig) TableName() string {
return "tenant_service_source"
}

View File

@ -48,9 +48,9 @@ type Interface interface {
//Tenants 租户信息
type Tenants struct {
Model
Name string `gorm:"column:name;size:40;unique_index"`
UUID string `gorm:"column:uuid;size:33;unique_index"`
EID string `gorm:"column:eid"`
Name string `gorm:"column:name;size:40;unique_index"`
UUID string `gorm:"column:uuid;size:33;unique_index"`
EID string `gorm:"column:eid"`
LimitMemory int `gorm:"column:limit_memory"`
}
@ -59,7 +59,7 @@ func (t *Tenants) TableName() string {
return "tenants"
}
//TenantServices 租户应用
//TenantServices app service base info
type TenantServices struct {
Model
TenantID string `gorm:"column:tenant_id;size:32" json:"tenant_id"`
@ -68,25 +68,27 @@ type TenantServices struct {
ServiceKey string `gorm:"column:service_key;size:32" json:"service_key"`
// 服务别名
ServiceAlias string `gorm:"column:service_alias;size:30" json:"service_alias"`
// service regist endpoint name(host name), used of statefulset
ServiceName string `gorm:"column:service_name;size:100" json:"service_name"`
// 服务描述
Comment string `gorm:"column:comment" json:"comment"`
// 服务版本
// 服务版本(deprecated)
ServiceVersion string `gorm:"column:service_version;size:32" json:"service_version"`
// 镜像名称
// 镜像名称(deprecated)
ImageName string `gorm:"column:image_name;size:100" json:"image_name"`
// 容器CPU权重
ContainerCPU int `gorm:"column:container_cpu;default:500" json:"container_cpu"`
// 容器最大内存
ContainerMemory int `gorm:"column:container_memory;default:128" json:"container_memory"`
// 容器启动命令
// 容器启动命令(deprecated)
ContainerCMD string `gorm:"column:container_cmd;size:2048" json:"container_cmd"`
// 容器环境变量
// 容器环境变量(deprecated)
ContainerEnv string `gorm:"column:container_env;size:255" json:"container_env"`
// 卷名字
// 卷名字 (deprecated)
VolumePath string `gorm:"column:volume_path" json:"volume_path"`
// 容器挂载目录
// 容器挂载目录 (deprecated)
VolumeMountPath string `gorm:"column:volume_mount_path" json:"volume_mount_path"`
// 宿主机目录
// 宿主机目录 (deprecated)
HostPath string `gorm:"column:host_path" json:"host_path"`
// 扩容方式0:无状态1:有状态2:分区
ExtendMethod string `gorm:"column:extend_method;default:'stateless';" json:"extend_method"`
@ -96,27 +98,27 @@ type TenantServices struct {
DeployVersion string `gorm:"column:deploy_version" json:"deploy_version"`
// 服务分类application,cache,store
Category string `gorm:"column:category" json:"category"`
// 服务当前状态undeploy,running,closed,unusual,starting,checking,stoping
// 服务当前状态undeploy,running,closed,unusual,starting,checking,stoping(deprecated)
CurStatus string `gorm:"column:cur_status;default:'undeploy'" json:"cur_status"`
// 计费状态 为1 计费为0不计费
// 计费状态 为1 计费为0不计费 (deprecated)
Status int `gorm:"column:status;default:0" json:"status"`
// 最新操作ID
EventID string `gorm:"column:event_id" json:"event_id"`
// 服务类型
// 服务类型 (deprecated)
ServiceType string `gorm:"column:service_type" json:"service_type"`
// 镜像来源
// 租户ID
Namespace string `gorm:"column:namespace" json:"namespace"`
// 共享类型shared、exclusive
// 共享类型shared、exclusive(deprecated)
VolumeType string `gorm:"column:volume_type;default:'shared'" json:"volume_type"`
// 端口类型one_outer;dif_protocol;multi_outer
// 端口类型one_outer;dif_protocol;multi_outer (deprecated)
PortType string `gorm:"column:port_type;default:'multi_outer'" json:"port_type"`
// 更新时间
UpdateTime time.Time `gorm:"column:update_time" json:"update_time"`
// 服务创建类型cloud云市服务,assistant云帮服务
ServiceOrigin string `gorm:"column:service_origin;default:'assistant'" json:"service_origin"`
// 代码来源:gitlab,github
// 代码来源:gitlab,github (deprecated)
CodeFrom string `gorm:"column:code_from" json:"code_from"`
//(deprecated)
Domain string `gorm:"column:domain" json:"domain"`
}
@ -204,6 +206,8 @@ type TenantServicesDelete struct {
ServiceKey string `gorm:"column:service_key;size:32" json:"service_key"`
// 服务别名
ServiceAlias string `gorm:"column:service_alias;size:30" json:"service_alias"`
// service regist endpoint name(host name), used of statefulset
ServiceName string `gorm:"column:service_name;size:100" json:"service_name"`
// 服务描述
Comment string `gorm:"column:comment" json:"comment"`
// 服务版本

View File

@ -35,7 +35,8 @@ type VersionInfo struct {
//slug: this is a source code tar file
DeliveredType string `gorm:"column:delivered_type;size:40"` //kind
DeliveredPath string `gorm:"column:delivered_path;size:250"` //交付物path
ImageName string `gorm:"column:image_name;size:250"` //交付物path
ImageName string `gorm:"column:image_name;size:250"` //运行镜像名称
Cmd string `gorm:"column:cmd;size:200"` //启动命令
RepoURL string `gorm:"column:repo_url;size:100"`
CodeVersion string `gorm:"column:code_version;size:40"`
CommitMsg string `gorm:"column:code_commit_msg;size:200"`

View File

@ -469,3 +469,44 @@ func (t *LocalSchedulerDaoImpl) GetLocalScheduler(serviceID string) ([]*model.Lo
}
return ls, nil
}
//ServiceSourceImpl service source
type ServiceSourceImpl struct {
DB *gorm.DB
}
//AddModel add service source
func (t *ServiceSourceImpl) AddModel(mo model.Interface) error {
ls := mo.(*model.ServiceSourceConfig)
var oldLs model.ServiceSourceConfig
if ok := t.DB.Where("service_id=? and source_type=?", ls.ServiceID, ls.SourceType).Find(&oldLs).RecordNotFound(); ok {
if err := t.DB.Create(ls).Error; err != nil {
return err
}
} else {
oldLs.SourceBody = ls.SourceBody
t.DB.Save(oldLs)
}
return nil
}
//UpdateModel update service source
func (t *ServiceSourceImpl) UpdateModel(mo model.Interface) error {
ls := mo.(*model.LocalScheduler)
if ls.ID == 0 {
return fmt.Errorf("ServiceSourceImpl id can not be empty when update ")
}
if err := t.DB.Save(ls).Error; err != nil {
return err
}
return nil
}
//GetServiceSource get services source
func (t *ServiceSourceImpl) GetServiceSource(serviceID string) ([]*model.ServiceSourceConfig, error) {
var serviceSources []*model.ServiceSourceConfig
if err := t.DB.Where("service_id=?", serviceID).Find(&serviceSources).Error; err != nil {
return nil, err
}
return serviceSources, nil
}

View File

@ -458,3 +458,10 @@ func (m *Manager) AppBackupDao() dao.AppBackupDao {
DB: m.db,
}
}
//ServiceSourceDao service source db impl
func (m *Manager) ServiceSourceDao() dao.ServiceSourceDao {
return &mysqldao.ServiceSourceImpl{
DB: m.db,
}
}

View File

@ -118,6 +118,7 @@ func (m *Manager) RegisterTableModel() {
m.models = append(m.models, &model.NotificationEvent{})
m.models = append(m.models, &model.AppStatus{})
m.models = append(m.models, &model.AppBackup{})
m.models = append(m.models, &model.ServiceSourceConfig{})
}
//CheckTable check and create tables

View File

@ -0,0 +1,64 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package conversion
import (
"github.com/goodrain/rainbond/db"
v1 "github.com/goodrain/rainbond/worker/appm/types/v1"
)
func init() {
//first conv service source
RegistConversion(ServiceSource)
//step2 conv service base
RegistConversion(TenantServiceBase)
//step3 conv service pod base info
RegistConversion(TenantServiceVersion)
//step4 conv service plugin
RegistConversion(TenantServicePlugin)
//step5 conv service inner and outer regist
RegistConversion(TenantServiceRegist)
}
//Conversion conversion function
//Any application attribute implementation is similarly injected
type Conversion func(*v1.AppService, db.Manager) error
//conversionList conversion function list
var conversionList []Conversion
//RegistConversion regist conversion function list
func RegistConversion(fun Conversion) {
conversionList = append(conversionList, fun)
}
//InitAppService init a app service
func InitAppService(dbmanager db.Manager, serviceID string) (*v1.AppService, error) {
appService := &v1.AppService{
AppServiceBase: v1.AppServiceBase{
ServiceID: serviceID,
},
}
for _, c := range conversionList {
if err := c(appService, dbmanager); err != nil {
return nil, err
}
}
return appService, nil
}

View File

@ -0,0 +1,42 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package conversion
import (
"testing"
"github.com/goodrain/rainbond/db/config"
"github.com/goodrain/rainbond/db"
)
func TestInitAppService(t *testing.T) {
err := db.CreateManager(config.Config{
MysqlConnectionInfo: "root:ASDASDASDASDASD@tcp(ali-sh-s1.goodrain.net:21194)/region",
DBType: "mysql",
})
if err != nil {
t.Fatal(err)
}
as, err := InitAppService(db.GetManager(), "")
if err != nil {
t.Fatal(err)
}
t.Log(as)
}

View File

@ -0,0 +1,49 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package conversion
import (
"fmt"
"os"
"strings"
"github.com/goodrain/rainbond/db"
v1 "github.com/goodrain/rainbond/worker/appm/types/v1"
)
//createDefaultDomain create default domain
func createDefaultDomain(tenantName, serviceAlias string, servicePort int) string {
exDomain := os.Getenv("EX_DOMAIN")
if exDomain == "" {
return ""
}
if strings.Contains(exDomain, ":") {
exDomain = strings.Split(exDomain, ":")[0]
}
if exDomain[0] == '.' {
exDomain = exDomain[1:]
}
exDomain = strings.TrimSpace(exDomain)
return fmt.Sprintf("%d.%s.%s.%s", servicePort, serviceAlias, tenantName, exDomain)
}
//TenantServiceRegist conv inner and outer service regist
func TenantServiceRegist(as *v1.AppService, dbmanager db.Manager) error {
return nil
}

View File

@ -0,0 +1,30 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package conversion
func getCommonLable(labels ...map[string]string) map[string]string {
var resultLabel = make(map[string]string)
for _, l := range labels {
for k, v := range l {
resultLabel[k] = v
}
}
resultLabel["creater"] = "Rainbond"
return resultLabel
}

View File

@ -0,0 +1,29 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package conversion
import (
"github.com/goodrain/rainbond/db"
v1 "github.com/goodrain/rainbond/worker/appm/types/v1"
)
//TenantServicePlugin conv service all plugin
func TenantServicePlugin(as *v1.AppService, dbmanager db.Manager) error {
return nil
}

View File

@ -0,0 +1,158 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package conversion
import (
"fmt"
"strings"
"github.com/goodrain/rainbond/db"
dbmodel "github.com/goodrain/rainbond/db/model"
"github.com/goodrain/rainbond/util"
v1 "github.com/goodrain/rainbond/worker/appm/types/v1"
"github.com/jinzhu/gorm"
yaml "gopkg.in/yaml.v2"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
//ServiceSource conv ServiceSource
func ServiceSource(as *v1.AppService, dbmanager db.Manager) error {
sscs, err := dbmanager.ServiceSourceDao().GetServiceSource(as.ServiceID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil
}
return fmt.Errorf("conv service source failure %s", err.Error())
}
for _, ssc := range sscs {
switch ssc.SourceType {
case "deployment":
var dm appsv1.Deployment
if err := decoding(ssc.SourceBody, &dm); err != nil {
return decodeError(err)
}
as.SetDeployment(&dm)
case "statefulset":
var ss appsv1.StatefulSet
if err := decoding(ssc.SourceBody, &ss); err != nil {
return decodeError(err)
}
as.SetStatefulSet(&ss)
case "configmap":
var cm corev1.ConfigMap
if err := decoding(ssc.SourceBody, &cm); err != nil {
return decodeError(err)
}
as.SetConfigMap(&cm)
}
}
return nil
}
func decodeError(err error) error {
return fmt.Errorf("decode service source failure %s", err.Error())
}
func decoding(source string, target interface{}) error {
return yaml.Unmarshal([]byte(source), target)
}
func int32Ptr(i int) *int32 {
j := int32(i)
return &j
}
//TenantServiceBase conv tenant service base info
func TenantServiceBase(as *v1.AppService, dbmanager db.Manager) error {
tenantService, err := dbmanager.TenantServiceDao().GetServiceByID(as.ServiceID)
if err != nil {
return fmt.Errorf("get service base info failure %s", err.Error())
}
tenant, err := dbmanager.TenantDao().GetTenantByUUID(tenantService.TenantID)
if err != nil {
return fmt.Errorf("get tenant info failure %s", err.Error())
}
serviceType, err := dbmanager.TenantServiceLabelDao().GetTenantServiceTypeLabel(as.ServiceID)
if err != nil {
return fmt.Errorf("get service type info failure %s", err.Error())
}
as.TenantID = tenantService.TenantID
as.DeployVersion = tenantService.DeployVersion
as.ContainerCPU = tenantService.ContainerCPU
as.ContainerMemory = tenantService.ContainerMemory
as.Replicas = tenantService.Replicas
as.ServiceAlias = tenantService.ServiceAlias
as.CreaterID = util.NewUUID()
as.TenantName = tenant.Name
if serviceType.LabelValue == util.StatefulServiceType {
as.ServiceType = v1.TypeStatefulSet
statefulset := as.GetStatefulSet()
if statefulset == nil {
statefulset = &appsv1.StatefulSet{}
}
initBaseStatefulSet(tenantService, statefulset)
as.SetStatefulSet(statefulset)
}
if serviceType.LabelValue == util.StatelessServiceType {
as.ServiceType = v1.TypeDeployment
deployment := as.GetDeployment()
if deployment == nil {
deployment = &appsv1.Deployment{}
}
initBaseDeployment(tenantService, deployment)
as.SetDeployment(deployment)
}
return nil
}
func initSelector(selector *metav1.LabelSelector, service *dbmodel.TenantServices) {
selector.MatchLabels["name"] = service.ServiceAlias
selector.MatchLabels["version"] = service.DeployVersion
}
func initBaseStatefulSet(service *dbmodel.TenantServices, stateful *appsv1.StatefulSet) {
stateful.Spec.Replicas = int32Ptr(service.Replicas)
if stateful.Spec.Selector == nil {
stateful.Spec.Selector = &metav1.LabelSelector{}
}
initSelector(stateful.Spec.Selector, service)
stateful.Spec.ServiceName = service.ServiceName
stateful.Namespace = service.TenantID
stateful.Name = service.ServiceAlias
stateful.GenerateName = service.ServiceAlias
stateful.Labels = getCommonLable(stateful.Labels, map[string]string{
"name": service.ServiceAlias,
"version": service.DeployVersion,
"service_id": service.ServiceID,
})
}
func initBaseDeployment(service *dbmodel.TenantServices, deploymemnt *appsv1.Deployment) {
deploymemnt.Spec.Replicas = int32Ptr(service.Replicas)
if deploymemnt.Spec.Selector == nil {
deploymemnt.Spec.Selector = &metav1.LabelSelector{}
}
initSelector(deploymemnt.Spec.Selector, service)
deploymemnt.Namespace = service.TenantID
deploymemnt.Name = util.NewUUID()
deploymemnt.GenerateName = strings.Replace(service.ServiceAlias, "_", "-", -1)
deploymemnt.Labels = getCommonLable(deploymemnt.Labels, map[string]string{
"name": service.ServiceAlias,
"version": service.DeployVersion,
"service_id": service.ServiceID,
})
}

View File

@ -0,0 +1,601 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package conversion
import (
"fmt"
"os"
"regexp"
"strconv"
"strings"
"github.com/Sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/api/resource"
"github.com/goodrain/rainbond/db"
dbmodel "github.com/goodrain/rainbond/db/model"
"github.com/goodrain/rainbond/util"
v1 "github.com/goodrain/rainbond/worker/appm/types/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
//TenantServiceVersion service deploy version conv. define pod spec
func TenantServiceVersion(as *v1.AppService, dbmanager db.Manager) error {
version, err := dbmanager.VersionInfoDao().GetVersionByDeployVersion(as.DeployVersion, as.ServiceID)
if err != nil {
return fmt.Errorf("get service deploy version failure %s", err.Error())
}
dv, err := createVolumes(as, version, dbmanager)
if err != nil {
return fmt.Errorf("create volume in pod template error :%s", err.Error())
}
container, err := getMainContainer(as, version, dv, dbmanager)
if err != nil {
return fmt.Errorf("conv service envs failure %s", err.Error())
}
podtmpSpec := corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Volumes: dv.GetVolumes(),
Containers: []corev1.Container{*container},
NodeSelector: createNodeSelector(as, dbmanager),
Affinity: createAffinity(as, dbmanager),
},
}
//set annotations feature by env
setFeature(&podtmpSpec)
//set to deployment or statefulset
as.SetPodTemplate(podtmpSpec)
return nil
}
func getMainContainer(as *v1.AppService, version *dbmodel.VersionInfo, dv *volumeDefine, dbmanager db.Manager) (*corev1.Container, error) {
envs, err := createEnv(as, dbmanager)
if err != nil {
return nil, fmt.Errorf("conv service envs failure %s", err.Error())
}
args := createArgs(version, *envs)
resources := createResources(as)
ports := createPorts(as, dbmanager)
return &corev1.Container{
Name: as.ServiceID,
Image: version.ImageName,
Args: args,
Ports: ports,
Env: *envs,
VolumeMounts: dv.GetVolumeMounts(),
LivenessProbe: createProbe(as, dbmanager, "liveness"),
ReadinessProbe: createProbe(as, dbmanager, "readiness"),
Resources: resources,
}, nil
}
//GetConfigKey 获取配置key
func GetConfigKey(rk string) string {
if len(rk) < 4 {
return ""
}
left := strings.Index(rk, "{")
right := strings.Index(rk, "}")
return rk[left+1 : right]
}
func getenv(key string, envs []corev1.EnvVar) string {
for _, env := range envs {
if env.Name == key {
return env.Value
}
}
return ""
}
func createArgs(version *dbmodel.VersionInfo, envs []corev1.EnvVar) (args []string) {
if version.Cmd == "" {
return
}
cmd := version.Cmd
var reg = regexp.MustCompile(`(?U)\$\{.*\}`)
resultKey := reg.FindAllString(cmd, -1)
for _, rk := range resultKey {
value := getenv(GetConfigKey(rk), envs)
cmd = strings.Replace(cmd, rk, value, -1)
}
args = strings.Split(cmd, " ")
args = util.RemoveSpaces(args)
return args
}
//createEnv create service container env
func createEnv(as *v1.AppService, dbmanager db.Manager) (*[]corev1.EnvVar, error) {
var envs []corev1.EnvVar
var envsAll []*dbmodel.TenantServiceEnvVar
//set relation app outer env
relations, err := dbmanager.TenantServiceRelationDao().GetTenantServiceRelations(as.ServiceID)
if err != nil {
return nil, err
}
if relations != nil && len(relations) > 0 {
var relationIDs []string
for _, r := range relations {
relationIDs = append(relationIDs, r.DependServiceID)
}
if len(relationIDs) > 0 {
es, err := dbmanager.TenantServiceEnvVarDao().GetDependServiceEnvs(relationIDs, []string{"outer", "both"})
if err != nil {
return nil, err
}
if es != nil {
envsAll = append(envsAll, es...)
}
serviceAliass, err := dbmanager.TenantServiceDao().GetServiceAliasByIDs(relationIDs)
if err != nil {
return nil, err
}
var Depend string
for _, sa := range serviceAliass {
if Depend != "" {
Depend += ","
}
Depend += fmt.Sprintf("%s:%s", sa.ServiceAlias, sa.ServiceID)
}
envs = append(envs, corev1.EnvVar{Name: "DEPEND_SERVICE", Value: Depend})
as.NeedProxy = true
}
}
//set app relation env
relations, err = dbmanager.TenantServiceRelationDao().GetTenantServiceRelationsByDependServiceID(as.ServiceID)
if err != nil {
return nil, err
}
if relations != nil && len(relations) > 0 {
var relationIDs []string
for _, r := range relations {
relationIDs = append(relationIDs, r.ServiceID)
}
if len(relationIDs) > 0 {
serviceAliass, err := dbmanager.TenantServiceDao().GetServiceAliasByIDs(relationIDs)
if err != nil {
return nil, err
}
var Depend string
for _, sa := range serviceAliass {
if Depend != "" {
Depend += ","
}
Depend += fmt.Sprintf("%s:%s", sa.ServiceAlias, sa.ServiceID)
}
envs = append(envs, corev1.EnvVar{Name: "REVERSE_DEPEND_SERVICE", Value: Depend})
}
}
//set app port and net env
ports, err := dbmanager.TenantServicesPortDao().GetPortsByServiceID(as.ServiceID)
if err != nil {
return nil, err
}
if ports != nil && len(ports) > 0 {
var portStr string
for i, port := range ports {
if i == 0 {
envs = append(envs, corev1.EnvVar{Name: "PORT", Value: strconv.Itoa(ports[0].ContainerPort)})
envs = append(envs, corev1.EnvVar{Name: "PROTOCOL", Value: ports[0].Protocol})
}
if portStr != "" {
portStr += ":"
}
portStr += fmt.Sprintf("%d", port.ContainerPort)
if port.IsOuterService && (port.Protocol == "http" || port.Protocol == "https") {
envs = append(envs, corev1.EnvVar{Name: fmt.Sprintf("DEFAULT_DOMAIN_%d", port.ContainerPort), Value: createDefaultDomain(as.TenantName, as.ServiceAlias, port.ContainerPort)})
}
}
envs = append(envs, corev1.EnvVar{Name: "MONITOR_PORT", Value: portStr})
}
//set net mode env by get from system
envs = append(envs, corev1.EnvVar{Name: "CUR_NET", Value: os.Getenv("CUR_NET")})
//set app custom envs
es, err := dbmanager.TenantServiceEnvVarDao().GetServiceEnvs(as.ServiceID, []string{"inner", "both", "outer"})
if err != nil {
return nil, err
}
if len(es) > 0 {
envsAll = append(envsAll, es...)
}
for _, e := range envsAll {
envs = append(envs, corev1.EnvVar{Name: e.AttrName, Value: e.AttrValue})
}
//set default env
envs = append(envs, corev1.EnvVar{Name: "TENANT_ID", Value: as.TenantID})
envs = append(envs, corev1.EnvVar{Name: "SERVICE_ID", Value: as.ServiceID})
envs = append(envs, corev1.EnvVar{Name: "MEMORY_SIZE", Value: getMemoryType(as.ContainerMemory)})
envs = append(envs, corev1.EnvVar{Name: "SERVICE_NAME", Value: as.ServiceAlias})
envs = append(envs, corev1.EnvVar{Name: "SERVICE_POD_NUM", Value: strconv.Itoa(as.Replicas)})
envs = append(envs, corev1.EnvVar{Name: "HOST_IP", ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "status.hostIP",
},
}})
envs = append(envs, corev1.EnvVar{Name: "POD_IP", ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "status.podIP",
},
}})
return &envs, nil
}
func getMemoryType(memorySize int) string {
memoryType := "small"
if v, ok := memoryLabels[memorySize]; ok {
memoryType = v
}
return memoryType
}
var memoryLabels = map[int]string{
128: "micro",
256: "small",
512: "medium",
1024: "large",
2048: "2xlarge",
4096: "4xlarge",
8192: "8xlarge",
16384: "16xlarge",
32768: "32xlarge",
65536: "64xlarge",
}
func createVolumes(as *v1.AppService, version *dbmodel.VersionInfo, dbmanager db.Manager) (*volumeDefine, error) {
var vd = &volumeDefine{}
vs, err := dbmanager.TenantServiceVolumeDao().GetTenantServiceVolumesByServiceID(version.ServiceID)
if err != nil {
return nil, err
}
if vs != nil && len(vs) > 0 {
for i := range vs {
v := vs[i]
if v.VolumeType == dbmodel.ShareFileVolumeType.String() {
err := util.CheckAndCreateDir(v.HostPath)
if err != nil {
return nil, fmt.Errorf("create host path %s error,%s", v.HostPath, err.Error())
}
os.Chmod(v.HostPath, 0777)
}
vd.SetVolume(dbmodel.VolumeType(v.VolumeType), fmt.Sprintf("manual%d", v.ID), v.VolumePath, v.HostPath, v.IsReadOnly)
}
}
//handle Shared storage
tsmr, err := dbmanager.TenantServiceMountRelationDao().GetTenantServiceMountRelationsByService(version.ServiceID)
if err != nil {
return nil, err
}
if vs != nil && len(tsmr) > 0 {
for i := range tsmr {
t := tsmr[i]
err := util.CheckAndCreateDir(t.HostPath)
if err != nil {
return nil, fmt.Errorf("create host path %s error,%s", t.HostPath, err.Error())
}
vd.SetVolume(dbmodel.ShareFileVolumeType, fmt.Sprintf("mnt%d", t.ID), t.VolumePath, t.HostPath, false)
}
}
//handle slug file volume
if version.DeliveredType == "slug" {
slugPath := version.DeliveredPath
vd.SetVolume(dbmodel.ShareFileVolumeType, "slug", "/tmp/slug/slug.tgz", slugPath, true)
}
//need service mesh sidecar, volume kubeconfig
if as.NeedProxy {
vd.SetVolume(dbmodel.ShareFileVolumeType, "kube-config", "/etc/kubernetes", "/grdata/kubernetes", true)
}
return vd, nil
}
type volumeDefine struct {
volumeMounts []corev1.VolumeMount
volumes []corev1.Volume
persistentVolumes []corev1.PersistentVolume
}
func (v *volumeDefine) GetVolumes() []corev1.Volume {
return v.volumes
}
func (v *volumeDefine) GetVolumeMounts() []corev1.VolumeMount {
return v.volumeMounts
}
func (v *volumeDefine) SetVolume(VolumeType dbmodel.VolumeType, name, mountPath, hostPath string, readOnly bool) {
for _, m := range v.volumeMounts {
if m.MountPath == mountPath {
return
}
}
if hostPath != "" {
switch VolumeType {
case dbmodel.MemoryFSVolumeType:
vo := corev1.Volume{Name: name}
vo.EmptyDir = &corev1.EmptyDirVolumeSource{
Medium: corev1.StorageMediumMemory,
}
v.volumes = append(v.volumes, vo)
if mountPath != "" {
vm := corev1.VolumeMount{
MountPath: mountPath,
Name: name,
ReadOnly: readOnly,
SubPath: "",
}
v.volumeMounts = append(v.volumeMounts, vm)
}
case dbmodel.ShareFileVolumeType:
vo := corev1.Volume{
Name: name,
}
vo.HostPath = &corev1.HostPathVolumeSource{
Path: hostPath,
}
v.volumes = append(v.volumes, vo)
if mountPath != "" {
vm := corev1.VolumeMount{
MountPath: mountPath,
Name: name,
ReadOnly: readOnly,
SubPath: "",
}
v.volumeMounts = append(v.volumeMounts, vm)
}
case dbmodel.LocalVolumeType:
fulesystem := corev1.PersistentVolumeFilesystem
localPV := corev1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name + "pv",
},
Spec: corev1.PersistentVolumeSpec{
VolumeMode: &fulesystem,
AccessModes: []corev1.PersistentVolumeAccessMode{
corev1.ReadWriteOnce,
},
//do not auto reclaim
PersistentVolumeReclaimPolicy: corev1.PersistentVolumeReclaimRetain,
StorageClassName: "local-storage",
PersistentVolumeSource: corev1.PersistentVolumeSource{
Local: &corev1.LocalVolumeSource{
Path: hostPath,
},
},
},
}
v.persistentVolumes = append(v.persistentVolumes, localPV)
}
}
}
func createResources(as *v1.AppService) corev1.ResourceRequirements {
var cpuRequest, cpuLimit int64
memory := as.ContainerMemory
if memory < 512 {
cpuRequest, cpuLimit = int64(memory)/128*30, int64(memory)/128*80
} else if memory <= 1024 {
cpuRequest, cpuLimit = int64(memory)/128*30, int64(memory)/128*160
} else {
cpuRequest, cpuLimit = int64(memory)/128*30, ((int64(memory)-1024)/1024*500 + 1280)
}
limits := corev1.ResourceList{}
limits[corev1.ResourceCPU] = *resource.NewMilliQuantity(
cpuLimit,
resource.DecimalSI)
limits[corev1.ResourceMemory] = *resource.NewQuantity(
int64(as.ContainerMemory*1024*1024),
resource.BinarySI)
request := corev1.ResourceList{}
request[corev1.ResourceCPU] = *resource.NewMilliQuantity(
cpuRequest,
resource.DecimalSI)
request[corev1.ResourceMemory] = *resource.NewQuantity(
int64(as.ContainerMemory*1024*1024),
resource.BinarySI)
return corev1.ResourceRequirements{
Limits: limits,
Requests: request,
}
}
func checkUpstreamPluginRelation(serviceID string, dbmanager db.Manager) (bool, error) {
return dbmanager.TenantServicePluginRelationDao().CheckSomeModelPluginByServiceID(
serviceID,
dbmodel.UpNetPlugin)
}
func createUpstreamPluginMappingPort(
ports []*dbmodel.TenantServicesPort,
pluginPorts []*dbmodel.TenantServicesStreamPluginPort,
) (
[]*dbmodel.TenantServicesPort,
error) {
//start from 65301
for i := range ports {
port := ports[i]
for _, pport := range pluginPorts {
if pport.ContainerPort == port.ContainerPort {
port.ContainerPort = pport.PluginPort
port.MappingPort = pport.PluginPort
}
}
}
return ports, nil
}
func createPorts(as *v1.AppService, dbmanager db.Manager) (ports []corev1.ContainerPort) {
ps, err := dbmanager.TenantServicesPortDao().GetPortsByServiceID(as.ServiceID)
if err == nil && ps != nil && len(ps) > 0 {
crt, err := checkUpstreamPluginRelation(as.ServiceID, dbmanager)
if err != nil {
//return nil, fmt.Errorf("get service upstream plugin relation error, %s", err.Error())
return
}
if crt {
pluginPorts, err := dbmanager.TenantServicesStreamPluginPortDao().GetPluginMappingPorts(
as.ServiceID,
dbmodel.UpNetPlugin,
)
if err != nil {
//return nil, fmt.Errorf("find upstream plugin mapping port error, %s", err.Error())
return
}
ps, err = createUpstreamPluginMappingPort(ps, pluginPorts)
}
for i := range ps {
p := ps[i]
var hostPort int32
if p.IsOuterService && os.Getenv("CUR_NET") == "midonet" {
hostPort = 1
}
ports = append(ports, corev1.ContainerPort{
HostPort: hostPort,
ContainerPort: int32(p.ContainerPort),
})
}
}
return
}
func createProbe(as *v1.AppService, dbmanager db.Manager, mode string) *corev1.Probe {
probe, err := dbmanager.ServiceProbeDao().GetServiceUsedProbe(as.ServiceID, mode)
if err == nil && probe != nil {
if mode == "liveness" && probe.SuccessThreshold < 1 {
probe.SuccessThreshold = 1
}
if mode == "readiness" && probe.FailureThreshold < 1 {
probe.FailureThreshold = 3
}
p := &corev1.Probe{
FailureThreshold: int32(probe.FailureThreshold),
SuccessThreshold: int32(probe.SuccessThreshold),
InitialDelaySeconds: int32(probe.InitialDelaySecond),
TimeoutSeconds: int32(probe.TimeoutSecond),
PeriodSeconds: int32(probe.PeriodSecond),
}
if probe.Scheme == "tcp" {
tcp := &corev1.TCPSocketAction{
Port: intstr.FromInt(probe.Port),
}
p.TCPSocket = tcp
return p
} else if probe.Scheme == "http" {
action := corev1.HTTPGetAction{Path: probe.Path, Port: intstr.FromInt(probe.Port)}
if probe.HTTPHeader != "" {
hds := strings.Split(probe.HTTPHeader, ",")
var headers []corev1.HTTPHeader
for _, hd := range hds {
kv := strings.Split(hd, "=")
if len(kv) == 1 {
header := corev1.HTTPHeader{
Name: kv[0],
Value: "",
}
headers = append(headers, header)
} else if len(kv) == 2 {
header := corev1.HTTPHeader{
Name: kv[0],
Value: kv[1],
}
headers = append(headers, header)
}
}
action.HTTPHeaders = headers
}
p.HTTPGet = &action
return p
}
return nil
}
if err != nil {
logrus.Error("query probe error:", err.Error())
}
//TODO:create default probe
return nil
}
func createNodeSelector(as *v1.AppService, dbmanager db.Manager) map[string]string {
selector := make(map[string]string)
labels, err := dbmanager.TenantServiceLabelDao().GetTenantServiceNodeSelectorLabel(as.ServiceID)
if err == nil && labels != nil && len(labels) > 0 {
for _, l := range labels {
selector[l.LabelValue] = dbmodel.LabelKeyNodeSelector
}
}
return selector
}
func createAffinity(as *v1.AppService, dbmanager db.Manager) *corev1.Affinity {
var affinity corev1.Affinity
labels, err := dbmanager.TenantServiceLabelDao().GetTenantServiceAffinityLabel(as.ServiceID)
if err == nil && labels != nil && len(labels) > 0 {
nsr := make([]corev1.NodeSelectorRequirement, 0)
podAffinity := make([]corev1.PodAffinityTerm, 0)
podAntAffinity := make([]corev1.PodAffinityTerm, 0)
for _, l := range labels {
if l.LabelKey == dbmodel.LabelKeyNodeAffinity {
nsr = append(nsr, corev1.NodeSelectorRequirement{
Key: l.LabelKey,
Operator: corev1.NodeSelectorOpIn,
Values: []string{l.LabelValue},
})
}
if l.LabelKey == dbmodel.LabelKeyServiceAffinity {
podAffinity = append(podAffinity, corev1.PodAffinityTerm{
LabelSelector: metav1.SetAsLabelSelector(map[string]string{
"name": l.LabelValue,
}),
})
}
if l.LabelKey == dbmodel.LabelKeyServiceAntyAffinity {
podAntAffinity = append(
podAntAffinity, corev1.PodAffinityTerm{
LabelSelector: metav1.SetAsLabelSelector(map[string]string{
"name": l.LabelValue,
}),
})
}
}
affinity.NodeAffinity = &corev1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
NodeSelectorTerms: []corev1.NodeSelectorTerm{
corev1.NodeSelectorTerm{MatchExpressions: nsr},
},
},
}
affinity.PodAffinity = &corev1.PodAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: podAffinity,
}
affinity.PodAntiAffinity = &corev1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: podAntAffinity,
}
}
return &affinity
}
func setFeature(podt *corev1.PodTemplateSpec) {
for _, env := range podt.Spec.Containers[0].Env {
switch strings.ToLower(env.Name) {
case "annotations_hostname":
podt.Spec.Hostname = env.Value
case "annotations_shcedulername":
podt.Spec.SchedulerName = env.Value
case "annotations_nodename":
podt.Spec.NodeName = env.Value
}
}
}

View File

@ -0,0 +1,30 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package conversion
import (
"testing"
v1 "github.com/goodrain/rainbond/worker/appm/types/v1"
)
func TestTenantServiceVersion(t *testing.T) {
var as v1.AppService
TenantServiceVersion(&as, nil)
}

View File

@ -0,0 +1,28 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package storageclass
//TODO:
// kind: StorageClass
// apiVersion: storage.k8s.io/v1
// metadata:
// name: local-storage
// provisioner: kubernetes.io/no-provisioner
// volumeBindingMode: WaitForFirstConsumer

View File

@ -0,0 +1,35 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package store
import (
"k8s.io/client-go/tools/cache"
)
//Informer kube-api client cache
type Informer struct {
Ingress cache.SharedIndexInformer
Service cache.SharedIndexInformer
Endpoint cache.SharedIndexInformer
Secret cache.SharedIndexInformer
StatefulSet cache.SharedIndexInformer
Deployment cache.SharedIndexInformer
Pod cache.SharedIndexInformer
ConfigMap cache.SharedIndexInformer
}

View File

@ -0,0 +1,37 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package store
import (
appsv1 "k8s.io/client-go/listers/apps/v1"
corev1 "k8s.io/client-go/listers/core/v1"
v1beta1 "k8s.io/client-go/listers/extensions/v1beta1"
)
//Lister kube-api client cache
type Lister struct {
Ingress v1beta1.IngressLister
Service corev1.ServiceLister
Endpoint corev1.EndpointsLister
Secret corev1.SecretLister
StatefulSet appsv1.StatefulSetLister
Deployment appsv1.DeploymentLister
Pod corev1.PodLister
ConfigMap corev1.ConfigMapLister
}

View File

@ -0,0 +1,94 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package store
import (
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
)
//Storer app runtime store interface
type Storer interface {
}
//appRuntimeStore app runtime store
//cache all kubernetes object and appservice
type appRuntimeStore struct {
informers *Informer
listers *Lister
}
//NewStore new app runtime store
func NewStore(client kubernetes.Interface) Storer {
store := &appRuntimeStore{
informers: &Informer{},
}
// create informers factory, enable and assign required informers
infFactory := informers.NewFilteredSharedInformerFactory(client, time.Second, corev1.NamespaceAll,
func(options *metav1.ListOptions) {
options.LabelSelector = "creater=Rainbond"
})
store.informers.Deployment = infFactory.Apps().V1().Deployments().Informer()
store.listers.Deployment = infFactory.Apps().V1().Deployments().Lister()
store.informers.StatefulSet = infFactory.Apps().V1().StatefulSets().Informer()
store.listers.StatefulSet = infFactory.Apps().V1().StatefulSets().Lister()
store.informers.Service = infFactory.Core().V1().Services().Informer()
store.listers.Service = infFactory.Core().V1().Services().Lister()
store.informers.Endpoint = infFactory.Core().V1().Endpoints().Informer()
store.listers.Endpoint = infFactory.Core().V1().Endpoints().Lister()
store.informers.Pod = infFactory.Core().V1().Pods().Informer()
store.listers.Pod = infFactory.Core().V1().Pods().Lister()
store.informers.Secret = infFactory.Core().V1().Secrets().Informer()
store.listers.Secret = infFactory.Core().V1().Secrets().Lister()
store.informers.ConfigMap = infFactory.Core().V1().ConfigMaps().Informer()
store.listers.ConfigMap = infFactory.Core().V1().ConfigMaps().Lister()
store.informers.Ingress = infFactory.Extensions().V1beta1().Ingresses().Informer()
store.listers.Ingress = infFactory.Extensions().V1beta1().Ingresses().Lister()
store.informers.Deployment.AddEventHandler(store)
store.informers.StatefulSet.AddEventHandler(store)
store.informers.Pod.AddEventHandler(store)
store.informers.Secret.AddEventHandler(store)
store.informers.Service.AddEventHandler(store)
store.informers.Endpoint.AddEventHandler(store)
store.informers.Ingress.AddEventHandler(store)
store.informers.ConfigMap.AddEventHandler(store)
return store
}
func (a *appRuntimeStore) OnAdd(obj interface{}) {
}
func (a *appRuntimeStore) OnUpdate(oldObj, newObj interface{}) {
}
func (a *appRuntimeStore) OnDelete(obj interface{}) {
}

View File

@ -27,10 +27,31 @@ import (
//AppServiceStatus the status of service, calculate in real time from kubernetes
type AppServiceStatus string
//AppServiceType the deploy type of service.
type AppServiceType string
//TypeStatefulSet statefulset
var TypeStatefulSet AppServiceType = "statefulset"
//TypeDeployment deployment
var TypeDeployment AppServiceType = "deployment"
//TypeReplicationController rc
var TypeReplicationController AppServiceType = "replicationcontroller"
//AppServiceBase app service base info
type AppServiceBase struct {
TenantID string
ServiceID string
TenantID string
TenantName string
ServiceID string
ServiceAlias string
ServiceType AppServiceType
DeployVersion string
ContainerCPU int
ContainerMemory int
Replicas int
NeedProxy bool
CreaterID string
}
//AppService a service of rainbond app state in kubernetes
@ -49,3 +70,91 @@ type AppService struct {
func (a *AppService) GetDeployment() *v1.Deployment {
return a.deployment
}
//SetDeployment set kubernetes deployment model
func (a *AppService) SetDeployment(d *v1.Deployment) {
a.deployment = d
}
//GetStatefulSet get kubernetes statefulset model
func (a *AppService) GetStatefulSet() *v1.StatefulSet {
return a.statefulset
}
//SetStatefulSet set kubernetes statefulset model
func (a *AppService) SetStatefulSet(d *v1.StatefulSet) {
a.statefulset = d
}
//SetConfigMap set kubernetes configmap model
func (a *AppService) SetConfigMap(d *corev1.ConfigMap) {
if len(a.configMaps) > 0 {
for i, configMap := range a.configMaps {
if configMap.GetName() == d.GetName() {
a.configMaps[i] = d
return
}
}
}
a.configMaps = append(a.configMaps, d)
}
//SetService set kubernetes service model
func (a *AppService) SetService(d *corev1.Service) {
if len(a.services) > 0 {
for i, service := range a.services {
if service.GetName() == d.GetName() {
a.services[i] = d
return
}
}
}
a.services = append(a.services, d)
}
//SetIngress set kubernetes ingress model
func (a *AppService) SetIngress(d *extensions.Ingress) {
if len(a.ingresses) > 0 {
for i, ingress := range a.ingresses {
if ingress.GetName() == d.GetName() {
a.ingresses[i] = d
return
}
}
}
a.ingresses = append(a.ingresses, d)
}
//SetEndpoint set kubernetes endpoint model
func (a *AppService) SetEndpoint(d *corev1.Endpoints) {
if len(a.endpoints) > 0 {
for i, endpoint := range a.endpoints {
if endpoint.GetName() == d.GetName() {
a.endpoints[i] = d
return
}
}
}
a.endpoints = append(a.endpoints, d)
}
//SetPodTemplate set pod template spec
func (a *AppService) SetPodTemplate(d corev1.PodTemplateSpec) {
if a.statefulset != nil {
a.statefulset.Spec.Template = d
}
if a.deployment != nil {
a.deployment.Spec.Template = d
}
}
//GetPodTemplate get pod template
func (a *AppService) GetPodTemplate() *corev1.PodTemplateSpec {
if a.statefulset != nil {
return &a.statefulset.Spec.Template
}
if a.deployment != nil {
return &a.deployment.Spec.Template
}
return nil
}