working commit
This commit is contained in:
@@ -15,20 +15,18 @@ import (
|
|||||||
"mstore/app/router"
|
"mstore/app/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
type xxxResponse struct {
|
type Response[T any] struct {
|
||||||
Error bool `json:"error" yaml:"error"`
|
|
||||||
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
|
||||||
Result any `json:"result,omitempty" yaml:"result,result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GenericResponse[T any] struct {
|
|
||||||
Error bool `json:"error" yaml:"error"`
|
Error bool `json:"error" yaml:"error"`
|
||||||
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||||
Result T `json:"result,omitempty" yaml:"result,result"`
|
Result T `json:"result,omitempty" yaml:"result,result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewResponse[T any]() *Response[T] {
|
||||||
|
return &Response[T]{}
|
||||||
|
}
|
||||||
|
|
||||||
func (hand *Handler) SendResult(rctx *router.Context, result any) {
|
func (hand *Handler) SendResult(rctx *router.Context, result any) {
|
||||||
response := &GenericResponse[any]{
|
response := &Response[any]{
|
||||||
Error: false,
|
Error: false,
|
||||||
Result: result,
|
Result: result,
|
||||||
}
|
}
|
||||||
@@ -36,7 +34,7 @@ func (hand *Handler) SendResult(rctx *router.Context, result any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (hand *Handler) SendError(rctx *router.Context, err error) {
|
func (hand *Handler) SendError(rctx *router.Context, err error) {
|
||||||
response := &GenericResponse[any]{
|
response := &Response[any]{
|
||||||
Error: true,
|
Error: true,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"mstore/pkg/client"
|
"mstore/pkg/client"
|
||||||
@@ -18,6 +21,24 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func packUserinfo(resurseuri, username, password string) (string, error) {
|
||||||
|
var err error
|
||||||
|
var res string
|
||||||
|
if !strings.Contains(resurseuri, "://") {
|
||||||
|
resurseuri = "https://" + resurseuri
|
||||||
|
}
|
||||||
|
uri, err := url.Parse(resurseuri)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
uri.Path = path.Clean(uri.Path)
|
||||||
|
if username != "" && password != "" {
|
||||||
|
uri.User = url.UserPassword(username, password)
|
||||||
|
}
|
||||||
|
res = uri.String()
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
func (util *ImageUtil) CreateImageCmds() *cobra.Command {
|
func (util *ImageUtil) CreateImageCmds() *cobra.Command {
|
||||||
const defaultTimeout uint64 = 30 // Second
|
const defaultTimeout uint64 = 30 // Second
|
||||||
|
|
||||||
@@ -101,10 +122,17 @@ func (util *ImageUtil) imageInfo(params *ImageInfoParams) (*ImageInfoResult, err
|
|||||||
res := &ImageInfoResult{}
|
res := &ImageInfoResult{}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
cli := client.NewClientWithAuth(params.Username, params.Password)
|
cli := client.NewClient()
|
||||||
timeout := time.Duration(params.Timeout) * time.Second
|
timeout := time.Duration(params.Timeout) * time.Second
|
||||||
opres, err := cli.ImageInfo(ctx, params.Imagepath, timeout)
|
|
||||||
|
|
||||||
|
params.Imagepath, err = packUserinfo(params.Imagepath, params.Username, params.Password)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
opres, err := cli.ImageInfo(ctx, params.Imagepath, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
res.ImageInfo = opres
|
res.ImageInfo = opres
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@@ -131,10 +159,16 @@ func (util *ImageUtil) pullImage(params *PullImageParams) (*PullImageResult, err
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
res := &PullImageResult{}
|
res := &PullImageResult{}
|
||||||
|
|
||||||
cli := client.NewClientWithAuth(params.Username, params.Password)
|
cli := client.NewClient()
|
||||||
timeout := time.Duration(params.Timeout) * time.Second
|
timeout := time.Duration(params.Timeout) * time.Second
|
||||||
|
params.Imagepath, err = packUserinfo(params.Imagepath, params.Username, params.Password)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
err = cli.PullImage(ctx, params.Imagepath, params.Filepath, timeout)
|
err = cli.PullImage(ctx, params.Imagepath, params.Filepath, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +193,15 @@ func (util *ImageUtil) pushImage(params *PushImageParams) (*PushImageResult, err
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
res := &PushImageResult{}
|
res := &PushImageResult{}
|
||||||
|
|
||||||
cli := client.NewClientWithAuth(params.Username, params.Password)
|
cli := client.NewClient()
|
||||||
timeout := time.Duration(params.Timeout) * time.Second
|
timeout := time.Duration(params.Timeout) * time.Second
|
||||||
err = cli.PushImage(ctx, params.Filepath, params.Imagepath, timeout)
|
params.Imagepath, err = packUserinfo(params.Imagepath, params.Username, params.Password)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
err = cli.PushImage(ctx, params.Filepath, params.Imagepath, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func EncodeBasicAuth(username, password string) string {
|
||||||
|
auth := username + ":" + password
|
||||||
|
return "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
|
||||||
|
}
|
||||||
|
|
||||||
func ParseBasicAuth(basicFields string) (string, string, error) {
|
func ParseBasicAuth(basicFields string) (string, string, error) {
|
||||||
var err error
|
var err error
|
||||||
var username string
|
var username string
|
||||||
|
|||||||
@@ -7,15 +7,20 @@
|
|||||||
* Distribution of this work is permitted, but commercial use and
|
* Distribution of this work is permitted, but commercial use and
|
||||||
* modifications are strictly prohibited.
|
* modifications are strictly prohibited.
|
||||||
*/
|
*/
|
||||||
package client
|
package auxtool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeTmpFileName(prefix string) string {
|
func init() {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeTmpFilename(prefix string) string {
|
||||||
randBytes := make([]byte, 6)
|
randBytes := make([]byte, 6)
|
||||||
rand.Read(randBytes)
|
rand.Read(randBytes)
|
||||||
suffix := hex.EncodeToString(randBytes)
|
suffix := hex.EncodeToString(randBytes)
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is published and licensed under a Creative Commons
|
||||||
|
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||||
|
*
|
||||||
|
* Distribution of this work is permitted, but commercial use and
|
||||||
|
* modifications are strictly prohibited.
|
||||||
|
*/
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"mstore/app/handler"
|
||||||
|
"mstore/app/operator"
|
||||||
|
"mstore/pkg/auxhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (cli *Client) CreateAccount(ctx context.Context, hosturi, username, password string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
apiuri, err := url.JoinPath(hosturi, "/v3/api/account/get")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
operParams := operator.CreateAccountParams{
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
paramsJson, err := json.Marshal(operParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
respBytes, err := doHTTPCall(ctx, apiuri, paramsJson)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
operRes := handler.NewResponse[operator.CreateAccountResult]()
|
||||||
|
err = json.Unmarshal(respBytes, operRes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !operRes.Error {
|
||||||
|
err = fmt.Errorf("%s", operRes.Message)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *Client) GetAccount(ctx context.Context, hosturi, id, username string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
apipath, err := url.JoinPath(hosturi, "/v3/api/account/get")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
operParams := operator.GetAccountParams{
|
||||||
|
Username: username,
|
||||||
|
AccountID: id,
|
||||||
|
}
|
||||||
|
paramsJson, err := json.Marshal(operParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
respBytes, err := doHTTPCall(ctx, apipath, paramsJson)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
operRes := handler.NewResponse[operator.CreateAccountResult]()
|
||||||
|
err = json.Unmarshal(respBytes, operRes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !operRes.Error {
|
||||||
|
err = fmt.Errorf("%s", operRes.Message)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func doHTTPCall(ctx context.Context, apiuri string, reqBytes []byte) ([]byte, error) {
|
||||||
|
var err error
|
||||||
|
respBytes := make([]byte, 0)
|
||||||
|
|
||||||
|
apiuri, username, password, err := repackServiceURI(apiuri)
|
||||||
|
if err != nil {
|
||||||
|
return respBytes, err
|
||||||
|
}
|
||||||
|
reqBuffer := bytes.NewBuffer(reqBytes)
|
||||||
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiuri, reqBuffer)
|
||||||
|
if err != nil {
|
||||||
|
return respBytes, err
|
||||||
|
}
|
||||||
|
httpReq.Header.Set("Content-Type", "application/json")
|
||||||
|
if username != "" && password != "" {
|
||||||
|
basicHeader := auxhttp.EncodeBasicAuth(username, password)
|
||||||
|
httpReq.Header.Add("Authorization", basicHeader)
|
||||||
|
}
|
||||||
|
transport := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
}
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Transport: transport,
|
||||||
|
}
|
||||||
|
httpResp, err := httpClient.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return respBytes, err
|
||||||
|
}
|
||||||
|
defer httpResp.Body.Close()
|
||||||
|
if httpResp.StatusCode != http.StatusOK {
|
||||||
|
err := fmt.Errorf("Wrong StatusCode header: %s", httpResp.Status)
|
||||||
|
return respBytes, err
|
||||||
|
}
|
||||||
|
respBuffer := bytes.NewBuffer(nil)
|
||||||
|
_, err = io.Copy(respBuffer, httpResp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return respBytes, err
|
||||||
|
}
|
||||||
|
respBytes = respBuffer.Bytes()
|
||||||
|
return respBytes, err
|
||||||
|
}
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
|
||||||
*
|
|
||||||
* This work is published and licensed under a Creative Commons
|
|
||||||
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
|
||||||
*
|
|
||||||
* Distribution of this work is permitted, but commercial use and
|
|
||||||
* modifications are strictly prohibited.
|
|
||||||
*/
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"net/url"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
serviceAPI = "/v3/api/service/"
|
|
||||||
fileAPI = "/v3/api/file/"
|
|
||||||
filesAPI = "/v3/api/files/"
|
|
||||||
)
|
|
||||||
|
|
||||||
func encodeBasicAuth(username, password string) string {
|
|
||||||
auth := username + ":" + password
|
|
||||||
return "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertServiceRefer(ref string) (string, error) {
|
|
||||||
var err error
|
|
||||||
var res string
|
|
||||||
if !strings.Contains(ref, "://") {
|
|
||||||
ref = "https://" + ref
|
|
||||||
}
|
|
||||||
url, err := url.Parse(ref)
|
|
||||||
if err != nil {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
url.Path = path.Clean(url.Path)
|
|
||||||
url.Path = path.Join(serviceAPI, url.Path)
|
|
||||||
url.User = nil
|
|
||||||
res = url.String()
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertFileRefer(ref string) (string, error) {
|
|
||||||
var err error
|
|
||||||
var res string
|
|
||||||
if !strings.Contains(ref, "://") {
|
|
||||||
ref = "https://" + ref
|
|
||||||
}
|
|
||||||
url, err := url.Parse(ref)
|
|
||||||
if err != nil {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
url.Path = path.Clean(url.Path)
|
|
||||||
url.Path = path.Join(fileAPI, url.Path)
|
|
||||||
url.User = nil
|
|
||||||
res = url.String()
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertFilesRefer(ref string) (string, error) {
|
|
||||||
var err error
|
|
||||||
var res string
|
|
||||||
if !strings.Contains(ref, "://") {
|
|
||||||
ref = "https://" + ref
|
|
||||||
}
|
|
||||||
url, err := url.Parse(ref)
|
|
||||||
if err != nil {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
url.Path = path.Clean(url.Path)
|
|
||||||
url.Path = path.Join(filesAPI, url.Path)
|
|
||||||
url.User = nil
|
|
||||||
res = url.String()
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
+21
-14
@@ -13,40 +13,47 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct{}
|
||||||
username string
|
|
||||||
password string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewClient() *Client {
|
func NewClient() *Client {
|
||||||
return &Client{}
|
return &Client{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientWithAuth(username, password string) *Client {
|
func convertServiceURI(ref string) (string, error) {
|
||||||
return &Client{
|
var err error
|
||||||
username: username,
|
var res string
|
||||||
password: password,
|
const serviceAPI = "/v3/api/service/"
|
||||||
|
const serviceScheme = "https"
|
||||||
|
uri, err := url.Parse(ref)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
}
|
}
|
||||||
|
uri.Path = serviceAPI
|
||||||
|
uri.Scheme = serviceScheme
|
||||||
|
res = uri.String()
|
||||||
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) ServiceHello(ctx context.Context, ref string, timeout time.Duration) (bool, error) {
|
func (cli *Client) ServiceHello(ctx context.Context, serviceuri string, timeout time.Duration) (bool, error) {
|
||||||
var res bool
|
var res bool
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
ctx, _ = context.WithTimeout(ctx, timeout)
|
||||||
|
serviceuri, _, _, err = repackServiceURI(serviceuri)
|
||||||
ref, err = convertServiceRefer(ref)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ref, nil)
|
serviceuri, err = convertServiceURI(serviceuri)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, serviceuri, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
transport := &http.Transport{
|
transport := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
|
|||||||
+120
-61
@@ -15,28 +15,17 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"mstore/pkg/auxhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cli *Client) FileExists(ctx context.Context, ref string) (bool, error) {
|
func makeHTTPClient() *http.Client {
|
||||||
var res bool
|
|
||||||
var err error
|
|
||||||
|
|
||||||
ref, err = convertFileRefer(ref)
|
|
||||||
if err != nil {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodHead, ref, nil)
|
|
||||||
if err != nil {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if cli.username != "" && cli.password != "" {
|
|
||||||
req.Header.Add("Authorization", encodeBasicAuth(cli.username, cli.password))
|
|
||||||
}
|
|
||||||
|
|
||||||
transport := &http.Transport{
|
transport := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
@@ -45,6 +34,80 @@ func (cli *Client) FileExists(ctx context.Context, ref string) (bool, error) {
|
|||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertFileURI(fileuri string) (string, error) {
|
||||||
|
var err error
|
||||||
|
var res string
|
||||||
|
uri, err := url.Parse(fileuri)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
const fileAPI = "/v3/api/file/"
|
||||||
|
uri.Path, err = url.JoinPath(fileAPI, uri.Path)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res = uri.String()
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertFilesURI(fileuri string) (string, error) {
|
||||||
|
var err error
|
||||||
|
var res string
|
||||||
|
uri, err := url.Parse(fileuri)
|
||||||
|
const filesAPI = "/v3/api/files/"
|
||||||
|
uri.Path, err = url.JoinPath(filesAPI, uri.Path)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res = uri.String()
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func repackServiceURI(fileuri string) (string, string, string, error) {
|
||||||
|
var err error
|
||||||
|
var res, username, password string
|
||||||
|
if !strings.Contains(fileuri, "://") {
|
||||||
|
fileuri = "https://" + fileuri
|
||||||
|
}
|
||||||
|
uri, err := url.Parse(fileuri)
|
||||||
|
if err != nil {
|
||||||
|
return res, username, password, err
|
||||||
|
}
|
||||||
|
uri.Path = path.Clean(uri.Path)
|
||||||
|
if uri.User != nil {
|
||||||
|
username = uri.User.Username()
|
||||||
|
password, _ = uri.User.Password()
|
||||||
|
}
|
||||||
|
uri.User = nil
|
||||||
|
uri.Scheme = "https"
|
||||||
|
res = uri.String()
|
||||||
|
return res, username, password, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *Client) FileExists(ctx context.Context, fileuri string) (bool, error) {
|
||||||
|
var res bool
|
||||||
|
var err error
|
||||||
|
fileuri, username, password, err := repackServiceURI(fileuri)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
fileuri, err = convertFileURI(fileuri)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodHead, fileuri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if username != "" && password != "" {
|
||||||
|
basic := auxhttp.EncodeBasicAuth(username, password)
|
||||||
|
req.Header.Add("Authorization", basic)
|
||||||
|
}
|
||||||
|
client := makeHTTPClient()
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
@@ -56,9 +119,14 @@ func (cli *Client) FileExists(ctx context.Context, ref string) (bool, error) {
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) PutFile(ctx context.Context, filename, ref string) error {
|
func (cli *Client) PutFile(ctx context.Context, filename, fileuri string) error {
|
||||||
var err error
|
var err error
|
||||||
ref, err = convertFileRefer(ref)
|
fileuri, username, password, err := repackServiceURI(fileuri)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileuri, err = convertFileURI(fileuri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -68,23 +136,10 @@ func (cli *Client) PutFile(ctx context.Context, filename, ref string) error {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPut, ref, file)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPut, fileuri, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.username != "" && cli.password != "" {
|
|
||||||
req.Header.Add("Authorization", encodeBasicAuth(cli.username, cli.password))
|
|
||||||
}
|
|
||||||
|
|
||||||
transport := &http.Transport{
|
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: transport,
|
|
||||||
}
|
|
||||||
fileinfo, err := os.Stat(filename)
|
fileinfo, err := os.Stat(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -93,6 +148,11 @@ func (cli *Client) PutFile(ctx context.Context, filename, ref string) error {
|
|||||||
|
|
||||||
req.ContentLength = filesize
|
req.ContentLength = filesize
|
||||||
req.Header.Set("Content-Type", "application/octet-stream")
|
req.Header.Set("Content-Type", "application/octet-stream")
|
||||||
|
if username != "" && password != "" {
|
||||||
|
basic := auxhttp.EncodeBasicAuth(username, password)
|
||||||
|
req.Header.Add("Authorization", basic)
|
||||||
|
}
|
||||||
|
client := makeHTTPClient()
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -107,31 +167,31 @@ func (cli *Client) PutFile(ctx context.Context, filename, ref string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) GetFile(ctx context.Context, ref, filename string) (int64, error) {
|
func (cli *Client) GetFile(ctx context.Context, fileuri, filename string) (int64, error) {
|
||||||
var err error
|
var err error
|
||||||
var size int64
|
var size int64
|
||||||
ref, err = convertFileRefer(ref)
|
|
||||||
|
fileuri, username, password, err := repackServiceURI(fileuri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return size, err
|
return size, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ref, nil)
|
fileuri, err = convertFileURI(fileuri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return size, err
|
return size, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.username != "" && cli.password != "" {
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fileuri, nil)
|
||||||
req.Header.Add("Authorization", encodeBasicAuth(cli.username, cli.password))
|
if err != nil {
|
||||||
|
return size, err
|
||||||
}
|
}
|
||||||
|
|
||||||
transport := &http.Transport{
|
if username != "" && password != "" {
|
||||||
TLSClientConfig: &tls.Config{
|
basic := auxhttp.EncodeBasicAuth(username, password)
|
||||||
InsecureSkipVerify: true,
|
req.Header.Add("Authorization", basic)
|
||||||
},
|
|
||||||
}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: transport,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client := makeHTTPClient()
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return size, err
|
return size, err
|
||||||
@@ -172,29 +232,28 @@ func (cli *Client) GetFile(ctx context.Context, ref, filename string) (int64, er
|
|||||||
return size, err
|
return size, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) DeleteFile(ctx context.Context, ref, filename string) error {
|
func (cli *Client) DeleteFile(ctx context.Context, fileuri, filename string) error {
|
||||||
var err error
|
var err error
|
||||||
ref, err = convertFileRefer(ref)
|
|
||||||
if err != nil {
|
fileuri, username, password, err := repackServiceURI(fileuri)
|
||||||
return err
|
|
||||||
}
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, ref, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.username != "" && cli.password != "" {
|
fileuri, err = convertFileURI(fileuri)
|
||||||
req.Header.Add("Authorization", encodeBasicAuth(cli.username, cli.password))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, fileuri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if username != "" && password != "" {
|
||||||
|
basic := auxhttp.EncodeBasicAuth(username, password)
|
||||||
|
req.Header.Add("Authorization", basic)
|
||||||
}
|
}
|
||||||
|
|
||||||
transport := &http.Transport{
|
client := makeHTTPClient()
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: transport,
|
|
||||||
}
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ package client
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type roundTripper struct{}
|
type roundTripper struct{}
|
||||||
@@ -25,3 +27,26 @@ func (t *roundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
return httpTransport.RoundTrip(r)
|
return httpTransport.RoundTrip(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func repackReference(ref string) (string, string, string, error) {
|
||||||
|
var err error
|
||||||
|
var username string
|
||||||
|
var password string
|
||||||
|
if !strings.Contains(ref, `://`) {
|
||||||
|
ref = "https://" + ref
|
||||||
|
}
|
||||||
|
uri, err := url.Parse(ref)
|
||||||
|
if err != nil {
|
||||||
|
return ref, username, password, err
|
||||||
|
}
|
||||||
|
username = uri.User.Username()
|
||||||
|
password, _ = uri.User.Password()
|
||||||
|
uri.User = nil
|
||||||
|
|
||||||
|
uri.Path, _ = url.JoinPath("/", uri.Path)
|
||||||
|
if err != nil {
|
||||||
|
return ref, username, password, err
|
||||||
|
}
|
||||||
|
ref = uri.Host + uri.Path
|
||||||
|
return ref, username, password, err
|
||||||
|
}
|
||||||
|
|||||||
+10
-7
@@ -31,8 +31,11 @@ func (cli *Client) ImageInfo(ctx context.Context, imagepath string, timeout time
|
|||||||
var err error
|
var err error
|
||||||
res := &ImageDescr{}
|
res := &ImageDescr{}
|
||||||
|
|
||||||
|
imagepath, username, password, err := repackReference(imagepath)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
ctx, _ = context.WithTimeout(ctx, timeout)
|
||||||
|
|
||||||
options := make([]crane.Option, 0)
|
options := make([]crane.Option, 0)
|
||||||
options = append(options, crane.WithContext(ctx))
|
options = append(options, crane.WithContext(ctx))
|
||||||
|
|
||||||
@@ -45,7 +48,7 @@ func (cli *Client) ImageInfo(ctx context.Context, imagepath string, timeout time
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.username != "" && cli.password != "" {
|
if username != "" && password != "" {
|
||||||
defaultTransport := &roundTripper{}
|
defaultTransport := &roundTripper{}
|
||||||
scopes := []string{repo.Scope(transport.PullScope)}
|
scopes := []string{repo.Scope(transport.PullScope)}
|
||||||
|
|
||||||
@@ -55,8 +58,8 @@ func (cli *Client) ImageInfo(ctx context.Context, imagepath string, timeout time
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
basicAuth := &authn.Basic{
|
basicAuth := &authn.Basic{
|
||||||
Username: cli.username,
|
Username: username,
|
||||||
Password: cli.password,
|
Password: password,
|
||||||
}
|
}
|
||||||
authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes)
|
authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -90,7 +93,7 @@ func (cli *Client) ImageInfo(ctx context.Context, imagepath string, timeout time
|
|||||||
remoteOptions := make([]remote.Option, 0)
|
remoteOptions := make([]remote.Option, 0)
|
||||||
remoteOptions = append(remoteOptions, remote.WithContext(ctx))
|
remoteOptions = append(remoteOptions, remote.WithContext(ctx))
|
||||||
|
|
||||||
if cli.username != "" && cli.password != "" {
|
if username != "" && password != "" {
|
||||||
defaultTransport := &roundTripper{}
|
defaultTransport := &roundTripper{}
|
||||||
scopes := []string{repo.Scope(transport.PullScope)}
|
scopes := []string{repo.Scope(transport.PullScope)}
|
||||||
|
|
||||||
@@ -100,8 +103,8 @@ func (cli *Client) ImageInfo(ctx context.Context, imagepath string, timeout time
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
basicAuth := &authn.Basic{
|
basicAuth := &authn.Basic{
|
||||||
Username: cli.username,
|
Username: username,
|
||||||
Password: cli.password,
|
Password: password,
|
||||||
}
|
}
|
||||||
authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes)
|
authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+10
-4
@@ -14,6 +14,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"mstore/pkg/auxtool"
|
||||||
"mstore/pkg/auxutar"
|
"mstore/pkg/auxutar"
|
||||||
|
|
||||||
"github.com/google/go-containerregistry/pkg/authn"
|
"github.com/google/go-containerregistry/pkg/authn"
|
||||||
@@ -26,10 +27,15 @@ func (cli *Client) PullImage(ctx context.Context, filepath, imagepath string, ti
|
|||||||
var err error
|
var err error
|
||||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
ctx, _ = context.WithTimeout(ctx, timeout)
|
||||||
|
|
||||||
|
imagepath, username, password, err := repackReference(imagepath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
options := make([]crane.Option, 0)
|
options := make([]crane.Option, 0)
|
||||||
options = append(options, crane.WithContext(ctx))
|
options = append(options, crane.WithContext(ctx))
|
||||||
|
|
||||||
if cli.username != "" && cli.password != "" {
|
if username != "" && password != "" {
|
||||||
ref, err := name.ParseReference(imagepath)
|
ref, err := name.ParseReference(imagepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -48,8 +54,8 @@ func (cli *Client) PullImage(ctx context.Context, filepath, imagepath string, ti
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
basicAuth := &authn.Basic{
|
basicAuth := &authn.Basic{
|
||||||
Username: cli.username,
|
Username: username,
|
||||||
Password: cli.password,
|
Password: password,
|
||||||
}
|
}
|
||||||
authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes)
|
authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -65,7 +71,7 @@ func (cli *Client) PullImage(ctx context.Context, filepath, imagepath string, ti
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dstdir := makeTmpFileName(filepath)
|
dstdir := auxtool.MakeTmpFilename(filepath)
|
||||||
err = os.MkdirAll(dstdir, 0750)
|
err = os.MkdirAll(dstdir, 0750)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+10
-4
@@ -15,6 +15,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"mstore/pkg/auxtool"
|
||||||
"mstore/pkg/auxutar"
|
"mstore/pkg/auxutar"
|
||||||
|
|
||||||
"github.com/google/go-containerregistry/pkg/authn"
|
"github.com/google/go-containerregistry/pkg/authn"
|
||||||
@@ -29,9 +30,14 @@ func (cli *Client) PushImage(ctx context.Context, filepath, imagepath string, ti
|
|||||||
var err error
|
var err error
|
||||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
ctx, _ = context.WithTimeout(ctx, timeout)
|
||||||
|
|
||||||
|
imagepath, username, password, err := repackReference(imagepath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
options := make([]crane.Option, 0)
|
options := make([]crane.Option, 0)
|
||||||
options = append(options, crane.WithContext(ctx))
|
options = append(options, crane.WithContext(ctx))
|
||||||
if cli.username != "" && cli.password != "" {
|
if username != "" && password != "" {
|
||||||
ref, err := name.ParseReference(imagepath)
|
ref, err := name.ParseReference(imagepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -53,8 +59,8 @@ func (cli *Client) PushImage(ctx context.Context, filepath, imagepath string, ti
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
basicAuth := &authn.Basic{
|
basicAuth := &authn.Basic{
|
||||||
Username: cli.username,
|
Username: username,
|
||||||
Password: cli.password,
|
Password: password,
|
||||||
}
|
}
|
||||||
|
|
||||||
authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes)
|
authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes)
|
||||||
@@ -67,7 +73,7 @@ func (cli *Client) PushImage(ctx context.Context, filepath, imagepath string, ti
|
|||||||
options = append(options, crane.WithTransport(defaultTransport))
|
options = append(options, crane.WithTransport(defaultTransport))
|
||||||
}
|
}
|
||||||
|
|
||||||
dstdir := makeTmpFileName(filepath)
|
dstdir := auxtool.MakeTmpFilename(filepath)
|
||||||
err = auxutar.Unarchive(filepath, dstdir)
|
err = auxutar.Unarchive(filepath, dstdir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(dstdir)
|
os.RemoveAll(dstdir)
|
||||||
|
|||||||
Reference in New Issue
Block a user