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:
commit
a9ca80d47d
@ -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)
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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, "")
|
||||
|
@ -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
|
||||
|
8
tests/integration/assets/test_17/cloud-config.yml
Normal file
8
tests/integration/assets/test_17/cloud-config.yml
Normal 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
|
45
tests/integration/rostest/test_17_http_proxy.py
Normal file
45
tests/integration/rostest/test_17_http_proxy.py
Normal 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
120
util/network/network.go
Normal 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
|
||||
}
|
23
util/network/network_test.go
Normal file
23
util/network/network_test.go
Normal 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)))
|
||||
}
|
77
util/util.go
77
util/util.go
@ -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 {
|
||||
|
@ -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)))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user