github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/providers/common/hub_client.go (about) 1 package common 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8 "os" 9 10 "github.com/djannot/aws-sdk-go/aws" 11 "github.com/djannot/aws-sdk-go/aws/session" 12 "github.com/djannot/aws-sdk-go/service/s3" 13 "github.com/emc-advanced-dev/pkg/errors" 14 "github.com/layer-x/layerx-commons/lxhttpclient" 15 "github.com/sirupsen/logrus" 16 "github.com/solo-io/unik/pkg/config" 17 "github.com/solo-io/unik/pkg/types" 18 ) 19 20 const ( 21 unik_hub_region = "us-east-1" 22 unik_hub_bucket = "unik-hub" 23 unik_image_info = "Unik-Image-Info" 24 ) 25 26 func PullImage(config config.HubConfig, imageName string, writer io.Writer) (*types.Image, error) { 27 //to trigger modified djannot/aws-sdk 28 os.Setenv("S3_AUTH_PROXY_URL", config.URL) 29 30 //search available images, get user for image name 31 resp, body, err := lxhttpclient.Get(config.URL, "/images", nil) 32 if err != nil { 33 return nil, errors.New("performing GET request", err) 34 } 35 if resp.StatusCode != http.StatusOK { 36 return nil, errors.New(fmt.Sprintf("failed GETting image list status %v: %s", resp.StatusCode, string(body)), nil) 37 } 38 var images []*types.UserImage 39 if err := json.Unmarshal(body, &images); err != nil { 40 logrus.Fatal(err) 41 } 42 var user string 43 for _, image := range images { 44 if image.Name == imageName { 45 user = image.Owner 46 break 47 } 48 } 49 if user == "" { 50 return nil, errors.New("could not find image "+imageName, nil) 51 } 52 53 metadata, err := s3Download(imageKey(user, imageName), config.Password, writer) 54 if err != nil { 55 return nil, errors.New("downloading image", err) 56 } 57 var image types.Image 58 if err := json.Unmarshal([]byte(metadata), &image); err != nil { 59 return nil, errors.New("unmarshalling metadata for image", err) 60 } 61 logrus.Infof("downloaded image %v", image) 62 return &image, nil 63 } 64 65 func PushImage(config config.HubConfig, image *types.Image, imagePath string) error { 66 //to trigger modified djannot/aws-sdk 67 os.Setenv("S3_AUTH_PROXY_URL", config.URL) 68 metadata, err := json.Marshal(image) 69 if err != nil { 70 return errors.New("converting image metadata to json", err) 71 } 72 //upload image 73 reader, err := os.Open(imagePath) 74 if err != nil { 75 return errors.New("opening file", err) 76 } 77 defer reader.Close() 78 fileInfo, err := reader.Stat() 79 if err != nil { 80 return errors.New("getting file info", err) 81 } 82 if err := s3Upload(config, imageKey(config.Username, image.Name), string(metadata), reader, fileInfo.Size()); err != nil { 83 return errors.New("uploading image file", err) 84 } 85 logrus.Infof("Image %v pushed to %s", image, config.URL) 86 return nil 87 } 88 89 func RemoteDeleteImage(config config.HubConfig, imageName string) error { 90 //to trigger modified djannot/aws-sdk 91 os.Setenv("S3_AUTH_PROXY_URL", config.URL) 92 if err := s3Delete(config, imageKey(config.Username, imageName)); err != nil { 93 return errors.New("deleting image file", err) 94 } 95 logrus.Infof("Image %v deleted from %s", imageName, config.URL) 96 return nil 97 } 98 99 func s3Download(key, password string, writer io.Writer) (string, error) { 100 params := &s3.GetObjectInput{ 101 Bucket: aws.String(unik_hub_bucket), 102 Key: aws.String(key), 103 Password: aws.String(password), 104 } 105 result, err := s3.New(session.New(&aws.Config{Region: aws.String(unik_hub_region)})).GetObject(params) 106 if err != nil { 107 return "", errors.New("failed to download from s3", err) 108 } 109 n, err := io.Copy(writer, result.Body) 110 if err != nil { 111 return "", errors.New("copying image bytes", err) 112 } 113 logrus.Infof("downloaded %v bytes", n) 114 if result.Metadata[unik_image_info] == nil { 115 return "", errors.New(fmt.Sprintf(unik_image_info+" was empty. full metadata: %+v", result.Metadata), nil) 116 } 117 return *result.Metadata[unik_image_info], nil 118 } 119 120 func s3Upload(config config.HubConfig, key, metadata string, body io.ReadSeeker, length int64) error { 121 params := &s3.PutObjectInput{ 122 Body: body, 123 Bucket: aws.String(unik_hub_bucket), 124 Key: aws.String(key), 125 Metadata: map[string]*string{ 126 "unik-password": aws.String(config.Password), 127 "unik-email": aws.String(config.Username), 128 "unik-access": aws.String("public"), 129 unik_image_info: aws.String(metadata), 130 }, 131 } 132 result, err := s3.New(session.New(&aws.Config{Region: aws.String(unik_hub_region)})).PutObject(params) 133 if err != nil { 134 return errors.New("uploading image to s3 backend", err) 135 } 136 logrus.Infof("uploaded %v bytes: %v", length, result) 137 return nil 138 } 139 140 // unik hub has to do it itself to validate user 141 func s3Delete(config config.HubConfig, key string) error { 142 deleteMessage := struct { 143 Username string `json:"user"` 144 Password string `json:"pass"` 145 Key string `json:"key"` 146 }{ 147 Username: config.Username, 148 Password: config.Password, 149 Key: key, 150 } 151 resp, body, err := lxhttpclient.Post(config.URL, "/delete_image", nil, deleteMessage) 152 if err != nil { 153 return errors.New("failed to perform delete request", err) 154 } 155 if resp.StatusCode != 204 { 156 return errors.New(fmt.Sprintf("expected status code 204, got %v: %s", resp.StatusCode, string(body)), nil) 157 } 158 return nil 159 } 160 161 func imageKey(username, imageName string) string { 162 return "/" + username + "/" + imageName + "/latest" //TODO: support image versioning 163 }