1
0
mirror of https://github.com/rancher/os.git synced 2025-08-01 06:59:05 +00:00

Merge pull request #917 from joshwget/proxy-settings

HTTP proxy settings can be set in cloud config
This commit is contained in:
Darren Shepherd 2016-05-07 12:56:52 -07:00
commit a9ca80d47d
11 changed files with 238 additions and 104 deletions

View File

@ -11,7 +11,7 @@ import (
"github.com/docker/libcompose/project"
"github.com/rancher/os/compose"
"github.com/rancher/os/config"
"github.com/rancher/os/util"
"github.com/rancher/os/util/network"
)
type projectFactory struct {
@ -172,7 +172,7 @@ func list(c *cli.Context) {
clone[service] = enabled
}
services, err := util.GetServices(cfg.Rancher.Repositories.ToArray())
services, err := network.GetServices(cfg.Rancher.Repositories.ToArray())
if err != nil {
logrus.Fatalf("Failed to get services: %v", err)
}

View File

@ -2,6 +2,7 @@ package compose
import (
"fmt"
log "github.com/Sirupsen/logrus"
yaml "github.com/cloudfoundry-incubator/candiedyaml"
"github.com/docker/libcompose/cli/logger"
@ -10,6 +11,7 @@ import (
"github.com/rancher/os/config"
rosDocker "github.com/rancher/os/docker"
"github.com/rancher/os/util"
"github.com/rancher/os/util/network"
)
func CreateService(cfg *config.CloudConfig, name string, serviceConfig *project.ServiceConfig) (project.Service, error) {
@ -121,7 +123,7 @@ func adjustContainerNames(m map[interface{}]interface{}) map[interface{}]interfa
return m
}
func newCoreServiceProject(cfg *config.CloudConfig, network bool) (*project.Project, error) {
func newCoreServiceProject(cfg *config.CloudConfig, useNetwork bool) (*project.Project, error) {
projectEvents := make(chan project.Event)
enabled := map[interface{}]interface{}{}
@ -151,9 +153,9 @@ func newCoreServiceProject(cfg *config.CloudConfig, network bool) (*project.Proj
continue
}
bytes, err := LoadServiceResource(service, network, cfg)
bytes, err := LoadServiceResource(service, useNetwork, cfg)
if err != nil {
if err == util.ErrNoNetwork {
if err == network.ErrNoNetwork {
log.Debugf("Can not load %s, networking not enabled", service)
} else {
log.Errorf("Failed to load %s : %v", service, err)
@ -186,7 +188,7 @@ func newCoreServiceProject(cfg *config.CloudConfig, network bool) (*project.Proj
go func() {
for event := range projectEvents {
if event.EventType == project.EventContainerStarted && event.ServiceName == "ntp" {
network = true
useNetwork = true
}
}
}()
@ -240,6 +242,6 @@ func StageServices(cfg *config.CloudConfig, services ...string) error {
return p.Pull()
}
func LoadServiceResource(name string, network bool, cfg *config.CloudConfig) ([]byte, error) {
return util.LoadResource(name, network, cfg.Rancher.Repositories.ToArray())
func LoadServiceResource(name string, useNetwork bool, cfg *config.CloudConfig) ([]byte, error) {
return network.LoadResource(name, useNetwork, cfg.Rancher.Repositories.ToArray())
}

View File

@ -27,11 +27,30 @@ func appendEnv(array []string, key, value string) []string {
return append(array, fmt.Sprintf("%s=%s", key, value))
}
func environmentFromCloudConfig(cfg *config.CloudConfig) map[string]string {
environment := cfg.Rancher.Environment
if cfg.Rancher.Network.HttpProxy != "" {
environment["http_proxy"] = cfg.Rancher.Network.HttpProxy
environment["HTTP_PROXY"] = cfg.Rancher.Network.HttpProxy
}
if cfg.Rancher.Network.HttpsProxy != "" {
environment["https_proxy"] = cfg.Rancher.Network.HttpsProxy
environment["HTTPS_PROXY"] = cfg.Rancher.Network.HttpsProxy
}
if cfg.Rancher.Network.NoProxy != "" {
environment["no_proxy"] = cfg.Rancher.Network.NoProxy
environment["NO_PROXY"] = cfg.Rancher.Network.NoProxy
}
return environment
}
func lookupKeys(cfg *config.CloudConfig, keys ...string) []string {
environment := environmentFromCloudConfig(cfg)
for _, key := range keys {
if strings.HasSuffix(key, "*") {
result := []string{}
for envKey, envValue := range cfg.Rancher.Environment {
for envKey, envValue := range environment {
keyPrefix := key[:len(key)-1]
if strings.HasPrefix(envKey, keyPrefix) {
result = appendEnv(result, envKey, envValue)
@ -41,7 +60,7 @@ func lookupKeys(cfg *config.CloudConfig, keys ...string) []string {
if len(result) > 0 {
return result
}
} else if value, ok := cfg.Rancher.Environment[key]; ok {
} else if value, ok := environment[key]; ok {
return appendEnv([]string{}, key, value)
}
}

View File

@ -14,6 +14,7 @@ import (
"github.com/rancher/docker-from-scratch"
"github.com/rancher/os/config"
"github.com/rancher/os/util"
"github.com/rancher/os/util/network"
)
const (
@ -223,6 +224,10 @@ func RunInit() error {
func(c *config.CloudConfig) (*config.CloudConfig, error) {
return c, dockerlaunch.PrepareFs(&mountConfig)
},
func(c *config.CloudConfig) (*config.CloudConfig, error) {
network.SetProxyEnvironmentVariables(c)
return c, nil
},
initializeSelinux,
func(c *config.CloudConfig) (*config.CloudConfig, error) {
return c, syscall.Mount("", "/", "", syscall.MS_SHARED|syscall.MS_REC, "")

View File

@ -339,6 +339,10 @@ rancher:
- /opt:/opt
docker:
image: {{.OS_IMAGES_ROOT}}/os-docker:{{.VERSION}}{{.SUFFIX}}
environment:
- HTTP_PROXY
- HTTPS_PROXY
- NO_PROXY
labels:
io.rancher.os.scope: system
io.rancher.os.after: console

View File

@ -0,0 +1,8 @@
#cloud-config
rancher:
network:
http_proxy: invalid
https_proxy: invalid
no_proxy: invalid
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC85w9stZyiLQp/DkVO6fqwiShYcj1ClKdtCqgHtf+PLpJkFReSFu8y21y+ev09gsSMRRrjF7yt0pUHV6zncQhVeqsZtgc5WbELY2DOYUGmRn/CCvPbXovoBrQjSorqlBmpuPwsStYLr92Xn+VVsMNSUIegHY22DphGbDKG85vrKB8HxUxGIDxFBds/uE8FhSy+xsoyT/jUZDK6pgq2HnGl6D81ViIlKecpOpWlW3B+fea99ADNyZNVvDzbHE5pcI3VRw8u59WmpWOUgT6qacNVACl8GqpBvQk8sw7O/X9DSZHCKafeD9G5k+GYbAUz92fKWrx/lOXfUXPS3+c8dRIF

View File

@ -0,0 +1,45 @@
import pytest
import rostest.util as u
from rostest.util import SSH
cloud_config_path = './tests/integration/assets/test_17/cloud-config.yml'
@pytest.fixture(scope="module")
def qemu(request):
q = u.run_qemu(request, run_args=['--cloud-config', cloud_config_path])
u.flush_out(q.stdout)
return q
def test_docker_http_proxy(qemu):
SSH(qemu).check_call('''
set -x -e
sudo system-docker exec docker env | grep HTTP_PROXY=invalid
sudo system-docker exec docker env | grep HTTPS_PROXY=invalid
sudo system-docker exec docker env | grep NO_PROXY=invalid
if docker pull busybox; then
exit 1
else
exit 0
fi
''')
def test_system_docker_http_proxy(qemu):
try:
SSH(qemu).check_call('sudo reboot')
except:
pass
SSH(qemu).check_call('''
set -x -e
if sudo system-docker pull busybox; then
exit 1
else
exit 0
fi
''')

120
util/network/network.go Normal file
View File

@ -0,0 +1,120 @@
package network
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
yaml "github.com/cloudfoundry-incubator/candiedyaml"
log "github.com/Sirupsen/logrus"
"github.com/rancher/os/config"
)
var (
ErrNoNetwork = errors.New("Networking not available to load resource")
ErrNotFound = errors.New("Failed to find resource")
)
func GetServices(urls []string) ([]string, error) {
result := []string{}
for _, url := range urls {
indexUrl := fmt.Sprintf("%s/index.yml", url)
content, err := LoadResource(indexUrl, true, []string{})
if err != nil {
log.Errorf("Failed to load %s: %v", indexUrl, err)
continue
}
services := make(map[string][]string)
err = yaml.Unmarshal(content, &services)
if err != nil {
log.Errorf("Failed to unmarshal %s: %v", indexUrl, err)
continue
}
if list, ok := services["services"]; ok {
result = append(result, list...)
}
}
return result, nil
}
func SetProxyEnvironmentVariables(cfg *config.CloudConfig) {
if cfg.Rancher.Network.HttpProxy != "" {
err := os.Setenv("HTTP_PROXY", cfg.Rancher.Network.HttpProxy)
if err != nil {
log.Errorf("Unable to set HTTP_PROXY: %s", err)
}
}
if cfg.Rancher.Network.HttpsProxy != "" {
err := os.Setenv("HTTPS_PROXY", cfg.Rancher.Network.HttpsProxy)
if err != nil {
log.Errorf("Unable to set HTTPS_PROXY: %s", err)
}
}
if cfg.Rancher.Network.NoProxy != "" {
err := os.Setenv("NO_PROXY", cfg.Rancher.Network.NoProxy)
if err != nil {
log.Errorf("Unable to set NO_PROXY: %s", err)
}
}
}
func retryHttp(f func() (*http.Response, error), times int) (resp *http.Response, err error) {
for i := 0; i < times; i++ {
if resp, err = f(); err == nil {
return
}
log.Warnf("Error making HTTP request: %s. Retrying", err)
}
return
}
func LoadResource(location string, network bool, urls []string) ([]byte, error) {
var bytes []byte
err := ErrNotFound
if strings.HasPrefix(location, "http:/") || strings.HasPrefix(location, "https:/") {
if !network {
return nil, ErrNoNetwork
}
cfg, err := config.LoadConfig()
if err != nil {
return nil, err
}
SetProxyEnvironmentVariables(cfg)
resp, err := retryHttp(func() (*http.Response, error) {
return http.Get(location)
}, 8)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("non-200 http response: %d", resp.StatusCode)
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
} else if strings.HasPrefix(location, "/") {
return ioutil.ReadFile(location)
} else if len(location) > 0 {
for _, url := range urls {
ymlUrl := fmt.Sprintf("%s/%s/%s.yml", url, location[0:1], location)
bytes, err = LoadResource(ymlUrl, network, []string{})
if err == nil {
log.Debugf("Loaded %s from %s", location, ymlUrl)
return bytes, nil
}
}
}
return nil, err
}

View File

@ -0,0 +1,23 @@
package network
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func NoTestLoadResourceSimple(t *testing.T) {
assert := require.New(t)
expected := `services:
- debian-console
- ubuntu-console
`
expected = strings.TrimSpace(expected)
b, e := LoadResource("https://raw.githubusercontent.com/rancher/os-services/v0.3.4/index.yml", true, []string{})
assert.Nil(e)
assert.Equal(expected, strings.TrimSpace(string(b)))
}

View File

@ -2,11 +2,8 @@ package util
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
@ -17,11 +14,6 @@ import (
"reflect"
)
var (
ErrNoNetwork = errors.New("Networking not available to load resource")
ErrNotFound = errors.New("Failed to find resource")
)
type AnyMap map[interface{}]interface{}
func Contains(values []string, value string) bool {
@ -256,32 +248,6 @@ func ToStrings(data []interface{}) []string {
return result
}
func GetServices(urls []string) ([]string, error) {
result := []string{}
for _, url := range urls {
indexUrl := fmt.Sprintf("%s/index.yml", url)
content, err := LoadResource(indexUrl, true, []string{})
if err != nil {
log.Errorf("Failed to load %s: %v", indexUrl, err)
continue
}
services := make(map[string][]string)
err = yaml.Unmarshal(content, &services)
if err != nil {
log.Errorf("Failed to unmarshal %s: %v", indexUrl, err)
continue
}
if list, ok := services["services"]; ok {
result = append(result, list...)
}
}
return result, nil
}
func DirLs(dir string) ([]interface{}, error) {
result := []interface{}{}
files, err := ioutil.ReadDir(dir)
@ -294,49 +260,6 @@ func DirLs(dir string) ([]interface{}, error) {
return result, nil
}
func retryHttp(f func() (*http.Response, error), times int) (resp *http.Response, err error) {
for i := 0; i < times; i++ {
if resp, err = f(); err == nil {
return
}
log.Warnf("Error making HTTP request: %s. Retrying", err)
}
return
}
func LoadResource(location string, network bool, urls []string) ([]byte, error) {
var bytes []byte
err := ErrNotFound
if strings.HasPrefix(location, "http:/") || strings.HasPrefix(location, "https:/") {
if !network {
return nil, ErrNoNetwork
}
resp, err := retryHttp(func() (*http.Response, error) { return http.Get(location) }, 8)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("non-200 http response: %d", resp.StatusCode)
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
} else if strings.HasPrefix(location, "/") {
return ioutil.ReadFile(location)
} else if len(location) > 0 {
for _, url := range urls {
ymlUrl := fmt.Sprintf("%s/%s/%s.yml", url, location[0:1], location)
bytes, err = LoadResource(ymlUrl, network, []string{})
if err == nil {
log.Debugf("Loaded %s from %s", location, ymlUrl)
return bytes, nil
}
}
}
return nil, err
}
func Map2KVPairs(m map[string]string) []string {
r := make([]string, 0, len(m))
for k, v := range m {

View File

@ -1,9 +1,9 @@
package util
import (
"github.com/stretchr/testify/require"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
type testCloudConfig struct {
@ -180,18 +180,3 @@ func TestMapsUnion(t *testing.T) {
}
assert.Equal(expected, MapsUnion(m0, m1))
}
func NoTestLoadResourceSimple(t *testing.T) {
assert := require.New(t)
expected := `services:
- debian-console
- ubuntu-console
`
expected = strings.TrimSpace(expected)
b, e := LoadResource("https://raw.githubusercontent.com/rancher/os-services/v0.3.4/index.yml", true, []string{})
assert.Nil(e)
assert.Equal(expected, strings.TrimSpace(string(b)))
}