working commit

This commit is contained in:
2026-02-18 23:22:46 +02:00
parent e1ca9b1b4c
commit 4a43a22c19
12 changed files with 500 additions and 92 deletions
+62
View File
@@ -198,3 +198,65 @@ func (hand *Handler) ListFiles(rctx *router.Context) {
}
rctx.SendJSON(code, res.Files)
}
func (hand *Handler) ListCollections(rctx *router.Context) {
cpath, _ := rctx.GetSubpath("path")
if cpath == "" {
cpath = "/"
}
params := &operator.ListCollectionsParams{
Path: cpath,
}
// Rigth checking
operatorID, _ := rctx.GetString(userTag)
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, descr.RightReadFiles, "")
if err != nil {
rctx.SetStatus(http.StatusInternalServerError)
return
}
if !opEnable {
rctx.SetStatus(http.StatusMethodNotAllowed)
return
}
// Execution of the operation
ctx := rctx.GetContext()
code, res, err := hand.oper.ListCollections(ctx, operatorID, params)
if err != nil {
hand.logg.Errorf("ListCollections error: %v", err)
rctx.SetStatus(code)
return
}
rctx.SendJSON(code, res.Collections)
}
func (hand *Handler) DeleteCollection(rctx *router.Context) {
cpath, _ := rctx.GetSubpath("path")
if cpath == "" {
cpath = "/"
}
params := &operator.DeleteColletionParams{
Path: cpath,
}
// Rigth checking
operatorID, _ := rctx.GetString(userTag)
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, descr.RightReadFiles, "")
if err != nil {
rctx.SetStatus(http.StatusInternalServerError)
return
}
if !opEnable {
rctx.SetStatus(http.StatusMethodNotAllowed)
return
}
// Execution of the operation
ctx := rctx.GetContext()
code, res, err := hand.oper.DeleteColletion(ctx, operatorID, params)
if err != nil {
hand.logg.Errorf("DeleteColletion error: %v", err)
rctx.SetStatus(code)
return
}
rctx.SendJSON(code, res.Files)
}
+90 -7
View File
@@ -16,6 +16,7 @@ import (
"net/http"
"path"
"path/filepath"
"slices"
"strconv"
"strings"
@@ -282,18 +283,16 @@ type ListFilesParams struct {
Filepath string
}
type ListFilesResult struct {
Files []descr.File `json:"files,omitempty"`
Collections []string `json:"collection,omitempty"`
Files []descr.File `json:"files,omitempty"`
}
func (oper *Operator) ListFiles(ctx context.Context, operID string, param *ListFilesParams) (int, *ListFilesResult, error) {
var err error
res := &ListFilesResult{
Files: make([]descr.File, 0),
Collections: make([]string, 0),
Files: make([]descr.File, 0),
}
_, err = cleanFilepath(param.Filepath)
param.Filepath, err = cleanFilepath(param.Filepath)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
@@ -307,12 +306,96 @@ func (oper *Operator) ListFiles(ctx context.Context, operID string, param *ListF
rFilepath := filepath.Join("/", param.Filepath)
for _, item := range fileDescrs {
cFilepath := filepath.Join("/", item.Collection, item.Name)
collection := filepath.Join("/", item.Collection)
if strings.HasPrefix(cFilepath, rFilepath) {
res.Files = append(res.Files, item)
res.Collections = append(res.Collections, collection)
}
}
code := http.StatusOK
return code, res, err
}
// ListCollections
type ListCollectionsParams struct {
Path string
}
type ListCollectionsResult struct {
Collections []string `json:"collection,omitempty"`
}
func (oper *Operator) ListCollections(ctx context.Context, operID string, param *ListCollectionsParams) (int, *ListCollectionsResult, error) {
var err error
res := &ListCollectionsResult{
Collections: make([]string, 0),
}
param.Path, err = cleanFilepath(param.Path)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
fileDescrs, err := oper.mdb.ListAllFiles(ctx)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
cmap := make(map[string]bool)
for _, item := range fileDescrs {
cPath := filepath.Join("/", item.Collection)
pattern := filepath.Join("/", param.Path)
if strings.HasPrefix(cPath, pattern) {
_, exists := cmap[cPath]
if !exists {
cmap[cPath] = true
}
}
}
for key, _ := range cmap {
res.Collections = append(res.Collections, key)
}
slices.Sort(res.Collections)
code := http.StatusOK
return code, res, err
}
// DeleteColletion
type DeleteColletionParams struct {
Path string
}
type DeleteColletionResult struct {
Files []descr.File `json:"collection,omitempty"`
}
func (oper *Operator) DeleteColletion(ctx context.Context, operID string, param *DeleteColletionParams) (int, *DeleteColletionResult, error) {
var err error
res := &DeleteColletionResult{
Files: make([]descr.File, 0),
}
param.Path, err = cleanFilepath(param.Path)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
oper.logg.Debugf("=== %s", param.Path)
fileDescrs, err := oper.mdb.ListFilesByCollection(ctx, param.Path)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
// TODO: transaction
for _, file := range fileDescrs {
err = oper.store.DeleteFile(file.Collection, file.Name)
if err != nil {
oper.logg.Warningf("%v", err)
err = nil
//code := http.StatusInternalServerError
//return code, res, err
}
err = oper.mdb.DeleteFileByCollectionName(ctx, file.Collection, file.Name)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
res.Files = append(res.Files, file)
}
code := http.StatusOK
return code, res, err
}
+6
View File
@@ -80,6 +80,12 @@ func (svc *Service) Build() error {
svc.rout.Get(`/v3/api/files/{filepath}`, svc.hand.ListFiles)
svc.rout.Get(`/v3/api/files/`, svc.hand.ListFiles)
svc.rout.Get(`/v3/api/collections/{path}`, svc.hand.ListCollections)
svc.rout.Get(`/v3/api/collections/`, svc.hand.ListCollections)
svc.rout.Delete(`/v3/api/collection/{path}`, svc.hand.DeleteCollection)
svc.rout.Delete(`/v3/api/collection/`, svc.hand.DeleteCollection)
svc.rout.Get(`/v2/`, svc.hand.GetVersion)
svc.rout.Head(`/v2/{name}/manifests/{reference}`, svc.hand.ManifestExists)
+6 -6
View File
@@ -45,7 +45,7 @@ type CommonAccountParams struct {
func (util *AccountUtil) CreateAccountCmds() *cobra.Command {
var subCmd = &cobra.Command{
Use: "accounts",
Short: "Account operation",
Short: "Account operations",
Aliases: []string{"account"},
}
const defaultTimeout uint64 = 10
@@ -58,7 +58,7 @@ func (util *AccountUtil) CreateAccountCmds() *cobra.Command {
// CreateAccount
var createAccountCmd = &cobra.Command{
Use: "create host username password",
Use: "create [user:pass@]hostname[:port] username password",
Short: "Create user account",
Args: cobra.ExactArgs(3),
Run: util.CreateAccount,
@@ -67,7 +67,7 @@ func (util *AccountUtil) CreateAccountCmds() *cobra.Command {
// GetAccount
var getAccountCmd = &cobra.Command{
Use: "get hostname accountId|username",
Use: "get [user:pass@]hostname[:port] accountId|username",
Short: "Get account info",
Args: cobra.ExactArgs(2),
Run: util.GetAccount,
@@ -76,7 +76,7 @@ func (util *AccountUtil) CreateAccountCmds() *cobra.Command {
// UpdateAccount
var updateAccountCmd = &cobra.Command{
Use: "update hostname username|accounId",
Use: "update [user:pass@]hostname[:port] username|accounId",
Short: "Update account parameters",
Args: cobra.ExactArgs(2),
Run: util.UpdateAccount,
@@ -88,7 +88,7 @@ func (util *AccountUtil) CreateAccountCmds() *cobra.Command {
// DeleteAccount
var deleteAccountCmd = &cobra.Command{
Use: "delete hostname username|accountId",
Use: "delete [user:pass@]hostname[:port] username|accountId",
Short: "Delete account",
Args: cobra.ExactArgs(2),
Run: util.DeleteAccount,
@@ -98,7 +98,7 @@ func (util *AccountUtil) CreateAccountCmds() *cobra.Command {
// ListAccount
var listAccountsCmd = &cobra.Command{
Use: "list hostname",
Use: "list [user:pass@]hostname[:port]",
Short: "list accounts",
Args: cobra.ExactArgs(1),
Run: util.ListAccounts,
+150 -38
View File
@@ -11,10 +11,12 @@ package main
import (
"context"
"errors"
"fmt"
"io/fs"
"net/url"
"path/filepath"
"strings"
"time"
"github.com/spf13/cobra"
@@ -26,7 +28,7 @@ import (
func (util *FileUtil) CreateFileCmds() *cobra.Command {
var subCmd = &cobra.Command{
Use: "files",
Short: "File operation",
Short: "File operations",
Aliases: []string{"file"},
}
const defaultTimeout uint64 = 10
@@ -39,89 +41,111 @@ func (util *FileUtil) CreateFileCmds() *cobra.Command {
// PutFile
var putFileCmd = &cobra.Command{
Use: "put",
Use: "put filepath [user:pass@]hostname[:port]/collection/name",
Args: cobra.ExactArgs(2),
Aliases: []string{"push"},
Short: "Put file to storage",
Run: util.PutFile,
}
putFileCmd.Flags().StringVarP(&util.putFileParams.Source, "src", "S", "", "Source path")
putFileCmd.Flags().StringVarP(&util.putFileParams.Dest, "dest", "D", "", "Desctination path")
putFileCmd.MarkFlagsRequiredTogether("src", "dest")
putFileCmd.MarkFlagFilename("src")
subCmd.AddCommand(putFileCmd)
// GetFile
var getFileCmd = &cobra.Command{
Use: "get",
Use: "get [user:pass@]hostname[:port]/collection/name filepath",
Aliases: []string{"pull"},
Args: cobra.ExactArgs(2),
Short: "Get file from storage",
Run: util.GetFile,
}
getFileCmd.Flags().StringVarP(&util.getFileParams.Source, "src", "S", "", "Source path")
getFileCmd.Flags().StringVarP(&util.getFileParams.Dest, "dest", "D", "", "Desctination path")
getFileCmd.MarkFlagsRequiredTogether("src", "dest")
subCmd.AddCommand(getFileCmd)
// FileInfo
var fileInfoCmd = &cobra.Command{
Use: "info",
Use: "info [user:pass@]hostname[:port]/collection/name",
Args: cobra.ExactArgs(1),
Short: "Show file information",
Run: util.FileInfo,
}
fileInfoCmd.Flags().StringVarP(&util.fileInfoParams.Filepath, "path", "P", "", "File path")
fileInfoCmd.MarkFlagRequired("path")
subCmd.AddCommand(fileInfoCmd)
// DeleteFile
var deleteFileCmd = &cobra.Command{
Use: "delete",
Use: "delete [user:pass@]hostname[:port]/collection/name",
Args: cobra.ExactArgs(1),
Aliases: []string{"remove"},
Short: "Delete file in storage",
Run: util.DeleteFile,
}
deleteFileCmd.Flags().StringVarP(&util.deleteFileParams.Filepath, "path", "P", "", "File path")
deleteFileCmd.MarkFlagRequired("path")
subCmd.AddCommand(deleteFileCmd)
// ListFiles
var listFilesCmd = &cobra.Command{
Use: "list",
Short: "List file in storage",
Use: "list [user:pass@]hostname[:port]/catalog",
Args: cobra.ExactArgs(1),
Short: "List files in storage",
Run: util.ListFiles,
}
listFilesCmd.Flags().StringVarP(&util.listFilesParams.Filepath, "catalog", "C", "", "Catalog path")
listFilesCmd.Flags().BoolVarP(&util.listFilesParams.Detail, "detail", "D", false, "Show detail file information")
listFilesCmd.MarkFlagRequired("catalog")
subCmd.AddCommand(listFilesCmd)
// ImportFiles
var importFilesCmd = &cobra.Command{
Use: "import",
Use: "import directory [user:pass@]hostname[:port]/collection",
Args: cobra.ExactArgs(2),
Short: "Send file tree to storage as is",
Run: util.ImportFiles,
}
importFilesCmd.Flags().StringVarP(&util.importFilesParams.Source, "src", "S", "", "Source base path")
importFilesCmd.Flags().StringVarP(&util.importFilesParams.Dest, "dest", "D", "", "Desctination base path")
importFilesCmd.MarkFlagsRequiredTogether("src", "dest")
subCmd.AddCommand(importFilesCmd)
return subCmd
}
func (util *FileUtil) CreateCollectionCmds() *cobra.Command {
var subCmd = &cobra.Command{
Use: "collections",
Short: "Colletion operations",
Aliases: []string{"col", "cols", "dir", "dirs"},
}
const defaultTimeout uint64 = 10
subCmd.PersistentFlags().StringVarP(&util.commonFileParams.Username, "user", "u", "", "Username")
subCmd.PersistentFlags().StringVarP(&util.commonFileParams.Password, "pass", "p", "", "Password")
subCmd.PersistentFlags().Uint64VarP(&util.commonFileParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout")
subCmd.MarkPersistentFlagRequired("host")
subCmd.MarkFlagsRequiredTogether("user", "pass")
// ListCollections
var listCollectionsCmd = &cobra.Command{
Use: "list [user:pass@]hostname[:port]/catalog",
Args: cobra.ExactArgs(1),
Short: "List collections in storage",
Run: util.ListCollections,
}
subCmd.AddCommand(listCollectionsCmd)
// DeleteCollection
var deleteCollectionCmd = &cobra.Command{
Use: "delete [user:pass@]hostname[:port]/catalog",
Args: cobra.ExactArgs(1),
Short: "Delete all files in collection",
Run: util.DeleteCollection,
}
deleteCollectionCmd.Flags().BoolVarP(&util.deleteCollectionParams.Detail, "detail", "D", false, "Show detail file information")
subCmd.AddCommand(deleteCollectionCmd)
return subCmd
}
type FileUtil struct {
fileInfoParams FileInfoParams
putFileParams PutFileParams
getFileParams GetFileParams
deleteFileParams DeleteFileParams
listFilesParams ListFilesParams
importFilesParams ImportFilesParams
commonFileParams CommonFileParams
fileInfoParams FileInfoParams
putFileParams PutFileParams
getFileParams GetFileParams
deleteFileParams DeleteFileParams
listFilesParams ListFilesParams
importFilesParams ImportFilesParams
listCollectionsParams ListCollectionsParams
deleteCollectionParams DeleteCollectionParams
commonFileParams CommonFileParams
}
type CommonFileParams struct {
@@ -139,6 +163,7 @@ type FileInfoResult struct {
}
func (util *FileUtil) FileInfo(cmd *cobra.Command, args []string) {
util.fileInfoParams.Filepath = args[0]
res, err := util.fileInfo(&util.commonFileParams, &util.fileInfoParams)
printResponse(res, err)
}
@@ -172,6 +197,8 @@ type PutFileParams struct {
type PutFileResult struct{}
func (util *FileUtil) PutFile(cmd *cobra.Command, args []string) {
util.putFileParams.Source = args[0]
util.putFileParams.Dest = args[1]
res, err := util.putFile(&util.commonFileParams, &util.putFileParams)
printResponse(res, err)
}
@@ -199,6 +226,8 @@ type GetFileParams struct {
}
func (util *FileUtil) GetFile(cmd *cobra.Command, args []string) {
util.getFileParams.Source = args[0]
util.getFileParams.Dest = args[1]
res, err := util.getFile(&util.commonFileParams, &util.getFileParams)
printResponse(res, err)
}
@@ -229,6 +258,7 @@ type DeleteFileParams struct {
type DeleteFileResult struct{}
func (util *FileUtil) DeleteFile(cmd *cobra.Command, args []string) {
util.deleteFileParams.Filepath = args[0]
res, err := util.deleteFile(&util.commonFileParams, &util.deleteFileParams)
printResponse(res, err)
}
@@ -260,6 +290,7 @@ type ListFilesResult struct {
}
func (util *FileUtil) ListFiles(cmd *cobra.Command, args []string) {
util.listFilesParams.Filepath = args[0]
res, err := util.listFiles(&util.commonFileParams, &util.listFilesParams)
printResponse(res, err)
}
@@ -299,6 +330,9 @@ type ImportFilesResult struct {
}
func (util *FileUtil) ImportFiles(cmd *cobra.Command, args []string) {
util.importFilesParams.Source = args[0]
util.importFilesParams.Dest = args[1]
res, err := util.importFiles(&util.commonFileParams, &util.importFilesParams)
printResponse(res, err)
}
@@ -330,7 +364,8 @@ func (util *FileUtil) importFiles(common *CommonFileParams, params *ImportFilesP
if !infoItem.IsDir() {
timeout := time.Duration(common.Timeout) * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout)
dest, _ := url.JoinPath(params.Dest, walkPath)
relPath, _ := strings.CutPrefix(walkPath, params.Source)
dest, _ := url.JoinPath(params.Dest, relPath)
if err != nil {
putErrors = append(putErrors, err)
return nil
@@ -346,9 +381,86 @@ func (util *FileUtil) importFiles(common *CommonFileParams, params *ImportFilesP
}
return nil
}
for _, item := range putErrors {
err = errors.Join(err, item)
}
err = filepath.Walk(params.Source, walcFunc)
if err != nil {
return res, err
}
return res, err
}
// ListCollections
type ListCollectionsParams struct {
Path string
}
type ListCollectionsResult struct {
Collections []string `yaml:"collections,omitempty"`
}
func (util *FileUtil) ListCollections(cmd *cobra.Command, args []string) {
util.listCollectionsParams.Path = args[0]
res, err := util.listCollections(&util.commonFileParams, &util.listCollectionsParams)
printResponse(res, err)
}
func (util *FileUtil) listCollections(common *CommonFileParams, params *ListCollectionsParams) (*ListCollectionsResult, error) {
var err error
res := &ListCollectionsResult{
Collections: make([]string, 0),
}
params.Path, err = packUserinfo(params.Path, common.Username, common.Password)
if err != nil {
return res, err
}
timeout := time.Duration(common.Timeout) * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout)
collecions, err := client.NewClient().ListCollections(ctx, params.Path)
if err != nil {
return res, err
}
res.Collections = collecions
return res, err
}
// DeleteCollection
type DeleteCollectionParams struct {
Path string
Detail bool
}
type DeleteCollectionResult struct {
Files []descr.File `yaml:"files,omitempty"`
Filenames []string `yaml:"filenames,omitempty"`
}
func (util *FileUtil) DeleteCollection(cmd *cobra.Command, args []string) {
util.deleteCollectionParams.Path = args[0]
res, err := util.deleteCollection(&util.commonFileParams, &util.deleteCollectionParams)
printResponse(res, err)
}
func (util *FileUtil) deleteCollection(common *CommonFileParams, params *DeleteCollectionParams) (*DeleteCollectionResult, error) {
var err error
res := &DeleteCollectionResult{
Filenames: make([]string, 0),
}
params.Path, err = packUserinfo(params.Path, common.Username, common.Password)
if err != nil {
return res, err
}
timeout := time.Duration(common.Timeout) * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout)
files, err := client.NewClient().DeleteCollection(ctx, params.Path)
if err != nil {
return res, err
}
if params.Detail {
res.Files = files
} else {
for _, file := range files {
res.Filenames = append(res.Filenames, filepath.Join(file.Collection, file.Name))
}
}
return res, err
}
+12 -12
View File
@@ -24,7 +24,7 @@ import (
func (util *GrantUtil) CreateGrantCmds() *cobra.Command {
var subCmd = &cobra.Command{
Use: "grants",
Short: "Grant operation",
Short: "Grant operations",
Aliases: []string{"grant"},
}
const defaultTimeout uint64 = 10
@@ -35,7 +35,7 @@ func (util *GrantUtil) CreateGrantCmds() *cobra.Command {
// CreateGrant
var createGrantCmd = &cobra.Command{
Use: "create hostname[:port] username|accountId rigth pattern",
Use: "create [user:pass@]hostname[:port] username|accountId rigth pattern",
Short: "Create grant",
Args: cobra.ExactArgs(4),
Run: util.CreateGrant,
@@ -44,7 +44,7 @@ func (util *GrantUtil) CreateGrantCmds() *cobra.Command {
// GetGrant
var getGrantCmd = &cobra.Command{
Use: "get hostname[:port] grantId",
Use: "get [user:pass@]hostname[:port] grantId",
Short: "Get detail grant info",
Args: cobra.ExactArgs(2),
Run: util.GetGrant,
@@ -53,16 +53,16 @@ func (util *GrantUtil) CreateGrantCmds() *cobra.Command {
// UpdateGrant
var updateGrantCmd = &cobra.Command{
Use: "update hostname[:port] gruntId newPattern",
Use: "update [user:pass@]hostname[:port] gruntId newPattern",
Short: "Update grant parameters",
Args: cobra.ExactArgs(3),
Run: util.UpdateGrant,
Run: util.UpdateGrant,
}
subCmd.AddCommand(updateGrantCmd)
// DeleteGrant
var deleteGrantCmd = &cobra.Command{
Use: "delete hostname[:port] gruntId ",
Use: "delete [user:pass@]hostname[:port] gruntId ",
Short: "Delete grant",
Args: cobra.ExactArgs(2),
@@ -72,9 +72,9 @@ func (util *GrantUtil) CreateGrantCmds() *cobra.Command {
// ListGrants
var listGrantsCmd = &cobra.Command{
Use: "list hostname[:port] accountId|username",
Use: "list [user:pass@]hostname[:port] accountId|username",
Short: "list user grants",
Args: cobra.ExactArgs(2),
Args: cobra.ExactArgs(2),
Run: util.ListGrants,
}
listGrantsCmd.Flags().BoolVarP(&util.listGrantsParams.Detail, "detail", "d", false, "Show detail information")
@@ -128,9 +128,9 @@ func (util *GrantUtil) createGrant(common *CommonGrantParams, params *CreateGran
}
timeout := time.Duration(common.Timeout) * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout)
re := regexp.MustCompile(uuidRegex)
re := regexp.MustCompile(uuidRegex)
id := strings.ToLower(params.AccountID)
var operRes string
var operRes string
if re.MatchString(id) {
operRes, err = client.NewClient().CreateGrantByAccountID(ctx, hostname, params.AccountID, params.Right, params.Pattern)
} else {
@@ -249,8 +249,8 @@ type ListGrantsParams struct {
}
type ListGrantsResult struct {
Grants []descr.Grant `yaml:"grants,omitempty"`
Rights map[string]string `yaml:"rights,omitempty"`
Grants []descr.Grant `yaml:"grants,omitempty"`
Rights map[string]string `yaml:"rights,omitempty"`
}
func (util *GrantUtil) ListGrants(cmd *cobra.Command, args []string) {
+28 -22
View File
@@ -12,6 +12,7 @@ package main
import (
"context"
"net/url"
"os"
"path"
"strings"
"time"
@@ -44,7 +45,7 @@ func (util *ImageUtil) CreateImageCmds() *cobra.Command {
var subCmd = &cobra.Command{
Use: "images",
Short: "Image operation",
Short: "Image operations",
Aliases: []string{"image"},
}
subCmd.PersistentFlags().StringVarP(&util.commonImageParams.Username, "user", "u", "", "Username")
@@ -54,50 +55,38 @@ func (util *ImageUtil) CreateImageCmds() *cobra.Command {
// PushImage
var pushImageCmd = &cobra.Command{
Use: "push",
Use: "push filename [user:pass@]hostname[:port]/path:tag",
Short: "Push container image from local tar file into registry",
Args: cobra.ExactArgs(2),
Run: util.PushImage,
}
pushImageCmd.Flags().StringVarP(&util.pushImageParams.Imagepath, "image", "i", "", "Remote image path")
pushImageCmd.Flags().StringVarP(&util.pushImageParams.Filepath, "file", "f", "", "Local tar file path")
pushImageCmd.MarkFlagRequired("image")
pushImageCmd.MarkFlagRequired("file")
subCmd.AddCommand(pushImageCmd)
// ImageInfo
var imageInfoCmd = &cobra.Command{
Use: "info",
Use: "info [user:pass@]hostname[:port]/path:tag",
Short: "Show container image info",
Args: cobra.ExactArgs(1),
Run: util.ImageInfo,
}
imageInfoCmd.Flags().StringVarP(&util.imageInfoParams.Imagepath, "image", "i", "", "Remote image path")
imageInfoCmd.MarkFlagRequired("image")
subCmd.AddCommand(imageInfoCmd)
// PullImage
var pullImageCmd = &cobra.Command{
Use: "pull",
Use: "pull [user:pass@]hostname[:port]/path:tag filename",
Short: "Pull container image from registry into local file",
Args: cobra.ExactArgs(2),
Run: util.PullImage,
}
pullImageCmd.Flags().StringVarP(&util.pullImageParams.Imagepath, "image", "i", "", "Remote image path")
pullImageCmd.Flags().StringVarP(&util.pullImageParams.Filepath, "file", "f", "", "Local file path")
pullImageCmd.MarkFlagRequired("image")
pullImageCmd.MarkFlagRequired("file")
subCmd.AddCommand(pullImageCmd)
// DeleteImage
var deleteImageCmd = &cobra.Command{
Use: "delete",
Use: "delete [user:pass@]hostname[:port]/path:tag",
Short: "Delete container image from registry",
Args: cobra.ExactArgs(1),
Run: util.DeleteImage,
}
deleteImageCmd.Flags().StringVarP(&util.deleteImageParams.Imagepath, "image", "i", "", "Remote image path")
deleteImageCmd.MarkFlagRequired("image")
subCmd.AddCommand(deleteImageCmd)
return subCmd
@@ -126,6 +115,9 @@ type PushImageParams struct {
type PushImageResult struct{}
func (util *ImageUtil) PushImage(cmd *cobra.Command, args []string) {
util.pushImageParams.Filepath = args[0]
util.pushImageParams.Imagepath = args[1]
res, err := util.pushImage(&util.commonImageParams, &util.pushImageParams)
printResponse(res, err)
}
@@ -159,6 +151,7 @@ type ImageInfoResult struct {
}
func (util *ImageUtil) ImageInfo(cmd *cobra.Command, args []string) {
util.imageInfoParams.Imagepath = args[0]
res, err := util.imageInfo(&util.commonImageParams, &util.imageInfoParams)
printResponse(res, err)
}
@@ -190,9 +183,14 @@ type PullImageParams struct {
Filepath string
}
type PullImageResult struct{}
type PullImageResult struct {
Filepath string `yaml:"filepath"`
Size int64 `yaml:"size"`
}
func (util *ImageUtil) PullImage(cmd *cobra.Command, args []string) {
util.pullImageParams.Imagepath = args[0]
util.pullImageParams.Filepath = args[1]
res, err := util.pullImage(&util.commonImageParams, &util.pullImageParams)
printResponse(res, err)
}
@@ -214,6 +212,13 @@ func (util *ImageUtil) pullImage(common *CommonImageParams, params *PullImagePar
if err != nil {
return res, err
}
filestat, err := os.Stat(params.Filepath)
if err != nil {
return res, err
}
res.Size = filestat.Size()
res.Filepath = params.Filepath
return res, err
}
@@ -226,6 +231,7 @@ type DeleteImageResult struct {
}
func (util *ImageUtil) DeleteImage(cmd *cobra.Command, args []string) {
util.deleteImageParams.Imagepath = args[0]
res, err := util.deleteImage(&util.commonImageParams, &util.deleteImageParams)
printResponse(res, err)
}
+1
View File
@@ -54,6 +54,7 @@ func (util *Util) Build() error {
rootCmd.CompletionOptions.DisableDefaultCmd = true
rootCmd.AddCommand(util.CreateFileCmds())
rootCmd.AddCommand(util.CreateCollectionCmds())
rootCmd.AddCommand(util.CreateImageCmds())
rootCmd.AddCommand(util.CreateAccountCmds())
rootCmd.AddCommand(util.CreateGrantCmds())
+116
View File
@@ -264,3 +264,119 @@ func (cli *Client) ListFiles(ctx context.Context, catalogURI string) ([]descr.Fi
}
return res, err
}
func (cli *Client) ListCollections(ctx context.Context, catalogURI string) ([]string, error) {
var err error
res := make([]string, 0)
catalogURI, username, password, err := repackServiceURI(catalogURI)
if err != nil {
return res, err
}
catalogURI, err = convertCollectionsURI(catalogURI)
if err != nil {
return res, err
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, catalogURI, 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)
if err != nil {
return res, err
}
defer resp.Body.Close()
contentLength := resp.Header.Get("Content-Length")
if contentLength == "" {
err = fmt.Errorf("Empty Content-Length received")
return res, err
}
if resp.StatusCode != http.StatusOK {
err := fmt.Errorf("Received wrong status code: %s", resp.Status)
return res, err
}
declSize, err := strconv.ParseInt(contentLength, 10, 64)
if err != nil {
err = fmt.Errorf("Wrong Content-Length value: %v", err)
return res, err
}
respBuffer := bytes.NewBuffer(nil)
size, err := io.Copy(respBuffer, resp.Body)
if err != nil {
return res, err
}
respBytes := respBuffer.Bytes()
if size != declSize {
err := fmt.Errorf("Mismatch Content-Length and recorded filesize")
return res, err
}
err = json.Unmarshal(respBytes, &res)
if err != nil {
return res, err
}
return res, err
}
func (cli *Client) DeleteCollection(ctx context.Context, catalogURI string) ([]descr.File, error) {
var err error
res := make([]descr.File, 0)
catalogURI, username, password, err := repackServiceURI(catalogURI)
if err != nil {
return res, err
}
catalogURI, err = convertCollectionURI(catalogURI)
if err != nil {
return res, err
}
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, catalogURI, 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)
if err != nil {
return res, err
}
defer resp.Body.Close()
contentLength := resp.Header.Get("Content-Length")
if contentLength == "" {
err = fmt.Errorf("Empty Content-Length received")
return res, err
}
if resp.StatusCode != http.StatusOK {
err := fmt.Errorf("Received wrong status code: %s", resp.Status)
return res, err
}
declSize, err := strconv.ParseInt(contentLength, 10, 64)
if err != nil {
err = fmt.Errorf("Wrong Content-Length value: %v", err)
return res, err
}
respBuffer := bytes.NewBuffer(nil)
size, err := io.Copy(respBuffer, resp.Body)
if err != nil {
return res, err
}
respBytes := respBuffer.Bytes()
if size != declSize {
err := fmt.Errorf("Mismatch Content-Length and recorded filesize")
return res, err
}
err = json.Unmarshal(respBytes, &res)
if err != nil {
return res, err
}
return res, err
}
+26
View File
@@ -59,6 +59,32 @@ func convertFilesURI(fileuri string) (string, error) {
return res, err
}
func convertCollectionsURI(fileuri string) (string, error) {
var err error
var res string
uri, err := url.Parse(fileuri)
const prefixAPI = "/v3/api/collections/"
uri.Path, err = url.JoinPath(prefixAPI, uri.Path)
if err != nil {
return res, err
}
res = uri.String()
return res, err
}
func convertCollectionURI(fileuri string) (string, error) {
var err error
var res string
uri, err := url.Parse(fileuri)
const prefixAPI = "/v3/api/collection/"
uri.Path, err = url.JoinPath(prefixAPI, 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
+2 -6
View File
@@ -54,7 +54,6 @@ func (cli *Client) CreateGrantByAccountID(ctx context.Context, hosturi, accountI
return res, err
}
func (cli *Client) CreateGrantByUsername(ctx context.Context, hosturi, username, right, pattern string) (string, error) {
var err error
var res string
@@ -65,8 +64,8 @@ func (cli *Client) CreateGrantByUsername(ctx context.Context, hosturi, username,
}
operParams := operator.CreateGrantParams{
Username: username,
Right: right,
Pattern: pattern,
Right: right,
Pattern: pattern,
}
paramsJson, err := json.Marshal(operParams)
if err != nil {
@@ -90,7 +89,6 @@ func (cli *Client) CreateGrantByUsername(ctx context.Context, hosturi, username,
return res, err
}
func (cli *Client) GetGrant(ctx context.Context, hosturi, id string) (*descr.Grant, error) {
var err error
res := &descr.Grant{}
@@ -124,8 +122,6 @@ func (cli *Client) GetGrant(ctx context.Context, hosturi, id string) (*descr.Gra
return res, err
}
func (cli *Client) UpdateGrant(ctx context.Context, hosturi, grantID, newPattern string) error {
var err error
+1 -1
View File
@@ -22,7 +22,7 @@ import (
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
)
func (cli *Client) PullImage(ctx context.Context, filepath, imagepath string) error {
func (cli *Client) PullImage(ctx context.Context, imagepath, filepath string) error {
var err error
imagepath, username, password, err := repackReference(imagepath)