entryMaker/config/config.go (208 lines of code) (raw):
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package config
import (
"errors"
"flag"
"fmt"
"io/ioutil"
"os"
"syscall"
"github.com/mitchellh/mapstructure"
"golang.org/x/crypto/ssh/terminal"
"gopkg.in/yaml.v2"
)
const ProductionPrefix string = "https://firefox.settings.services.mozilla.com"
const StagePrefix string = "https://firefox.settings.services.allizom.org"
const RecordsPathPrefix string = "/v1/buckets/"
const RecordsPathSuffix string = "/collections/onecrl/records"
const PREFIX_BUGZILLA_PROD string = "https://bugzilla.mozilla.org"
const PREFIX_BUGZILLA_STAGE string = "https://bugzilla.allizom.org"
const DEFAULT_BUG_PRODUCT string = "Core"
const DEFAULT_BUG_COMPONENT string = "Security Block-lists, Allow-lists, and other State"
const DEFAULT_BUG_VERSION string = "unspecified"
type OneCRLConfig struct {
oneCRLConfig string
oneCRLEnvString string `mapstructure:"onecrlenv"`
oneCRLBucketString string `mapstructure:"onecrlbucket"`
OneCRLVerbose string `mapstructure:"onecrlverbose"`
BugzillaBase string `mapstructure:"bugzilla"`
BugzillaAPIKey string `mapstructure:"bzapikey"`
BugzillaReviewers string `mapstructure:"reviewers"`
BugProduct string `mapstructure:"bugproduct"`
BugComponent string `mapstructure:"bugcomponent"`
BugVersion string `mapstructure:"bugversion"`
BugzillaBlockee string `mapstructure:"blockee"`
BugDescription string `mapstructure:"bugdescription"`
Preview string `mapstructure:"preview"`
EnforceCRLChecks string `mapstructure:"enforcecrlchecks"`
KintoUser string `mapstructure:"kintouser"`
KintoPassword string `mapstructure:"kintopass"`
KintoToken string `mapstructure:"kintotoken"`
KintoCollectionURL string `mapstructure:"collectionurl"`
SkipBugzilla bool // Must be set by CLI flags
AdditionalConfig map[string]string
}
// GetRecordURLForEnv returns the the URL (as a string) for a given OneCRL Environment ("stage" or "production")
func (config OneCRLConfig) GetRecordURLForEnv(environment string) (error, string) {
var RecordsPath string = RecordsPathPrefix + config.oneCRLBucketString + RecordsPathSuffix
if environment == "stage" {
return nil, StagePrefix + RecordsPath
}
if environment == "production" {
return nil, ProductionPrefix + RecordsPath
}
return errors.New("valid onecrlenv values are \"stage\" and \"production\""), ""
}
func (config OneCRLConfig) GetRecordURL() (error, string) {
return config.GetRecordURLForEnv(config.oneCRLEnvString)
}
const DEFAULT_ONECRLCONFIG string = ".config.yml"
const DEFAULT_ONECRLENV string = "production"
const DEFAULT_ONECRLBUCKET string = "security-state"
const DEFAULT_ONECRLVERBOSE string = "no"
const DEFAULT_COLLECTION_URL string = "https://remote-settings.allizom.org/v1/buckets/ecurity-state-staging/collections/onecrl"
const DEFAULT_DEFAULT string = ""
const DEFAULT_PREVIEW string = "no"
const DEFAULT_ENFORCE_CRL_CHECKS string = "yes"
const DEFAULT_DESCRIPTION string = "Here are some entries: Please ensure that the entries are correct."
func (config *OneCRLConfig) loadConfig() error {
// load the config from configuration file
filename := config.oneCRLConfig
fmt.Printf("config file was: %v\n", filename)
if filename == DEFAULT_ONECRLCONFIG {
envFilename := os.Getenv("onecrlconfig")
fmt.Printf("Looking for config file in environment: %v\n", envFilename)
if 0 != len(envFilename) {
filename = envFilename
}
}
if len(filename) == 0 {
filename = DEFAULT_ONECRLCONFIG
}
data, err := ioutil.ReadFile(filename)
if nil != err {
return err
}
// Load the yaml into a map first - so we capture additional config options
configMap := map[string]string{}
yaml.Unmarshal(data, &configMap)
// Transfer entries from the map that we recognise
loaded := OneCRLConfig{}
var md mapstructure.Metadata
decoderConfig := &mapstructure.DecoderConfig{
Metadata: &md,
Result: &loaded,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
panic(err)
}
if err := decoder.Decode(configMap); err != nil {
panic(err)
}
// Loop over the unused keys, add them to additional config
if len(md.Unused) > 0 {
if nil == config.AdditionalConfig {
config.AdditionalConfig = make(map[string]string)
}
for _, key := range md.Unused {
fmt.Printf("Key is %v\n", key)
config.AdditionalConfig[key] = configMap[key]
}
}
// Check the config values to see if any are already overridden
// for each value, if it's unset, copy the config file's value (if present)
if config.oneCRLEnvString == DEFAULT_ONECRLENV && loaded.oneCRLEnvString != "" {
config.oneCRLEnvString = loaded.oneCRLEnvString
}
if config.oneCRLBucketString == DEFAULT_ONECRLBUCKET && loaded.oneCRLBucketString != "" {
config.oneCRLBucketString = loaded.oneCRLBucketString
}
fmt.Printf("loaded bugzilla base is %s\n", loaded.BugzillaBase)
if config.BugzillaBase == PREFIX_BUGZILLA_PROD && loaded.BugzillaBase != "" {
fmt.Printf("overriding with loaded bugzilla base\n")
config.BugzillaBase = loaded.BugzillaBase
fmt.Printf("overridden bugzilla base is %s\n", config.BugzillaBase)
}
if config.BugzillaAPIKey == DEFAULT_DEFAULT {
// if it's set in config, use that value
if loaded.BugzillaAPIKey != "" {
config.BugzillaAPIKey = loaded.BugzillaAPIKey
} else {
// attempt to get a value from environment
config.BugzillaAPIKey = os.Getenv("bzapikey")
}
}
//Bug report settings
if config.BugProduct == DEFAULT_BUG_PRODUCT && loaded.BugProduct != "" {
config.BugProduct = loaded.BugProduct
}
if config.BugComponent == DEFAULT_BUG_COMPONENT && loaded.BugComponent != "" {
config.BugComponent = loaded.BugComponent
}
if config.BugVersion == DEFAULT_BUG_VERSION && loaded.BugVersion != "" {
config.BugVersion = loaded.BugVersion
}
if config.BugzillaReviewers == DEFAULT_DEFAULT && loaded.BugzillaReviewers != "" {
config.BugzillaReviewers = loaded.BugzillaReviewers
}
if config.BugzillaBlockee == DEFAULT_DEFAULT && loaded.BugzillaBlockee != "" {
config.BugzillaBlockee = loaded.BugzillaBlockee
}
if config.BugDescription == DEFAULT_DESCRIPTION && loaded.BugDescription != "" {
config.BugDescription = loaded.BugDescription
}
if config.KintoUser == DEFAULT_DEFAULT {
// if it's set in config, use that value
if loaded.KintoUser != "" {
config.KintoUser = loaded.KintoUser
} else {
// attempt to get a value from environment
config.KintoUser = os.Getenv("kintouser")
}
}
if config.Preview == DEFAULT_PREVIEW && loaded.Preview != "" {
config.Preview = loaded.Preview
}
if config.EnforceCRLChecks == DEFAULT_ENFORCE_CRL_CHECKS && loaded.EnforceCRLChecks != "" {
config.EnforceCRLChecks = loaded.EnforceCRLChecks
}
if config.KintoPassword == DEFAULT_DEFAULT {
// if it's set in config, use that value
if loaded.KintoPassword != "" {
config.KintoPassword = loaded.KintoPassword
} else {
// attempt to get a value from environment
config.KintoPassword = os.Getenv("kintopass")
}
}
if config.KintoToken == DEFAULT_DEFAULT {
// if it's set in config, use that value
if loaded.KintoToken != "" {
config.KintoToken = loaded.KintoToken
} else {
// attempt to get a value from environment
config.KintoToken = os.Getenv("kintotoken")
}
}
if config.KintoCollectionURL == DEFAULT_COLLECTION_URL && loaded.KintoCollectionURL != "" {
config.KintoCollectionURL = loaded.KintoCollectionURL
}
if len(config.KintoToken) == 0 && len(config.KintoUser) > 0 && len(config.KintoPassword) == 0 {
fmt.Printf("Please enter the password for user %s\n", config.KintoUser)
bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
if nil != err {
panic(err)
}
config.KintoPassword = string(bytePassword)
}
return nil
}
var conf = OneCRLConfig{}
// GetConfig obtains the system-wide default config including entries loaded from configuration and the environment.
func GetConfig() *OneCRLConfig {
conf.loadConfig()
return &conf
}
// DefineFlags defines the command line flags common to different OneCRL tools.
func DefineFlags() {
flag.StringVar(&conf.oneCRLConfig, "onecrlconfig", DEFAULT_ONECRLCONFIG, "The OneCRL config file")
flag.StringVar(&conf.oneCRLEnvString, "onecrlenv", DEFAULT_ONECRLENV, "The OneCRL Environment to use by default - values other than 'stage' will result in the production instance being used")
flag.StringVar(&conf.oneCRLBucketString, "onecrlbucket", DEFAULT_ONECRLBUCKET, "The OneCRL bucket to use for reads")
flag.StringVar(&conf.OneCRLVerbose, "onecrlverbose", DEFAULT_ONECRLVERBOSE, "Be verbose about OneCRL stuff")
flag.StringVar(&conf.BugzillaBase, "bugzilla", PREFIX_BUGZILLA_PROD, "The bugzilla instance to use by default")
flag.StringVar(&conf.BugzillaAPIKey, "bzapikey", DEFAULT_DEFAULT, "The bugzilla API key")
flag.StringVar(&conf.BugProduct, "bugproduct", DEFAULT_BUG_PRODUCT, "The defualt product of the bug")
flag.StringVar(&conf.BugComponent, "bugcomponent", DEFAULT_BUG_COMPONENT, "The defualt product component of the bug")
flag.StringVar(&conf.BugVersion, "bugversion", DEFAULT_BUG_VERSION, "The defualt component version of the bug")
flag.StringVar(&conf.BugzillaReviewers, "reviewers", DEFAULT_DEFAULT, "The reviewers for the buzilla attachmenets")
flag.StringVar(&conf.BugzillaBlockee, "blockee", DEFAULT_DEFAULT, "What bugzilla bug should this bug block")
flag.StringVar(&conf.BugDescription, "bugdescription", DEFAULT_DESCRIPTION, "The bugzilla comment to put in the bug")
flag.StringVar(&conf.Preview, "preview", DEFAULT_PREVIEW, "Preview (don't write changes)")
flag.StringVar(&conf.EnforceCRLChecks, "enforcecrlchecks", DEFAULT_ENFORCE_CRL_CHECKS, "Enforce CRL checks (options: yes, no)")
flag.StringVar(&conf.KintoUser, "kintouser", DEFAULT_DEFAULT, "The kinto user")
flag.StringVar(&conf.KintoPassword, "kintopass", DEFAULT_DEFAULT, "The kinto user's pasword")
flag.StringVar(&conf.KintoCollectionURL, "collectionurl", DEFAULT_COLLECTION_URL, "The kinto collection URL")
flag.BoolVar(&conf.SkipBugzilla, "skipbugzilla", false, "Skip updating Bugzilla")
}