Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add new -rsh/--remoteServiceHosts flag and corresponding env override #596

Merged
merged 4 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions bootstrap/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ const (
deviceServicesKey = "device-services"
)

var invalidRemoteHostsError = errors.New("-rsh/--remoteServiceHosts must contain 3 and only 3 comma seperated host names")

// UpdatedStream defines the stream type that is notified by ListenForChanges when a configuration update is received.
type UpdatedStream chan struct{}

Expand Down Expand Up @@ -124,6 +126,7 @@ func (cp *Processor) Process(

cp.overwriteConfig = cp.flags.OverwriteConfig()
configProviderUrl := cp.flags.ConfigProviderUrl()
remoteHosts := environment.GetRemoteServiceHosts(cp.lc, cp.flags.RemoteServiceHosts())

// Create new ProviderInfo and initialize it from command-line flag or Variables
configProviderInfo, err := NewProviderInfo(cp.envVars, configProviderUrl)
Expand All @@ -133,10 +136,30 @@ func (cp *Processor) Process(

useProvider := configProviderInfo.UseProvider()

mode := &container.DevRemoteMode{
InDevMode: cp.flags.InDevMode(),
InRemoteMode: remoteHosts != nil,
}

cp.dic.Update(di.ServiceConstructorMap{
container.DevRemoteModeName: func(get di.Get) interface{} {
return mode
},
})

var privateConfigClient configuration.Client
var privateServiceConfig interfaces.Configuration

if useProvider {
if remoteHosts != nil {
if len(remoteHosts) != 3 {
return invalidRemoteHostsError
}

cp.lc.Infof("Setting config Provider host to %s", remoteHosts[1])
configProviderInfo.SetHost(remoteHosts[1])
}

getAccessToken, err := cp.getAccessTokenCallback(serviceKey, secretProvider, err, configProviderInfo)
if err != nil {
return err
Expand Down Expand Up @@ -283,9 +306,51 @@ func (cp *Processor) Process(
}
}

if remoteHosts != nil {
err = applyRemoteHosts(remoteHosts, serviceConfig)
if err != nil {
return err
}
}

return err
}

func applyRemoteHosts(remoteHosts []string, serviceConfig interfaces.Configuration) error {
if len(remoteHosts) != 3 {
return invalidRemoteHostsError
}

config := serviceConfig.GetBootstrap()

config.Service.Host = remoteHosts[0]
config.Service.ServerBindAddr = remoteHosts[2]

if config.Config != nil {
config.Config.Host = remoteHosts[1]
}

if config.MessageBus != nil {
config.MessageBus.Host = remoteHosts[1]
}

if config.Registry != nil {
config.Registry.Host = remoteHosts[1]
}

if config.Database != nil {
config.Database.Host = remoteHosts[1]
}

if config.Clients != nil {
for _, client := range *config.Clients {
client.Host = remoteHosts[1]
}
}

return nil
}

type createProviderCallback func(
logger.LoggingClient,
string,
Expand Down
34 changes: 33 additions & 1 deletion bootstrap/config/config_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2022 Intel Corp.
* Copyright 2023 Intel Corp.
*
* 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
Expand Down Expand Up @@ -490,3 +490,35 @@ func TestGetInsecureSecretDataFullPath(t *testing.T) {
})
}
}

func TestProcessorApplyRemoteHosts(t *testing.T) {
mockStruct := ConfigurationMockStruct{
Registry: config.RegistryInfo{},
Service: config.ServiceInfo{},
MessageBus: config.MessageBusInfo{},
Clients: config.ClientsCollection{
"core-metadata": {},
},
Database: config.Database{},
Config: config.ConfigProviderInfo{},
}

localIP := "1.2.3.4"
remoteIP := "5.6.7.8"
srvBindIP := "localhost"
hosts := []string{localIP, remoteIP, srvBindIP}
err := applyRemoteHosts(hosts, &mockStruct)
require.NoError(t, err)

assert.Equal(t, localIP, mockStruct.Service.Host)
assert.Equal(t, srvBindIP, mockStruct.Service.ServerBindAddr)
assert.Equal(t, remoteIP, mockStruct.Clients["core-metadata"].Host)
assert.Equal(t, remoteIP, mockStruct.Database.Host)
assert.Equal(t, remoteIP, mockStruct.MessageBus.Host)
assert.Equal(t, remoteIP, mockStruct.Registry.Host)
assert.Equal(t, remoteIP, mockStruct.Config.Host)

hosts = []string{localIP, remoteIP}
err = applyRemoteHosts(hosts, &mockStruct)
require.Error(t, err)
}
18 changes: 14 additions & 4 deletions bootstrap/config/configmock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@ type WritableInfo struct {
}

type ConfigurationMockStruct struct {
Writable WritableInfo
Registry config.RegistryInfo
Trigger TriggerInfo
Writable WritableInfo
Registry config.RegistryInfo
Service config.ServiceInfo
MessageBus config.MessageBusInfo
Clients config.ClientsCollection
Database config.Database
Config config.ConfigProviderInfo
Trigger TriggerInfo
}

