github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/environs/imagemetadata.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package environs
     5  
     6  import (
     7  	"sync"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/utils"
    11  
    12  	"github.com/juju/juju/environs/imagemetadata"
    13  	"github.com/juju/juju/environs/simplestreams"
    14  )
    15  
    16  type datasourceFuncId struct {
    17  	id string
    18  	f  ImageDataSourceFunc
    19  }
    20  
    21  var (
    22  	datasourceFuncsMu sync.RWMutex
    23  	datasourceFuncs   []datasourceFuncId
    24  )
    25  
    26  // ImageDataSourceFunc is a function type that takes an environment and
    27  // returns a simplestreams datasource.
    28  //
    29  // ImageDataSourceFunc will be used in ImageMetadataSources.
    30  // Any error satisfying errors.IsNotSupported will be ignored;
    31  // any other error will be cause ImageMetadataSources to fail.
    32  type ImageDataSourceFunc func(Environ) (simplestreams.DataSource, error)
    33  
    34  // RegisterImageDataSourceFunc registers an ImageDataSourceFunc
    35  // with the specified id, overwriting any function previously registered
    36  // with the same id.
    37  func RegisterImageDataSourceFunc(id string, f ImageDataSourceFunc) {
    38  	datasourceFuncsMu.Lock()
    39  	defer datasourceFuncsMu.Unlock()
    40  	for i := range datasourceFuncs {
    41  		if datasourceFuncs[i].id == id {
    42  			datasourceFuncs[i].f = f
    43  			return
    44  		}
    45  	}
    46  	datasourceFuncs = append(datasourceFuncs, datasourceFuncId{id, f})
    47  }
    48  
    49  // UnregisterImageDataSourceFunc unregisters an ImageDataSourceFunc
    50  // with the specified id.
    51  func UnregisterImageDataSourceFunc(id string) {
    52  	datasourceFuncsMu.Lock()
    53  	defer datasourceFuncsMu.Unlock()
    54  	for i, f := range datasourceFuncs {
    55  		if f.id == id {
    56  			head := datasourceFuncs[:i]
    57  			tail := datasourceFuncs[i+1:]
    58  			datasourceFuncs = append(head, tail...)
    59  			return
    60  		}
    61  	}
    62  }
    63  
    64  // ImageMetadataSources returns the sources to use when looking for
    65  // simplestreams image id metadata for the given stream.
    66  func ImageMetadataSources(env Environ) ([]simplestreams.DataSource, error) {
    67  	config := env.Config()
    68  
    69  	// Add configured and environment-specific datasources.
    70  	var sources []simplestreams.DataSource
    71  	if userURL, ok := config.ImageMetadataURL(); ok {
    72  		verify := utils.VerifySSLHostnames
    73  		if !config.SSLHostnameVerification() {
    74  			verify = utils.NoVerifySSLHostnames
    75  		}
    76  		sources = append(sources, simplestreams.NewURLDataSource("image-metadata-url", userURL, verify))
    77  	}
    78  
    79  	envDataSources, err := environmentDataSources(env)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	sources = append(sources, envDataSources...)
    84  
    85  	// Add the default, public datasource.
    86  	defaultURL, err := imagemetadata.ImageMetadataURL(imagemetadata.DefaultBaseURL, config.ImageStream())
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	if defaultURL != "" {
    91  		sources = append(sources,
    92  			simplestreams.NewURLDataSource("default cloud images", defaultURL, utils.VerifySSLHostnames))
    93  	}
    94  	return sources, nil
    95  }
    96  
    97  // environmentDataSources returns simplestreams datasources for the environment
    98  // by calling the functions registered in RegisterImageDataSourceFunc.
    99  // The datasources returned will be in the same order the functions were registered.
   100  func environmentDataSources(env Environ) ([]simplestreams.DataSource, error) {
   101  	datasourceFuncsMu.RLock()
   102  	defer datasourceFuncsMu.RUnlock()
   103  	var datasources []simplestreams.DataSource
   104  	for _, f := range datasourceFuncs {
   105  		logger.Debugf("trying datasource %q", f.id)
   106  		datasource, err := f.f(env)
   107  		if err != nil {
   108  			if errors.IsNotSupported(err) {
   109  				continue
   110  			}
   111  			return nil, err
   112  		}
   113  		datasources = append(datasources, datasource)
   114  	}
   115  	return datasources, nil
   116  }