github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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.Environ) ([]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(env environs.Environ) ([]simplestreams.DataSource, error) { 105 toolsDatasourceFuncsMu.RLock() 106 defer toolsDatasourceFuncsMu.RUnlock() 107 var datasources []simplestreams.DataSource 108 for _, f := range toolsDatasourceFuncs { 109 logger.Debugf("trying datasource %q", f.id) 110 datasource, err := f.f(env) 111 if err != nil { 112 if errors.IsNotSupported(err) { 113 continue 114 } 115 return nil, err 116 } 117 datasources = append(datasources, datasource) 118 } 119 return datasources, nil 120 } 121 122 // ToolsURL returns a valid tools URL constructed from source. 123 // source may be a directory, or a URL like file://foo or http://foo. 124 func ToolsURL(source string) (string, error) { 125 if source == "" { 126 return "", nil 127 } 128 129 return envutils.GetURL(source, storage.BaseToolsPath) 130 }