generationtux/brizo

View on GitHub
resources/environment.go

Summary

Maintainability
A
45 mins
Test Coverage
package resources

import (
    "errors"
    "fmt"

    "k8s.io/client-go/pkg/api/v1"

    "github.com/Machiel/slugify"
    "github.com/generationtux/brizo/database"
    "github.com/generationtux/brizo/kube"
    "github.com/jinzhu/gorm"
    "github.com/pborman/uuid"
)

// Environment as defined by Brizo.
type Environment struct {
    database.Model
    UUID            string      `gorm:"not null;unique_index" sql:"type:varchar(36)" json:"uuid"`
    Name            string      `gorm:"not null" json:"name"`
    Slug            string      `gorm:"not null" json:"slug"`
    VersionID       uint64      `gorm:"not null" json:"version_id,string"`
    VersionUUID     string      `gorm:"not null" json:"version_uuid"`
    Version         Version     `json:"version"`
    ApplicationID   uint64      `gorm:"not null" json:"application_id,string"`
    ApplicationUUID string      `gorm:"not null" json:"application_uuid"`
    Application     Application `json:"application"`
}

// BeforeCreate is a hook that runs before inserting a new record into the
// database
func (environment *Environment) BeforeCreate() (err error) {
    if environment.UUID == "" {
        environment.UUID = uuid.New()
    }
    if environment.Slug == "" {
        environment.Slug = slugify.Slugify(environment.Name)
    }
    return
}

// AllEnvironments will return all of the Environments
func AllEnvironments(db *gorm.DB) ([]Environment, error) {
    var environments []Environment
    result := db.Preload("Application").Find(&environments)

    return environments, result.Error
}

// CreateEnvironment will add a new Environment to Brizo
func CreateEnvironment(db *gorm.DB, client kube.APIInterface, environment *Environment, application *Application) (bool, error) {
    result := db.Create(&environment)
    service := environmentServiceDefinition(environment, application)
    err := client.CreateService(service)
    if err != nil {
        // @TODO need a better way to handle some of this upstream
        DeleteEnvironment(db, environment.Name)
        return false, err
    }

    return result.RowsAffected == 1, result.Error
}

func environmentServiceDefinition(environment *Environment, application *Application) *v1.Service {
    name := fmt.Sprintf(
        "%v-%v",
        application.Slug,
        environment.Slug,
    )
    return &v1.Service{
        ObjectMeta: v1.ObjectMeta{
            Name:      name,
            Namespace: "brizo",
            Labels: map[string]string{
                "brizoManaged": "true",
                "appUUID":      application.UUID,
                "envUUID":      environment.UUID,
            },
        },
        Spec: v1.ServiceSpec{
            Selector: map[string]string{
                "appUUID": application.UUID,
                "envUUID": environment.UUID,
            },
            Ports: []v1.ServicePort{
                v1.ServicePort{
                    Protocol: v1.ProtocolTCP,
                    Port:     int32(80),
                },
            },
        },
    }
}

// UpdateEnvironment will update an existing Environment
func UpdateEnvironment(db *gorm.DB, environment *Environment) (bool, error) {
    environment.Slug = slugify.Slugify(environment.Name)
    result := db.Model(environment).Where("uuid = ?", environment.UUID).
        UpdateColumns(environment)

    return result.RowsAffected == 1, result.Error
}

// UpdateEnvironmentService will update an existing Environment's service in K8s
func UpdateEnvironmentService(db *gorm.DB, client kube.APIInterface, environment *Environment, ports []ContainerPort) (bool, error) {
    var svcPorts = make([]v1.ServicePort, len(ports))
    var protocol = v1.ProtocolTCP

    // build svcPorts (service ports)
    for index, element := range ports {
        if element.Protocol == "UDP" {
            protocol = v1.ProtocolUDP
        }

        // Name is required because k8s requires each port have a name for
        // services with multiple ports
        var sp = v1.ServicePort{
            Name:     slugify.Slugify(fmt.Sprintf("%v-%v", element.Protocol, element.Port)),
            Protocol: protocol,
            Port:     int32(element.Port),
        }

        svcPorts[index] = sp
    }

    name := fmt.Sprintf(
        "%v-%v",
        environment.Version.Application.Slug,
        environment.Slug,
    )

    service, err := client.GetService("brizo", name)

    if err != nil {
        return false, err
    }

    service.Spec.Ports = svcPorts

    err = client.UpdateService(service)

    if err != nil {
        return false, err
    }

    return true, err
}

// GetEnvironment will get an existing Environment by id
func GetEnvironment(db *gorm.DB, id string) (*Environment, error) {
    environment := new(Environment)
    if err := db.Preload("Application.Environments").Preload("Version").Where("uuid = ?", id).First(&environment).Error; err != nil {
        return environment, err
    }

    if environment.ID == 0 {
        return new(Environment), errors.New("not-found")
    }

    return environment, nil
}

// DeleteEnvironment will delete an existing Environment by name
func DeleteEnvironment(db *gorm.DB, name string) (bool, error) {
    result := db.Delete(Environment{}, "name = ?", name)

    return result.RowsAffected == 1, result.Error
}