github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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  )
    18  
    19  type toolsDatasourceFuncId struct {
    20  	id string
    21  	f  ToolsDataSourceFunc
    22  }
    23  
    24  var (
    25  	toolsDatasourceFuncsMu sync.RWMutex
    26  	toolsDatasourceFuncs   []toolsDatasourceFuncId
    27  )
    28  
    29  // ToolsDataSourceFunc is a function type that takes an environment and
    30  // returns a simplestreams datasource.
    31  //
    32  // ToolsDataSourceFunc will be used in GetMetadataSources.
    33  // Any error satisfying errors.IsNotSupported will be ignored;
    34  // any other error will be cause GetMetadataSources to fail.
    35  type ToolsDataSourceFunc func(environs.Environ) (simplestreams.DataSource, error)
    36  
    37  // RegisterToolsDataSourceFunc registers an ToolsDataSourceFunc
    38  // with the specified id, overwriting any function previously registered
    39  // with the same id.
    40  func RegisterToolsDataSourceFunc(id string, f ToolsDataSourceFunc) {
    41  	toolsDatasourceFuncsMu.Lock()
    42  	defer toolsDatasourceFuncsMu.Unlock()
    43  	for i := range toolsDatasourceFuncs {
    44  		if toolsDatasourceFuncs[i].id == id {
    45  			toolsDatasourceFuncs[i].f = f
    46  			return
    47  		}
    48  	}
    49  	toolsDatasourceFuncs = append(toolsDatasourceFuncs, toolsDatasourceFuncId{id, f})
    50  }
    51  
    52  // UnregisterToolsDataSourceFunc unregisters an ToolsDataSourceFunc
    53  // with the specified id.
    54  func UnregisterToolsDataSourceFunc(id string) {
    55  	toolsDatasourceFuncsMu.Lock()
    56  	defer toolsDatasourceFuncsMu.Unlock()
    57  	for i, f := range toolsDatasourceFuncs {
    58  		if f.id == id {
    59  			head := toolsDatasourceFuncs[:i]
    60  			tail := toolsDatasourceFuncs[i+1:]
    61  			toolsDatasourceFuncs = append(head, tail...)
    62  			return
    63  		}
    64  	}
    65  }
    66  
    67  // GetMetadataSources returns the sources to use when looking for
    68  // simplestreams tools metadata for the given stream.
    69  func GetMetadataSources(env environs.Environ) ([]simplestreams.DataSource, error) {
    70  	config := env.Config()
    71  
    72  	// Add configured and environment-specific datasources.
    73  	var sources []simplestreams.DataSource
    74  	if userURL, ok := config.AgentMetadataURL(); ok {
    75  		verify := utils.VerifySSLHostnames
    76  		if !config.SSLHostnameVerification() {
    77  			verify = utils.NoVerifySSLHostnames
    78  		}
    79  		sources = append(sources, simplestreams.NewURLDataSource(conf.AgentMetadataURLKey, userURL, verify))
    80  	}
    81  
    82  	envDataSources, err := environmentDataSources(env)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	sources = append(sources, envDataSources...)
    87  
    88  	// Add the default, public datasource.
    89  	defaultURL, err := ToolsURL(DefaultBaseURL)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	if defaultURL != "" {
    94  		sources = append(sources,
    95  			simplestreams.NewURLDataSource("default simplestreams", defaultURL, utils.VerifySSLHostnames))
    96  	}
    97  	return sources, nil
    98  }
    99  
   100  // environmentDataSources returns simplestreams datasources for the environment
   101  // by calling the functions registered in RegisterToolsDataSourceFunc.
   102  // The datasources returned will be in the same order the functions were registered.
   103  func environmentDataSources(env environs.Environ) ([]simplestreams.DataSource, error) {
   104  	toolsDatasourceFuncsMu.RLock()
   105  	defer toolsDatasourceFuncsMu.RUnlock()
   106  	var datasources []simplestreams.DataSource
   107  	for _, f := range toolsDatasourceFuncs {
   108  		logger.Debugf("trying datasource %q", f.id)
   109  		datasource, err := f.f(env)
   110  		if err != nil {
   111  			if errors.IsNotSupported(err) {
   112  				continue
   113  			}
   114  			return nil, err
   115  		}
   116  		datasources = append(datasources, datasource)
   117  	}
   118  	return datasources, nil
   119  }
   120  
   121  // ToolsURL returns a valid tools URL constructed from source.
   122  // source may be a directory, or a URL like file://foo or http://foo.
   123  func ToolsURL(source string) (string, error) {
   124  	if source == "" {
   125  		return "", nil
   126  	}
   127  
   128  	return envutils.GetURL(source, storage.BaseToolsPath)
   129  }