Skip to content

Commit

Permalink
add config handler to service, use new config service for geolocation
Browse files Browse the repository at this point in the history
  • Loading branch information
garmr-ulfr committed Jul 30, 2024
1 parent abd8ab1 commit f15ff8f
Show file tree
Hide file tree
Showing 13 changed files with 434 additions and 772 deletions.
18 changes: 12 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
Expand Down Expand Up @@ -209,6 +208,7 @@ func embeddedIsNewer(conf *config, opts *options) bool {
if opts.embeddedRequired {
sentry.CaptureException(log.Errorf("no embedded config for %v", opts.name))
}

return false
}

Expand All @@ -233,23 +233,25 @@ func yamlRoundTrip(o interface{}) interface{} {
if o == nil {
return nil
}

var or interface{}
t := reflect.TypeOf(o)
if t.Kind() == reflect.Ptr {
if t := reflect.TypeOf(o); t.Kind() == reflect.Ptr {
or = reflect.New(t.Elem()).Interface()
} else {
or = reflect.New(t).Interface()
}

b, err := yaml.Marshal(o)
if err != nil {
log.Errorf("Unable to yaml round trip (marshal): %v %v", o, err)
return o
}
err = yaml.Unmarshal(b, or)
if err != nil {

if err = yaml.Unmarshal(b, or); err != nil {
log.Errorf("Unable to yaml round trip (unmarshal): %v %v", o, err)
return o
}

return or
}

Expand Down Expand Up @@ -287,12 +289,13 @@ func (conf *config) saved() (interface{}, error) {
in = rot13.NewReader(infile)
}

bytes, err := ioutil.ReadAll(in)
bytes, err := io.ReadAll(in)
if err != nil {
err = fmt.Errorf("error reading config from %v: %w", conf.filePath, err)
log.Error(err.Error())
return nil, err
}

if len(bytes) == 0 {
return nil, fmt.Errorf("config exists but is empty at %v", conf.filePath)
}
Expand All @@ -311,6 +314,7 @@ func (conf *config) configFetcher(stopCh chan bool, dispatch func(interface{}),
if sleepDuration == noSleep {
sleepDuration = defaultSleep()
}

select {
case <-stopCh:
log.Debug("Stopping polling")
Expand Down Expand Up @@ -370,10 +374,12 @@ func (conf *config) doSaveOne(in []byte) error {
if conf.obfuscate {
out = rot13.NewWriter(outfile)
}

_, err = out.Write(in)
if err != nil {
return fmt.Errorf("unable to write yaml to file %v: %w", conf.filePath, err)
}

log.Debugf("Wrote file at %v", conf.filePath)
return nil
}
200 changes: 100 additions & 100 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@ package config

import (
"errors"
"io/ioutil"
"net/http"
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"

commonconfig "github.com/getlantern/common/config"
"github.com/getlantern/fronted"
"github.com/getlantern/golog"

"github.com/getlantern/flashlight/v7/common"
"github.com/getlantern/flashlight/v7/embeddedconfig"
)

func TestEmptyEmbedded(t *testing.T) {
Expand Down Expand Up @@ -58,7 +55,7 @@ func TestEmbeddedIsNewer(t *testing.T) {
func TestInvalidFile(t *testing.T) {
logger := golog.LoggerFor("config-test")

tmpfile, err := ioutil.TempFile("", "invalid-test-file")
tmpfile, err := os.CreateTemp("", "invalid-test-file")
if err != nil {
logger.Fatal(err)
}
Expand Down Expand Up @@ -106,105 +103,108 @@ func TestObfuscated(t *testing.T) {
})
}

// TestSaved tests reading stored proxies from disk
func TestSaved(t *testing.T) {
withTempDir(t, func(inTempDir func(string) string) {
file := inTempDir("proxies.yaml")
proxiesConfig := newProxiesConfig(t)
writeObfuscatedConfig(t, proxiesConfig, file)

cfg := newConfig(file, &options{
obfuscate: true,
unmarshaler: newProxiesUnmarshaler(),
})

pr, err := cfg.saved()
assert.Nil(t, err)

proxies := pr.(map[string]*commonconfig.ProxyConfig)
chained := proxies["fallback-104.236.192.114"]
assert.True(t, chained != nil)
assert.Equal(t, "104.236.192.114:443", chained.Addr)
})
}

// TestEmbedded tests reading stored proxies from disk
func TestEmbedded(t *testing.T) {
withTempDir(t, func(inTempDir func(string) string) {
file := inTempDir("proxies.yaml")

cfg := newConfig(file, &options{
unmarshaler: newProxiesUnmarshaler(),
})

_, err := cfg.embedded(embeddedconfig.Proxies)
assert.NotNil(t, err)
})
}

func TestPollProxies(t *testing.T) {
withTempDir(t, func(inTempDir func(string) string) {
fronted.ConfigureForTest(t)

file := inTempDir("proxies.yaml")
proxyConfig := newProxiesConfig(t)
writeObfuscatedConfig(t, proxyConfig, file)

proxyChan := make(chan interface{})
cfg := newConfig(file, &options{
unmarshaler: newProxiesUnmarshaler(),
})
var fi os.FileInfo
var err error
for i := 1; i <= 400; i++ {
fi, err = os.Stat(file)
if err == nil {
break
}
time.Sleep(200 * time.Millisecond)
}
if !assert.Nil(t, err) {
return
}

mtime := fi.ModTime()
os.Remove(file)

proxyConfigURLs, _ := startConfigServer(t, proxyConfig)
fetcher := newHttpFetcher(newTestUserConfig(), &http.Transport{}, proxyConfigURLs)
dispatch := func(cfg interface{}) {
proxyChan <- cfg
}
go cfg.configFetcher(nil, dispatch, fetcher, func() time.Duration { return 1 * time.Hour }, log)
proxies := (<-proxyChan).(map[string]*commonconfig.ProxyConfig)

assert.True(t, len(proxies) > 0)
for _, val := range proxies {
assert.True(t, val != nil)
assert.True(t, len(val.Addr) > 6)
}

for i := 1; i <= 400; i++ {
fi, err = os.Stat(file)
if err == nil && fi != nil && fi.ModTime().After(mtime) {
//log.Debugf("Got newer mod time?")
break
}
time.Sleep(50 * time.Millisecond)
}

fi, err = os.Stat(file)

assert.NotNil(t, fi)
assert.Nil(t, err, "Got error: %v", err)

assert.True(t, fi.ModTime().After(mtime))
})
}
/*
commented out for now because this is for the old proxy config stuff
*/

// // TestSaved tests reading stored proxies from disk
// func TestSaved(t *testing.T) {
// withTempDir(t, func(inTempDir func(string) string) {
// file := inTempDir("proxies.yaml")
// proxiesConfig := newProxiesConfig(t)
// writeObfuscatedConfig(t, proxiesConfig, file)
//
// cfg := newConfig(file, &options{
// obfuscate: true,
// unmarshaler: newProxiesUnmarshaler(),
// })
//
// pr, err := cfg.saved()
// assert.Nil(t, err)
//
// proxies := pr.(map[string]*commonconfig.ProxyConfig)
// chained := proxies["fallback-104.236.192.114"]
// assert.True(t, chained != nil)
// assert.Equal(t, "104.236.192.114:443", chained.Addr)
// })
// }

// // TestEmbedded tests reading stored proxies from disk
// func TestEmbedded(t *testing.T) {
// withTempDir(t, func(inTempDir func(string) string) {
// file := inTempDir("proxies.yaml")
//
// cfg := newConfig(file, &options{
// unmarshaler: newProxiesUnmarshaler(),
// })
//
// _, err := cfg.embedded(embeddedconfig.Proxies)
// assert.NotNil(t, err)
// })
// }

// func TestPollProxies(t *testing.T) {
// withTempDir(t, func(inTempDir func(string) string) {
// fronted.ConfigureForTest(t)
//
// file := inTempDir("proxies.yaml")
// proxyConfig := newProxiesConfig(t)
// writeObfuscatedConfig(t, proxyConfig, file)
//
// proxyChan := make(chan interface{})
// cfg := newConfig(file, &options{
// unmarshaler: newProxiesUnmarshaler(),
// })
// var fi os.FileInfo
// var err error
// for i := 1; i <= 400; i++ {
// fi, err = os.Stat(file)
// if err == nil {
// break
// }
// time.Sleep(200 * time.Millisecond)
// }
// if !assert.Nil(t, err) {
// return
// }
//
// mtime := fi.ModTime()
// os.Remove(file)
//
// proxyConfigURLs, _ := startConfigServer(t, proxyConfig)
// fetcher := newHttpFetcher(newTestUserConfig(), &http.Transport{}, proxyConfigURLs)
// dispatch := func(cfg interface{}) {
// proxyChan <- cfg
// }
// go cfg.configFetcher(nil, dispatch, fetcher, func() time.Duration { return 1 * time.Hour }, log)
// proxies := (<-proxyChan).(map[string]*commonconfig.ProxyConfig)
//
// assert.True(t, len(proxies) > 0)
// for _, val := range proxies {
// assert.True(t, val != nil)
// assert.True(t, len(val.Addr) > 6)
// }
//
// for i := 1; i <= 400; i++ {
// fi, err = os.Stat(file)
// if err == nil && fi != nil && fi.ModTime().After(mtime) {
// //log.Debugf("Got newer mod time?")
// break
// }
// time.Sleep(50 * time.Millisecond)
// }
//
// fi, err = os.Stat(file)
//
// assert.NotNil(t, fi)
// assert.Nil(t, err, "Got error: %v", err)
//
// assert.True(t, fi.ModTime().After(mtime))
// })
// }

// TestProductionGlobal validates certain properties of the live production global config
func TestProductionGlobal(t *testing.T) {

testURL := common.GlobalURL // this should always point to the live production configuration (not staging etc)

expectedProviders := map[string]bool{
Expand Down
2 changes: 1 addition & 1 deletion config/global/global.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// This package breaks out some global config handling to where it can be used externally without dependence on all flashlight config.
package globalConfig
package globalconfig

import (
"errors"
Expand Down
18 changes: 3 additions & 15 deletions config/initializer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (

"github.com/stretchr/testify/assert"

commonconfig "github.com/getlantern/common/config"
"github.com/getlantern/eventual"

"github.com/getlantern/flashlight/v7/common"
)

Expand All @@ -27,18 +27,13 @@ func TestInit(t *testing.T) {

// Note these dispatch functions will receive multiple configs -- local ones,
// embedded ones, and remote ones.
proxiesDispatch := func(cfg interface{}, src Source) {
proxies := cfg.(map[string]*commonconfig.ProxyConfig)
assert.True(t, len(proxies) > 0)
gotProxies.Set(true)
}
globalDispatch := func(cfg interface{}, src Source) {
global := cfg.(*Global)
assert.True(t, len(global.Client.MasqueradeSets) > 1)
gotGlobal.Set(true)
}
stop := Init(
".", flags, newTestUserConfig(), proxiesDispatch, nil, globalDispatch, nil, &http.Transport{
".", flags, newTestUserConfig(), globalDispatch, nil, &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
// the same token should also be configured on staging
// config-server, staging proxies and staging DDF distributions.
Expand All @@ -59,7 +54,6 @@ func TestInit(t *testing.T) {
func TestInitWithURLs(t *testing.T) {
withTempDir(t, func(inTempDir func(string) string) {
globalConfig := newGlobalConfig(t)
proxiesConfig := newProxiesConfig(t)

globalConfig.GlobalConfigPollInterval = 3 * time.Second
globalConfig.ProxyConfigPollInterval = 1 * time.Second
Expand All @@ -75,20 +69,15 @@ func TestInitWithURLs(t *testing.T) {
// set up servers to serve global config and count number of requests
globalConfigURL, globalReqCount := startConfigServer(t, globalConfig)

// set up servers to serve global config and count number of requests
proxyConfigURL, proxyReqCount := startConfigServer(t, proxiesConfig)

// set up and call InitWithURLs
flags := make(map[string]interface{})
flags["staging"] = true

proxiesDispatch := func(interface{}, Source) {}
globalDispatch := func(interface{}, Source) {}
stop := InitWithURLs(
inTempDir("."), flags, newTestUserConfig(),
proxiesDispatch, nil,
globalDispatch, nil,
proxyConfigURL, globalConfigURL, &http.Transport{})
globalConfigURL, &http.Transport{})
defer stop()

// sleep some amount
Expand All @@ -100,7 +89,6 @@ func TestInitWithURLs(t *testing.T) {

// test that proxy & config servers were called the correct number of times
assert.GreaterOrEqual(t, 3, int(globalReqCount()), "should have fetched global config every %v", globalConfig.GlobalConfigPollInterval)
assert.GreaterOrEqual(t, 7, int(proxyReqCount()), "should have fetched proxy config every %v", globalConfig.ProxyConfigPollInterval)
})
}

Expand Down
Loading

0 comments on commit f15ff8f

Please sign in to comment.