Esempio n. 1
0
func (d *DockerProxy) RunByConfig(runConfig ContainerRunConfig) (string, error) {
	portBingds := map[string][]dockerclient.PortBinding{}
	exposedPorts := map[string]struct{}{}
	for _, port := range runConfig.PortBindings {
		pb := dockerclient.PortBinding{}
		pb.HostIp = "0.0.0.0"
		pb.HostPort = fmt.Sprintf("%d", port.GetHostPort())
		key := fmt.Sprintf("%d/%s", port.ContainerPort, port.Protocal)
		portBingds[key] = []dockerclient.PortBinding{pb}

		exposedPorts[key] = struct{}{}
	}

	config := &dockerclient.ContainerConfig{}
	config.Image = runConfig.Image
	config.Env = runConfig.Envs
	config.Cmd = runConfig.Cmds
	config.Hostname = runConfig.Hostname

	config.ExposedPorts = exposedPorts

	hostConfig := &dockerclient.HostConfig{}

	hostConfig.PortBindings = portBingds
	hostConfig.Binds = runConfig.Bindings
	hostConfig.Dns = runConfig.DNS
	hostConfig.RestartPolicy = dockerclient.RestartPolicy{
		Name:              runConfig.RestartPolicy.Name,
		MaximumRetryCount: int64(runConfig.RestartPolicy.MaxTry),
	}

	config.HostConfig = *hostConfig

	cid, err := d.CreateContainer(config, runConfig.Name)
	if err != nil {
		return "", errors.New(fmt.Sprintf("Failed to create a container. name: %s, error: %s", runConfig.Name, err.Error()))
	}
	fmt.Printf("Container created. name:%s, id:%s\n", runConfig.Name, cid)

	if err := d.StartContainer(cid, hostConfig); err != nil {
		fmt.Printf("Failed to start container. name:%s, id:%s.\n", runConfig.Name, cid)
		return cid, err
	}
	fmt.Printf("Container start successfully. name:%s, id:%s.\n", runConfig.Name, cid)

	return cid, nil
}
Esempio n. 2
0
func (p HaproxyPlugin) GenerateProxyConfig() (*ProxyConfig, error) {
	logMessage(log.DebugLevel, "generating proxy config")

	containers, err := p.client.ListContainers(false, false, "")
	if err != nil {
		return nil, err
	}
	var hosts []*Host
	proxyUpstreams := map[string][]*Upstream{}
	hostChecks := map[string]string{}
	hostBalanceAlgorithms := map[string]string{}
	hostBackendOptions := map[string][]string{}
	hostSSLOnly := map[string]bool{}
	for _, cnt := range containers {
		cntId := cnt.Id[:12]
		// load interlock data
		cInfo, err := p.client.InspectContainer(cntId)
		if err != nil {
			return nil, err
		}

		env := cInfo.Config.Env
		interlockData := &InterlockData{}

		for _, e := range env {
			envParts := strings.Split(e, "=")
			if envParts[0] == "INTERLOCK_DATA" {
				b := bytes.NewBufferString(envParts[1])
				if err := json.NewDecoder(b).Decode(&interlockData); err != nil {
					logMessage(log.WarnLevel,
						fmt.Sprintf("%s: unable to parse interlock data: %s", cntId, err))
				}
				break
			}
		}
		hostname := cInfo.Config.Hostname
		domain := cInfo.Config.Domainname

		if interlockData.Hostname != "" {
			hostname = interlockData.Hostname
		}

		if interlockData.Domain != "" {
			domain = interlockData.Domain
		}

		if domain == "" {
			continue
		}

		if hostname != domain && hostname != "" {
			domain = fmt.Sprintf("%s.%s", hostname, domain)
		}

		if interlockData.Check != "" {
			if val, ok := hostChecks[domain]; ok {
				// check existing host check for different values
				if val != interlockData.Check {
					logMessage(log.WarnLevel,
						fmt.Sprintf("conflicting check specified for %s", domain))
				}
			} else {
				hostChecks[domain] = interlockData.Check
				logMessage(log.DebugLevel,
					fmt.Sprintf("using custom check for %s: %s", domain, interlockData.Check))
			}
		}

		checkInterval := 5000

		if interlockData.CheckInterval != 0 {
			checkInterval = interlockData.CheckInterval
			logMessage(log.DebugLevel,
				fmt.Sprintf("using custom check interval for %s: %d", domain, checkInterval))
		}

		hostBalanceAlgorithms[domain] = "roundrobin"

		if interlockData.BalanceAlgorithm != "" {
			hostBalanceAlgorithms[domain] = interlockData.BalanceAlgorithm
		}

		if len(interlockData.BackendOptions) > 0 {
			hostBackendOptions[domain] = interlockData.BackendOptions
			logMessage(log.DebugLevel,
				fmt.Sprintf("using backend options for %s: %s", domain, strings.Join(interlockData.BackendOptions, ",")))
		}

		hostSSLOnly[domain] = false
		if interlockData.SSLOnly {
			logMessage(log.DebugLevel,
				fmt.Sprintf("configuring ssl redirect for %s", domain))
			hostSSLOnly[domain] = true
		}

		//host := cInfo.NetworkSettings.IpAddress
		ports := cInfo.NetworkSettings.Ports
		if len(ports) == 0 {
			logMessage(log.WarnLevel, fmt.Sprintf("%s: no ports exposed", cntId))
			continue
		}

		var portDef dockerclient.PortBinding

		for _, v := range ports {
			if len(v) > 0 {
				portDef = dockerclient.PortBinding{
					HostIp:   v[0].HostIp,
					HostPort: v[0].HostPort,
				}
				break
			}
		}

		if p.pluginConfig.ProxyBackendOverrideAddress != "" {
			portDef.HostIp = p.pluginConfig.ProxyBackendOverrideAddress
		}

		addr := fmt.Sprintf("%s:%s", portDef.HostIp, portDef.HostPort)

		if interlockData.Port != 0 {
			interlockPort := fmt.Sprintf("%d", interlockData.Port)
			for k, v := range ports {
				parts := strings.Split(k, "/")
				if parts[0] == interlockPort {
					port := v[0]
					logMessage(log.DebugLevel,
						fmt.Sprintf("%s: found specified port %s exposed as %s", domain, interlockPort, port.HostPort))
					addr = fmt.Sprintf("%s:%s", portDef.HostIp, port.HostPort)
					break
				}
			}
		}

		container_name := cInfo.Name[1:]
		up := &Upstream{
			Addr:          addr,
			Container:     container_name,
			CheckInterval: checkInterval,
		}

		logMessage(log.InfoLevel,
			fmt.Sprintf("%s: upstream=%s container=%s", domain, addr, container_name))

		for _, alias := range interlockData.AliasDomains {
			logMessage(log.DebugLevel,
				fmt.Sprintf("adding alias %s for %s", alias, cntId))
			proxyUpstreams[alias] = append(proxyUpstreams[alias], up)
		}

		proxyUpstreams[domain] = append(proxyUpstreams[domain], up)
	}
	for k, v := range proxyUpstreams {
		name := strings.Replace(k, ".", "_", -1)
		host := &Host{
			Name:             name,
			Domain:           k,
			Upstreams:        v,
			Check:            hostChecks[k],
			BalanceAlgorithm: hostBalanceAlgorithms[k],
			BackendOptions:   hostBackendOptions[k],
			SSLOnly:          hostSSLOnly[k],
		}
		logMessage(log.DebugLevel,
			fmt.Sprintf("adding host name=%s domain=%s", host.Name, host.Domain))
		hosts = append(hosts, host)
	}
	// generate config
	cfg := &ProxyConfig{
		Hosts:        hosts,
		PluginConfig: p.pluginConfig,
	}
	return cfg, nil
}
Esempio n. 3
0
func (p NginxPlugin) generateNginxConfig() (*NginxConfig, error) {
	containers, err := p.client.ListContainers(false, false, "")
	if err != nil {
		return nil, err
	}

	var hosts []*Host
	upstreamServers := map[string][]string{}
	serverNames := map[string][]string{}
	//hostBalanceAlgorithms := map[string]string{}
	hostSSL := map[string]bool{}
	hostSSLCert := map[string]string{}
	hostSSLCertKey := map[string]string{}
	hostSSLOnly := map[string]bool{}
	hostWebsocketEndpoints := map[string][]string{}

	for _, c := range containers {
		cntId := c.Id[:12]
		// load interlock data
		cInfo, err := p.client.InspectContainer(cntId)
		if err != nil {
			return nil, err
		}

		env := cInfo.Config.Env
		interlockData := &InterlockData{}

		for _, e := range env {
			envParts := strings.Split(e, "=")
			if envParts[0] == "INTERLOCK_DATA" {
				b := bytes.NewBufferString(envParts[1])
				if err := json.NewDecoder(b).Decode(&interlockData); err != nil {
					logMessage(log.WarnLevel,
						fmt.Sprintf("%s: unable to parse interlock data: %s", cntId, err))
				}
				break
			}
		}
		hostname := cInfo.Config.Hostname
		domain := cInfo.Config.Domainname

		if interlockData.Hostname != "" {
			hostname = interlockData.Hostname
		}

		if interlockData.Domain != "" {
			domain = interlockData.Domain
		}

		if domain == "" {
			continue
		}

		if hostname != domain && hostname != "" {
			domain = fmt.Sprintf("%s.%s", hostname, domain)
		}

		// check if the first server name is there; if not, add
		// this happens if there are multiple backend containers
		if _, ok := serverNames[domain]; !ok {
			serverNames[domain] = []string{domain}
		}

		hostSSL[domain] = interlockData.SSL

		hostSSLOnly[domain] = false
		if interlockData.SSLOnly {
			logMessage(log.DebugLevel,
				fmt.Sprintf("configuring ssl redirect for %s", domain))
			hostSSLOnly[domain] = true
		}

		// set cert paths
		baseCertPath := p.pluginConfig.SSLCertDir
		if interlockData.SSLCert != "" {
			certPath := filepath.Join(baseCertPath, interlockData.SSLCert)
			logMessage(log.InfoLevel,
				fmt.Sprintf("ssl cert for %s: %s", domain, certPath))
			hostSSLCert[domain] = certPath
		}

		if interlockData.SSLCertKey != "" {
			keyPath := filepath.Join(baseCertPath, interlockData.SSLCertKey)
			logMessage(log.InfoLevel,
				fmt.Sprintf("ssl key for %s: %s", domain, keyPath))
			hostSSLCertKey[domain] = keyPath
		}

		ports := cInfo.NetworkSettings.Ports
		if len(ports) == 0 {
			logMessage(log.WarnLevel, fmt.Sprintf("%s: no ports exposed", cntId))
			continue
		}

		var portDef dockerclient.PortBinding

		for _, v := range ports {
			if len(v) > 0 {
				portDef = dockerclient.PortBinding{
					HostIp:   v[0].HostIp,
					HostPort: v[0].HostPort,
				}
				break
			}
		}

		if p.pluginConfig.ProxyBackendOverrideAddress != "" {
			portDef.HostIp = p.pluginConfig.ProxyBackendOverrideAddress
		}

		addr := fmt.Sprintf("%s:%s", portDef.HostIp, portDef.HostPort)

		if interlockData.Port != 0 {
			interlockPort := fmt.Sprintf("%d", interlockData.Port)
			for k, v := range ports {
				parts := strings.Split(k, "/")
				if parts[0] == interlockPort {
					port := v[0]
					logMessage(log.DebugLevel,
						fmt.Sprintf("%s: found specified port %s exposed as %s", domain, interlockPort, port.HostPort))
					addr = fmt.Sprintf("%s:%s", portDef.HostIp, port.HostPort)
					break
				}
			}
		}

		// websocket endpoints
		for _, ws := range interlockData.WebsocketEndpoints {
			hostWebsocketEndpoints[domain] = append(hostWebsocketEndpoints[domain], ws)
		}

		logMessage(log.InfoLevel,
			fmt.Sprintf("%s: upstream=%s", domain, addr))

		for _, alias := range interlockData.AliasDomains {
			logMessage(log.DebugLevel,
				fmt.Sprintf("adding alias %s for %s", alias, cntId))
			serverNames[domain] = append(serverNames[domain], alias)
		}

		upstreamServers[domain] = append(upstreamServers[domain], addr)
	}

	for k, v := range upstreamServers {
		h := &Host{
			ServerNames: serverNames[k],
			// TODO: make configurable for TCP via InterlockData
			Port:               p.pluginConfig.Port,
			SSLPort:            p.pluginConfig.SSLPort,
			SSL:                hostSSL[k],
			SSLCert:            hostSSLCert[k],
			SSLCertKey:         hostSSLCertKey[k],
			SSLOnly:            hostSSLOnly[k],
			WebsocketEndpoints: hostWebsocketEndpoints[k],
		}

		servers := []*Server{}

		for _, s := range v {
			srv := &Server{
				Addr: s,
			}

			servers = append(servers, srv)
		}

		up := &Upstream{
			Name:    k,
			Servers: servers,
		}
		h.Upstream = up

		hosts = append(hosts, h)
	}

	return &NginxConfig{
		*p.pluginConfig,
		hosts,
	}, nil
}
Esempio n. 4
0
func (p *NginxLoadBalancer) GenerateProxyConfig() (*Config, error) {
	containers, err := p.client.ListContainers(false, false, "")
	if err != nil {
		return nil, err
	}

	var hosts []*Host
	upstreamServers := map[string][]string{}
	serverNames := map[string][]string{}
	//hostBalanceAlgorithms := map[string]string{}
	hostSSL := map[string]bool{}
	hostSSLCert := map[string]string{}
	hostSSLCertKey := map[string]string{}
	hostSSLOnly := map[string]bool{}
	hostSSLBackend := map[string]bool{}
	hostWebsocketEndpoints := map[string][]string{}

	for _, c := range containers {
		cntId := c.Id[:12]
		// load interlock data
		cInfo, err := p.client.InspectContainer(cntId)
		if err != nil {
			return nil, err
		}

		hostname := cInfo.Config.Hostname
		domain := cInfo.Config.Domainname

		if v, ok := cInfo.Config.Labels[ext.InterlockHostnameLabel]; ok {
			hostname = v
		}

		if v, ok := cInfo.Config.Labels[ext.InterlockDomainLabel]; ok {
			domain = v
		}

		if domain == "" {
			continue
		}

		if hostname != domain && hostname != "" {
			domain = fmt.Sprintf("%s.%s", hostname, domain)
		}

		// check if the first server name is there; if not, add
		// this happens if there are multiple backend containers
		if _, ok := serverNames[domain]; !ok {
			serverNames[domain] = []string{domain}
		}

		if _, ok := cInfo.Config.Labels[ext.InterlockSSLLabel]; ok {
			hostSSL[domain] = true
		}

		hostSSLOnly[domain] = false

		if _, ok := cInfo.Config.Labels[ext.InterlockSSLOnlyLabel]; ok {
			log().Infof("configuring ssl redirect for %s", domain)
			hostSSLOnly[domain] = true
		}

		// check ssl backend
		hostSSLBackend[domain] = false
		if _, ok := cInfo.Config.Labels[ext.InterlockSSLBackendLabel]; ok {
			log().Debugf("configuring ssl backend for %s", domain)
			hostSSLBackend[domain] = true
		}

		// set cert paths
		baseCertPath := p.cfg.SSLCertPath
		if v, ok := cInfo.Config.Labels[ext.InterlockSSLCertLabel]; ok {
			certPath := filepath.Join(baseCertPath, v)
			log().Infof("ssl cert for %s: %s", domain, certPath)
			hostSSLCert[domain] = certPath
		}

		if v, ok := cInfo.Config.Labels[ext.InterlockSSLCertKeyLabel]; ok {
			keyPath := filepath.Join(baseCertPath, v)
			log().Infof("ssl key for %s: %s", domain, keyPath)
			hostSSLCertKey[domain] = keyPath
		}

		ports := cInfo.NetworkSettings.Ports
		if len(ports) == 0 {
			log().Warnf("%s: no ports exposed", cntId)
			continue
		}

		var portDef dockerclient.PortBinding

		for _, v := range ports {
			if len(v) > 0 {
				portDef = dockerclient.PortBinding{
					HostIp:   v[0].HostIp,
					HostPort: v[0].HostPort,
				}
				break
			}
		}

		if p.cfg.BackendOverrideAddress != "" {
			portDef.HostIp = p.cfg.BackendOverrideAddress
		}

		addr := fmt.Sprintf("%s:%s", portDef.HostIp, portDef.HostPort)

		if v, ok := cInfo.Config.Labels[ext.InterlockPortLabel]; ok {
			interlockPort := v
			for k, x := range ports {
				parts := strings.Split(k, "/")
				if parts[0] == interlockPort {
					port := x[0]
					log().Debugf("%s: found specified port %s exposed as %s", domain, interlockPort, port.HostPort)
					addr = fmt.Sprintf("%s:%s", portDef.HostIp, port.HostPort)
					break
				}
			}
		}

		// "parse" multiple labels for websocket endpoints
		websocketEndpoints := []string{}
		for l, v := range cInfo.Config.Labels {
			// this is for labels like interlock.websocket_endpoint.1=foo
			if strings.Index(l, ext.InterlockWebsocketEndpointLabel) > -1 {
				websocketEndpoints = append(websocketEndpoints, v)
			}
		}

		log().Debugf("websocket endpoints: %v", websocketEndpoints)

		// websocket endpoints
		for _, ws := range websocketEndpoints {
			hostWebsocketEndpoints[domain] = append(hostWebsocketEndpoints[domain], ws)
		}

		// "parse" multiple labels for alias domains
		aliasDomains := []string{}
		for l, v := range cInfo.Config.Labels {
			// this is for labels like interlock.alias_domain.1=foo.local
			if strings.Index(l, ext.InterlockAliasDomainLabel) > -1 {
				aliasDomains = append(aliasDomains, v)
			}
		}

		log().Debugf("alias domains: %v", aliasDomains)

		for _, alias := range aliasDomains {
			log().Debugf("adding alias %s for %s", alias, cntId)
			serverNames[domain] = append(serverNames[domain], alias)
		}

		log().Infof("%s: upstream=%s", domain, addr)

		upstreamServers[domain] = append(upstreamServers[domain], addr)
	}

	for k, v := range upstreamServers {
		h := &Host{
			ServerNames:        serverNames[k],
			Port:               p.cfg.Port,
			SSLPort:            p.cfg.SSLPort,
			SSL:                hostSSL[k],
			SSLCert:            hostSSLCert[k],
			SSLCertKey:         hostSSLCertKey[k],
			SSLOnly:            hostSSLOnly[k],
			SSLBackend:         hostSSLBackend[k],
			WebsocketEndpoints: hostWebsocketEndpoints[k],
		}

		servers := []*Server{}

		for _, s := range v {
			srv := &Server{
				Addr: s,
			}

			servers = append(servers, srv)
		}

		up := &Upstream{
			Name:    k,
			Servers: servers,
		}
		h.Upstream = up

		hosts = append(hosts, h)
	}

	return &Config{
		Hosts:  hosts,
		Config: p.cfg,
	}, nil
}
Esempio n. 5
0
func (p *HAProxyLoadBalancer) GenerateProxyConfig() (*Config, error) {
	log().Debug("generating proxy config")

	containers, err := p.client.ListContainers(false, false, "")
	if err != nil {
		return nil, err
	}

	var hosts []*Host

	proxyUpstreams := map[string][]*Upstream{}
	hostChecks := map[string]string{}
	hostBalanceAlgorithms := map[string]string{}
	hostBackendOptions := map[string][]string{}
	hostSSLOnly := map[string]bool{}
	hostSSLBackend := map[string]bool{}
	hostSSLBackendTLSVerify := map[string]string{}

	// TODO: instead of setting defaults here use
	// SetDefaultConfig in the utils package
	for _, cnt := range containers {
		cntId := cnt.Id[:12]
		// load interlock data
		cInfo, err := p.client.InspectContainer(cntId)
		if err != nil {
			return nil, err
		}

		hostname := cInfo.Config.Hostname
		domain := cInfo.Config.Domainname

		if v, ok := cInfo.Config.Labels[ext.InterlockHostnameLabel]; ok {
			hostname = v
		}

		if v, ok := cInfo.Config.Labels[ext.InterlockDomainLabel]; ok {
			domain = v
		}

		if domain == "" {
			continue
		}

		if hostname != domain && hostname != "" {
			domain = fmt.Sprintf("%s.%s", hostname, domain)
		}

		if v, ok := cInfo.Config.Labels[ext.InterlockHealthCheckLabel]; ok {
			if val, ok := hostChecks[domain]; ok {
				// check existing host check for different values
				if val != v {
					log().Warnf("conflicting check specified for %s", domain)
				}
			} else {
				hostChecks[domain] = v
				log().Debugf("using custom check for %s: %s", domain, v)
			}
		}

		checkInterval := 5000

		if v, ok := cInfo.Config.Labels[ext.InterlockHealthCheckIntervalLabel]; ok && v != "" {
			i, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			if i != 0 {
				checkInterval = i
				log().Debugf("using custom check interval for %s: %d", domain, checkInterval)
			}
		}

		hostBalanceAlgorithms[domain] = "roundrobin"

		if v, ok := cInfo.Config.Labels[ext.InterlockBalanceAlgorithmLabel]; ok && v != "" {
			hostBalanceAlgorithms[domain] = v
		}

		backendOptions := []string{}
		for l, v := range cInfo.Config.Labels {
			// this is for labels like interlock.backend_option.1=foo
			if strings.Index(l, ext.InterlockBackendOptionLabel) > -1 {
				backendOptions = append(backendOptions, v)
			}
		}

		if len(backendOptions) > 0 {
			hostBackendOptions[domain] = backendOptions
			log().Debugf("using backend options for %s: %s", domain, strings.Join(backendOptions, ","))
		}

		hostSSLOnly[domain] = false
		if _, ok := cInfo.Config.Labels[ext.InterlockSSLOnlyLabel]; ok {
			log().Debugf("configuring ssl redirect for %s", domain)
			hostSSLOnly[domain] = true
		}

		// ssl backend
		hostSSLBackend[domain] = false
		if _, ok := cInfo.Config.Labels[ext.InterlockSSLBackendLabel]; ok {
			hostSSLBackend[domain] = true

			sslBackendTLSVerify := "none"
			if v, ok := cInfo.Config.Labels[ext.InterlockSSLBackendTLSVerifyLabel]; ok {
				sslBackendTLSVerify = v
			}
			hostSSLBackendTLSVerify[domain] = sslBackendTLSVerify

			log().Debugf("configuring ssl backend for %s verify=%s", domain, sslBackendTLSVerify)
		}

		//host := cInfo.NetworkSettings.IpAddress
		ports := cInfo.NetworkSettings.Ports
		if len(ports) == 0 {
			log().Warnf("%s: no ports exposed", cntId)
			continue
		}

		var portDef dockerclient.PortBinding

		for _, v := range ports {
			if len(v) > 0 {
				portDef = dockerclient.PortBinding{
					HostIp:   v[0].HostIp,
					HostPort: v[0].HostPort,
				}
				break
			}
		}

		if p.cfg.BackendOverrideAddress != "" {
			portDef.HostIp = p.cfg.BackendOverrideAddress
		}

		addr := fmt.Sprintf("%s:%s", portDef.HostIp, portDef.HostPort)
		if v, ok := cInfo.Config.Labels[ext.InterlockPortLabel]; ok {
			for k, x := range ports {
				parts := strings.Split(k, "/")
				if parts[0] == v {
					port := x[0]
					log().Debugf("%s: found specified port %s exposed as %s", domain, v, port.HostPort)
					addr = fmt.Sprintf("%s:%s", portDef.HostIp, port.HostPort)
					break
				}
			}
		}

		container_name := cInfo.Name[1:]
		up := &Upstream{
			Addr:          addr,
			Container:     container_name,
			CheckInterval: checkInterval,
		}

		log().Infof("%s: upstream=%s container=%s", domain, addr, container_name)

		// "parse" multiple labels for alias domains
		aliasDomains := []string{}
		for l, v := range cInfo.Config.Labels {
			// this is for labels like interlock.alias_domain.1=foo.local
			if strings.Index(l, ext.InterlockAliasDomainLabel) > -1 {
				aliasDomains = append(aliasDomains, v)
			}
		}

		log().Debugf("alias domains: %v", aliasDomains)

		for _, alias := range aliasDomains {
			log().Debugf("adding alias %s for %s", alias, cntId)
			proxyUpstreams[alias] = append(proxyUpstreams[alias], up)
		}

		proxyUpstreams[domain] = append(proxyUpstreams[domain], up)
	}
	for k, v := range proxyUpstreams {
		name := strings.Replace(k, ".", "_", -1)
		host := &Host{
			Name:                name,
			Domain:              k,
			Upstreams:           v,
			Check:               hostChecks[k],
			BalanceAlgorithm:    hostBalanceAlgorithms[k],
			BackendOptions:      hostBackendOptions[k],
			SSLOnly:             hostSSLOnly[k],
			SSLBackend:          hostSSLBackend[k],
			SSLBackendTLSVerify: hostSSLBackendTLSVerify[k],
		}
		log().Debugf("adding host name=%s domain=%s", host.Name, host.Domain)
		hosts = append(hosts, host)
	}
	// generate config
	cfg := &Config{
		Hosts:  hosts,
		Config: p.cfg,
	}

	return cfg, nil
}