1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
// Copyright (c) 2020, Control Command Inc. All rights reserved.
// Copyright (c) 2019-2022, Sylabs Inc. All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE.md file distributed with the sources of this project regarding your
// rights to use or distribute this software.
package endpoint
import (
"errors"
"io"
"net/url"
"os"
"path/filepath"
"time"
"github.com/gosimple/slug"
"github.com/sylabs/singularity/v4/internal/pkg/remote/credential"
"github.com/sylabs/singularity/v4/pkg/syfs"
)
var cacheDuration = 720 * time.Hour
// DefaultEndpointConfig is the default remote configuration.
var DefaultEndpointConfig = &Config{
URI: SCSDefaultCloudURI,
System: true,
}
var ErrNoURI = errors.New("no URI set for endpoint")
// Config describes a single remote endpoint.
type Config struct {
URI string `yaml:"URI,omitempty"` // hostname/path - no protocol expected
Token string `yaml:"Token,omitempty"`
System bool `yaml:"System"` // Was this EndPoint set from system config file
Exclusive bool `yaml:"Exclusive"` // true if the endpoint must be used exclusively
Insecure bool `yaml:"Insecure,omitempty"` // Allow use of http for service discovery
Keyservers []*ServiceConfig `yaml:"Keyservers,omitempty"`
// for internal purpose
credentials []*credential.Config
services map[string][]Service
}
func (e *Config) SetCredentials(creds []*credential.Config) {
e.credentials = creds
}
// GetUrl returns a URL with the correct https or http protocol for the endpoint.
// The protocol depends on whether the endpoint is set 'Insecure'.
func (e *Config) GetURL() (string, error) {
if e.URI == "" {
return "", ErrNoURI
}
u, err := url.Parse(e.URI)
if err != nil {
return "", err
}
if e.Insecure {
u.Scheme = "http"
} else {
u.Scheme = "https"
}
return u.String(), nil
}
type ServiceConfig struct {
// for internal purpose
credential *credential.Config
URI string `yaml:"URI"`
Skip bool `yaml:"Skip"`
External bool `yaml:"External"`
Insecure bool `yaml:"Insecure"`
}
func cacheDir() string {
cacheDir := syfs.RemoteCacheDir()
if _, err := os.Stat(cacheDir); os.IsNotExist(err) {
if err := os.Mkdir(cacheDir, 0o700); err != nil {
return ""
}
}
return cacheDir
}
func getCachedConfig(uri string) io.ReadCloser {
dir := cacheDir()
if dir == "" {
return nil
}
uriSlug := slug.Make(uri)
config := filepath.Join(dir, uriSlug+".json")
fi, err := os.Stat(config)
if err != nil {
return nil
} else if fi.ModTime().Add(cacheDuration).Before(time.Now()) {
return nil
}
rc, err := os.Open(config)
if err != nil {
return nil
}
return rc
}
func updateCachedConfig(uri string, data []byte) {
dir := cacheDir()
if dir == "" {
return
}
config := filepath.Join(dir, uri+".json")
os.WriteFile(config, data, 0o600)
}
|