Files
haproxy-ingress/pkg/controller/controller.go
T
2017-06-07 20:54:52 -03:00

170 lines
5.1 KiB
Go

/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"bytes"
"github.com/golang/glog"
"github.com/jcmoraisjr/haproxy-ingress/pkg/version"
"github.com/spf13/pflag"
"io/ioutil"
api "k8s.io/client-go/pkg/api/v1"
"k8s.io/ingress/core/pkg/ingress"
"k8s.io/ingress/core/pkg/ingress/controller"
"k8s.io/ingress/core/pkg/ingress/defaults"
"net/http"
"os"
"os/exec"
)
// HAProxyController has internal data of a HAProxyController instance
type HAProxyController struct {
controller *controller.GenericController
configMap *api.ConfigMap
storeLister *ingress.StoreLister
command string
reloadStrategy *string
configFile string
template *template
}
// NewHAProxyController constructor
func NewHAProxyController() *HAProxyController {
return &HAProxyController{}
}
// Info provides controller name and repository infos
func (haproxy *HAProxyController) Info() *ingress.BackendInfo {
return &ingress.BackendInfo{
Name: "HAProxy",
Release: version.RELEASE,
Build: version.COMMIT,
Repository: version.REPO,
}
}
// Start starts the controller
func (haproxy *HAProxyController) Start() {
haproxy.controller = controller.NewIngressController(haproxy)
haproxy.controller.Start()
}
// Stop shutdown the controller process
func (haproxy *HAProxyController) Stop() error {
err := haproxy.controller.Stop()
return err
}
// Name provides the complete name of the controller
func (haproxy *HAProxyController) Name() string {
return "HAProxy Ingress Controller"
}
// DefaultIngressClass returns the ingress class name
func (haproxy *HAProxyController) DefaultIngressClass() string {
return "haproxy"
}
// Check health check implementation
func (haproxy *HAProxyController) Check(_ *http.Request) error {
return nil
}
// SetListers give access to the store listers
func (haproxy *HAProxyController) SetListers(lister ingress.StoreLister) {
haproxy.storeLister = &lister
}
// ConfigureFlags allow to configure more flags before the parsing of
// command line arguments
func (haproxy *HAProxyController) ConfigureFlags(flags *pflag.FlagSet) {
haproxy.reloadStrategy = flags.String("reload-strategy", "native",
`Name of the reload strategy. Options are: native (default) or multibinder`)
ingressClass := flags.Lookup("ingress-class")
if ingressClass != nil {
ingressClass.Value.Set("haproxy")
ingressClass.DefValue = "haproxy"
}
}
// OverrideFlags allows controller to override command line parameter flags
func (haproxy *HAProxyController) OverrideFlags(flags *pflag.FlagSet) {
if *haproxy.reloadStrategy == "native" {
haproxy.configFile = "/etc/haproxy/haproxy.cfg"
haproxy.template = newTemplate("haproxy.tmpl", "/etc/haproxy/template/haproxy.tmpl")
} else if *haproxy.reloadStrategy == "multibinder" {
haproxy.configFile = "/etc/haproxy/haproxy.cfg.erb"
haproxy.template = newTemplate("haproxy.cfg.erb.tmpl", "/etc/haproxy/haproxy.cfg.erb.tmpl")
} else {
glog.Fatalf("Unsupported reload strategy: %v", *haproxy.reloadStrategy)
}
haproxy.command = "/haproxy-reload.sh"
}
// SetConfig receives the ConfigMap the user has configured
func (haproxy *HAProxyController) SetConfig(configMap *api.ConfigMap) {
haproxy.configMap = configMap
}
// BackendDefaults defines default values to the ingress core
func (haproxy *HAProxyController) BackendDefaults() defaults.Backend {
return newHAProxyConfig(haproxy).Backend
}
// OnUpdate regenerate the configuration file of the backend
func (haproxy *HAProxyController) OnUpdate(cfg ingress.Configuration) ([]byte, error) {
data, err := haproxy.template.execute(newControllerConfig(&cfg, haproxy))
if err != nil {
return nil, err
}
return data, nil
}
// Reload reload the backend if the configuration file has changed
func (haproxy *HAProxyController) Reload(data []byte) ([]byte, bool, error) {
if !haproxy.configChanged(data) {
return nil, false, nil
}
// TODO missing HAProxy validation before overwrite and try to reload
err := ioutil.WriteFile(haproxy.configFile, data, 0644)
if err != nil {
return nil, false, err
}
out, err := haproxy.reloadHaproxy()
if len(out) > 0 {
glog.Infof("HAProxy output:\n%v", string(out))
}
return out, true, err
}
func (haproxy *HAProxyController) configChanged(data []byte) bool {
if _, err := os.Stat(haproxy.configFile); os.IsNotExist(err) {
return true
}
cfg, err := ioutil.ReadFile(haproxy.configFile)
if err != nil {
glog.Warningf("error reading haproxy config: %v")
return false
}
return !bytes.Equal(cfg, data)
}
func (haproxy *HAProxyController) reloadHaproxy() ([]byte, error) {
out, err := exec.Command(haproxy.command, *haproxy.reloadStrategy, haproxy.configFile).CombinedOutput()
return out, err
}