type TriggerInfo struct {
Expand Down Expand Up @@ -64,7 +69,12 @@ func (c *ConfigurationMockStruct) UpdateWritableFromRaw(rawWritable interface{})

func (c *ConfigurationMockStruct) GetBootstrap() config.BootstrapConfiguration {
return config.BootstrapConfiguration{
Registry: &c.Registry,
Clients: &c.Clients,
Service: &c.Service,
Config: &c.Config,
Registry: &c.Registry,
MessageBus: &c.MessageBus,
Database: &c.Database,
}
}

Expand Down
9 changes: 7 additions & 2 deletions bootstrap/config/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,16 @@ func NewProviderInfo(envVars *environment.Variables, providerUrl string) (*Provi
}

// UseProvider returns whether the Configuration Provider should be used or not.
func (config ProviderInfo) UseProvider() bool {
func (config *ProviderInfo) UseProvider() bool {
return config.serviceConfig.Host != ""
}

// SetHost sets the host name for the Configuration Provider.
func (config *ProviderInfo) SetHost(host string) {
config.serviceConfig.Host = host
}

// ServiceConfig returns service configuration for the Configuration Provider
func (config ProviderInfo) ServiceConfig() types.ServiceConfig {
func (config *ProviderInfo) ServiceConfig() types.ServiceConfig {
return config.serviceConfig
}
2 changes: 1 addition & 1 deletion bootstrap/config/testdata/all-service-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ all-services:
Database:
Host: "localhost"
Port: 6379
Timeout: 5000
Timeout: "5s"
Type: "redisdb"

MessageBus:
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/config/testdata/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ all-services:
Database:
Host: "localhost"
Port: 6379
Timeout: 5000
Timeout: "5s"
Type: "redisdb"

MessageBus:
Expand Down
37 changes: 37 additions & 0 deletions bootstrap/container/dev_remote_mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright 2023 Intel Inc.
*
* 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 container

import (
"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
)

type DevRemoteMode struct {
InDevMode bool
InRemoteMode bool
}

// DevRemoteModeName contains the name of the DevRemoteMode struct in the DIC.
var DevRemoteModeName = di.TypeInstanceToName((*DevRemoteMode)(nil))

// DevRemoteModeFrom helper function queries the DIC and returns the Dev and Remotes mode flags.
func DevRemoteModeFrom(get di.Get) DevRemoteMode {
devOrRemoteMode, ok := get(DevRemoteModeName).(*DevRemoteMode)
if !ok {
return DevRemoteMode{}
}

return *devOrRemoteMode
}
31 changes: 22 additions & 9 deletions bootstrap/environment/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ const (
bootRetrySecondsDefault = 1
defaultConfigDirValue = "./res"

envKeyConfigUrl = "EDGEX_CONFIG_PROVIDER"
envKeyCommonConfig = "EDGEX_COMMON_CONFIG"
envKeyUseRegistry = "EDGEX_USE_REGISTRY"
envKeyStartupDuration = "EDGEX_STARTUP_DURATION"
envKeyStartupInterval = "EDGEX_STARTUP_INTERVAL"
envKeyConfigDir = "EDGEX_CONFIG_DIR"
envKeyProfile = "EDGEX_PROFILE"
envKeyConfigFile = "EDGEX_CONFIG_FILE"
envKeyFileURITimeout = "EDGEX_FILE_URI_TIMEOUT"
envKeyConfigUrl = "EDGEX_CONFIG_PROVIDER"
envKeyCommonConfig = "EDGEX_COMMON_CONFIG"
envKeyUseRegistry = "EDGEX_USE_REGISTRY"
envKeyStartupDuration = "EDGEX_STARTUP_DURATION"
envKeyStartupInterval = "EDGEX_STARTUP_INTERVAL"
envKeyConfigDir = "EDGEX_CONFIG_DIR"
envKeyProfile = "EDGEX_PROFILE"
envKeyConfigFile = "EDGEX_CONFIG_FILE"
envKeyFileURITimeout = "EDGEX_FILE_URI_TIMEOUT"
envKeyRemoteServiceHosts = "EDGEX_REMOTE_SERVICE_HOSTS"

noConfigProviderValue = "none"

Expand Down Expand Up @@ -478,3 +479,15 @@ func GetURIRequestTimeout(lc logger.LoggingClient) time.Duration {
lc.Infof("Variables override of 'URI Request Timeout' by environment variable: %s=%s", envKeyFileURITimeout, envValue)
return requestTimeout
}

// GetRemoteServiceHosts gets the Remote Service host name list from an environment variable (if it exists), if not returns the passed in (default) value
func GetRemoteServiceHosts(lc logger.LoggingClient, remoteHosts []string) []string {
envValue := os.Getenv(envKeyRemoteServiceHosts)
if len(envValue) <= 0 {
return remoteHosts
}

logEnvironmentOverride(lc, "-rsh/--remoteServiceHosts", envKeyRemoteServiceHosts, envValue)

return strings.Split(envValue, ",")
}
32 changes: 31 additions & 1 deletion bootstrap/environment/variables_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Copyright 2019 Dell Inc.
* Copyright 2020 Intel Inc.
* Copyright 2023 Intel Inc.
*
* 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
Expand Down Expand Up @@ -180,6 +180,36 @@ func TestGetConfigDir(t *testing.T) {
}
}

func TestGetRemoteServiceHosts(t *testing.T) {
_, lc := initializeTest()

testCases := []struct {
TestName string
EnvName string
EnvValue string
PassedIn []string
Expected []string
}{
{"With Env Var", envKeyRemoteServiceHosts, "1,2,3", nil, []string{"1", "2", "3"}},
{"With No Env Var and passed in", "", "", []string{"1", "2", "3"}, []string{"1", "2", "3"}},
{"With No Env Var and no passed in", "", "", nil, nil},
}

for _, test := range testCases {
t.Run(test.TestName, func(t *testing.T) {
os.Clearenv()

if len(test.EnvName) > 0 {
err := os.Setenv(test.EnvName, test.EnvValue)
require.NoError(t, err)
}

actual := GetRemoteServiceHosts(lc, test.PassedIn)
assert.Equal(t, test.Expected, actual)
})
}
}

func TestGetProfileDir(t *testing.T) {
_, lc := initializeTest()

Expand Down
Loading