github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/environs/tools/urls.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package tools 5 6 import ( 7 "sync" 8 9 "github.com/juju/errors" 10 "github.com/juju/utils" 11 12 "github.com/juju/juju/environs" 13 conf "github.com/juju/juju/environs/config" 14 "github.com/juju/juju/environs/simplestreams" 15 "github.com/juju/juju/environs/storage" 16 envutils "github.com/juju/juju/environs/utils" 17 "github.com/juju/juju/juju/keys" 18 ) 19 20 type toolsDatasourceFuncId struct { 21 id string 22 f ToolsDataSourceFunc 23 } 24 25 var ( 26 toolsDatasourceFuncsMu sync.RWMutex 27 toolsDatasourceFuncs []toolsDatasourceFuncId 28 ) 29 30 // ToolsDataSourceFunc is a function type that takes an environment and 31 // returns a simplestreams datasource. 32 // 33 // ToolsDataSourceFunc will be used in GetMetadataSources. 34 // Any error satisfying errors.IsNotSupported will be ignored; 35 // any other error will be cause GetMetadataSources to fail. 36 type ToolsDataSourceFunc func(environs.Environ) (simplestreams.DataSource, error) 37 38 // RegisterToolsDataSourceFunc registers an ToolsDataSourceFunc 39 // with the specified id, overwriting any function previously registered 40 // with the same id. 41 func RegisterToolsDataSourceFunc(id string, f ToolsDataSourceFunc) { 42 toolsDatasourceFuncsMu.Lock() 43 defer toolsDatasourceFuncsMu.Unlock() 44 for i := range toolsDatasourceFuncs { 45 if toolsDatasourceFuncs[i].id == id { 46 toolsDatasourceFuncs[i].f = f 47 return 48 } 49 } 50 toolsDatasourceFuncs = append(toolsDatasourceFuncs, toolsDatasourceFuncId{id, f}) 51 } 52 53 // UnregisterToolsDataSourceFunc unregisters an ToolsDataSourceFunc 54 // with the specified id. 55 func UnregisterToolsDataSourceFunc(id string) { 56 toolsDatasourceFuncsMu.Lock() 57 defer toolsDatasourceFuncsMu.Unlock() 58 for i, f := range toolsDatasourceFuncs { 59 if f.id == id { 60 head := toolsDatasourceFuncs[:i] 61 tail := toolsDatasourceFuncs[i+1:] 62 toolsDatasourceFuncs = append(head, tail...) 63 return 64 } 65 } 66 } 67 68 // GetMetadataSources returns the sources to use when looking for 69 // simplestreams tools metadata for the given stream. 70 func GetMetadataSources(env environs.BootstrapEnviron) ([]simplestreams.DataSource, error) { 71 config := env.Config() 72 73 // Add configured and environment-specific datasources. 74 var sources []simplestreams.DataSource 75 if userURL, ok := config.AgentMetadataURL(); ok { 76 verify := utils.VerifySSLHostnames 77 if !config.SSLHostnameVerification() { 78 verify = utils.NoVerifySSLHostnames 79 } 80 sources = append(sources, simplestreams.NewURLSignedDataSource(conf.AgentMetadataURLKey, userURL, keys.JujuPublicKey, verify, simplestreams.SPECIFIC_CLOUD_DATA, false)) 81 } 82 83 envDataSources, err := environmentDataSources(env) 84 if err != nil { 85 return nil, err 86 } 87 sources = append(sources, envDataSources...) 88 89 // Add the default, public datasource. 90 defaultURL, err := ToolsURL(DefaultBaseURL) 91 if err != nil { 92 return nil, err 93 } 94 if defaultURL != "" { 95 sources = append(sources, 96 simplestreams.NewURLSignedDataSource("default simplestreams", defaultURL, keys.JujuPublicKey, utils.VerifySSLHostnames, simplestreams.DEFAULT_CLOUD_DATA, true)) 97 } 98 return sources, nil 99 } 100 101 // environmentDataSources returns simplestreams datasources for the environment 102 // by calling the functions registered in RegisterToolsDataSourceFunc. 103 // The datasources returned will be in the same order the functions were registered. 104 func environmentDataSources(bootstrapEnviron environs.BootstrapEnviron) ([]simplestreams.DataSource, error) { 105 toolsDatasourceFuncsMu.RLock() 106 defer toolsDatasourceFuncsMu.RUnlock() 107 108 var datasources []simplestreams.DataSource 109 env, ok := bootstrapEnviron.(environs.Environ) 110 if !ok { 111 logger.Debugf("environmentDataSources is supported for IAAS, environ %#v is not Environ", bootstrapEnviron) 112 // ignore for CAAS 113 return datasources, nil 114 } 115 for _, f := range toolsDatasourceFuncs { 116 logger.Debugf("trying datasource %q", f.id) 117 datasource, err := f.f(env) 118 if err != nil { 119 if errors.IsNotSupported(err) { 120 continue 121 } 122 return nil, err 123 } 124 datasources = append(datasources, datasource) 125 } 126 return datasources, nil 127 } 128 129 // ToolsURL returns a valid tools URL constructed from source. 130 // source may be a directory, or a URL like file://foo or http://foo. 131 func ToolsURL(source string) (string, error) { 132 if source == "" { 133 return "", nil 134 } 135 136 return envutils.GetURL(source, storage.BaseToolsPath) 137 }