From 8d3deff69e92f03d0146b8c047f477e64acff9c7 Mon Sep 17 00:00:00 2001 From: Suryansh Prajapati <58465650+drk1rd@users.noreply.github.com> Date: Tue, 25 Mar 2025 10:38:20 +0530 Subject: [PATCH 1/2] basic s3 func --- cli/cmd/root.go | 26 ++++---- cli/cmd/s3/bucket.go | 86 ++++++++++++++++++++++++++ cli/cmd/s3/object.go | 140 +++++++++++++++++++++++++++++++++++++++++++ cli/cmd/s3/s3.go | 17 ++++++ cli/go.mod | 16 ++++- cli/go.sum | 30 ++++++++++ 6 files changed, 301 insertions(+), 14 deletions(-) create mode 100644 cli/cmd/s3/bucket.go create mode 100644 cli/cmd/s3/object.go create mode 100644 cli/cmd/s3/s3.go diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 934d8c8..5df3365 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -1,31 +1,33 @@ package cmd import ( - "fmt" + "fmt" - "github.com/spf13/cobra" "github.com/homecloudhq/homecloud/cli/cmd/compute" + "github.com/homecloudhq/homecloud/cli/cmd/s3" + "github.com/spf13/cobra" ) // RootCmd is the base command for the CLI, exported for use in other modules. var RootCmd = &cobra.Command{ - Use: "homecloud", - Short: "HomeCloud CLI for managing self-hosted cloud services", - Long: `HomeCloud CLI provides tools to deploy, manage, and monitor + Use: "homecloud", + Short: "HomeCloud CLI for managing self-hosted cloud services", + Long: `HomeCloud CLI provides tools to deploy, manage, and monitor self-hosted cloud infrastructure.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Welcome to HomeCloud CLI!") - }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Welcome to HomeCloud CLI!") + }, } // Execute runs the root command, entry point for the CLI. func Execute() { - if err := RootCmd.Execute(); err != nil { - fmt.Println(err) - } + if err := RootCmd.Execute(); err != nil { + fmt.Println(err) + } } // Register all individual comments here. func init() { RootCmd.AddCommand(compute.ComputeCmd) -} \ No newline at end of file + RootCmd.AddCommand(s3.S3Cmd) +} diff --git a/cli/cmd/s3/bucket.go b/cli/cmd/s3/bucket.go new file mode 100644 index 0000000..ae5745a --- /dev/null +++ b/cli/cmd/s3/bucket.go @@ -0,0 +1,86 @@ +package s3 + +import ( + "context" + "fmt" + "log" + + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" + "github.com/spf13/cobra" +) + +// Initialize MinIO client +func connectMinIO() *minio.Client { + client, err := minio.New("localhost:9000", &minio.Options{ + Creds: credentials.NewStaticV4("minioadmin", "minioadmin", ""), + Secure: false, + }) + if err != nil { + log.Fatalf("Failed to connect to MinIO: %v", err) + } + return client +} + +// Define bucket commands +var bucketCmd = &cobra.Command{ + Use: "bucket", + Short: "Manage S3 buckets", +} + +// Create bucket command +var createBucketCmd = &cobra.Command{ + Use: "create", + Short: "Create a new S3 bucket", + Run: func(cmd *cobra.Command, args []string) { + client := connectMinIO() + bucketName, _ := cmd.Flags().GetString("name") + + err := client.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{}) + if err != nil { + log.Fatalf("Failed to create bucket: %v", err) + } + fmt.Printf("Bucket '%s' created successfully!\n", bucketName) + }, +} + +// Delete bucket command +var deleteBucketCmd = &cobra.Command{ + Use: "delete", + Short: "Delete an S3 bucket", + Run: func(cmd *cobra.Command, args []string) { + client := connectMinIO() + bucketName, _ := cmd.Flags().GetString("name") + + err := client.RemoveBucket(context.Background(), bucketName) + if err != nil { + log.Fatalf("Failed to delete bucket: %v", err) + } + fmt.Printf("Bucket '%s' deleted successfully!\n", bucketName) + }, +} + +// List buckets command +var listBucketsCmd = &cobra.Command{ + Use: "list", + Short: "List all S3 buckets", + Run: func(cmd *cobra.Command, args []string) { + client := connectMinIO() + buckets, err := client.ListBuckets(context.Background()) + if err != nil { + log.Fatalf("Failed to list buckets: %v", err) + } + for _, bucket := range buckets { + fmt.Println(bucket.Name) + } + }, +} + +func init() { + bucketCmd.AddCommand(createBucketCmd) + bucketCmd.AddCommand(deleteBucketCmd) + bucketCmd.AddCommand(listBucketsCmd) + + createBucketCmd.Flags().StringP("name", "n", "", "Name of the bucket (required)") + deleteBucketCmd.Flags().StringP("name", "n", "", "Name of the bucket (required)") +} diff --git a/cli/cmd/s3/object.go b/cli/cmd/s3/object.go new file mode 100644 index 0000000..2b125dd --- /dev/null +++ b/cli/cmd/s3/object.go @@ -0,0 +1,140 @@ +package s3 + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/minio/minio-go/v7" + "github.com/spf13/cobra" +) + +// Create the "object" command +var objectCmd = &cobra.Command{ + Use: "object", + Short: "Manage S3 objects", +} + +// Upload file command +var uploadCmd = &cobra.Command{ + Use: "upload", + Short: "Upload a file to an S3 bucket", + Run: func(cmd *cobra.Command, args []string) { + client := connectMinIO() + + bucket, _ := cmd.Flags().GetString("bucket") + filePath, _ := cmd.Flags().GetString("file") + + file, err := os.Open(filePath) + if err != nil { + log.Fatalf("Failed to open file: %v", err) + } + defer file.Close() + + fileStat, _ := file.Stat() + _, err = client.PutObject(context.Background(), bucket, filePath, file, fileStat.Size(), minio.PutObjectOptions{}) + if err != nil { + log.Fatalf("Failed to upload file: %v", err) + } + + fmt.Printf("βœ… File '%s' uploaded to bucket '%s'!\n", filePath, bucket) + }, +} + +// Download file command +var downloadCmd = &cobra.Command{ + Use: "download", + Short: "Download a file from an S3 bucket", + Run: func(cmd *cobra.Command, args []string) { + client := connectMinIO() + + bucket, _ := cmd.Flags().GetString("bucket") + file, _ := cmd.Flags().GetString("file") + destination, _ := cmd.Flags().GetString("destination") + + if destination == "" { + destination = file + } + + err := client.FGetObject(context.Background(), bucket, file, destination, minio.GetObjectOptions{}) + if err != nil { + log.Fatalf("❌ Failed to download file: %v", err) + } + + fmt.Printf("βœ… File '%s' downloaded from bucket '%s' to '%s'!\n", file, bucket, destination) + }, +} + +// List objects command +var listObjectsCmd = &cobra.Command{ + Use: "list", + Short: "List all objects in a bucket", + Run: func(cmd *cobra.Command, args []string) { + client := connectMinIO() + bucket, _ := cmd.Flags().GetString("bucket") + + objectCh := client.ListObjects(context.Background(), bucket, minio.ListObjectsOptions{}) + fmt.Printf("πŸ“‚ Objects in bucket '%s':\n", bucket) + + for object := range objectCh { + if object.Err != nil { + log.Fatalf("❌ Error listing objects: %v", object.Err) + } + fmt.Println(" - " + object.Key) + } + }, +} + +// Delete an object +var deleteObjectCmd = &cobra.Command{ + Use: "delete", + Short: "Delete an object from an S3 bucket", + Run: func(cmd *cobra.Command, args []string) { + client := connectMinIO() + + bucket, _ := cmd.Flags().GetString("bucket") + file, _ := cmd.Flags().GetString("file") + + err := client.RemoveObject(context.Background(), bucket, file, minio.RemoveObjectOptions{}) + if err != nil { + log.Fatalf("❌ Failed to delete object: %v", err) + } + + fmt.Printf("βœ… Object '%s' deleted from bucket '%s'!\n", file, bucket) + }, +} + +// MinIO connection setup +// The connectMinIO function is defined in bucket.go + +func init() { + // Register all object commands + objectCmd.AddCommand(uploadCmd) + objectCmd.AddCommand(downloadCmd) + objectCmd.AddCommand(listObjectsCmd) + objectCmd.AddCommand(deleteObjectCmd) + + // Upload flags + uploadCmd.Flags().StringP("bucket", "b", "", "Target bucket (required)") + uploadCmd.Flags().StringP("file", "f", "", "File to upload (required)") + uploadCmd.MarkFlagRequired("bucket") + uploadCmd.MarkFlagRequired("file") + + // Download flags + downloadCmd.Flags().StringP("bucket", "b", "", "Source bucket (required)") + downloadCmd.Flags().StringP("file", "f", "", "File to download (required)") + downloadCmd.Flags().StringP("destination", "d", "", "Destination path (optional)") + downloadCmd.MarkFlagRequired("bucket") + downloadCmd.MarkFlagRequired("file") + + // List objects + listObjectsCmd.Flags().StringP("bucket", "b", "", "Bucket to list objects from (required)") + listObjectsCmd.MarkFlagRequired("bucket") + + // Delete object + deleteObjectCmd.Flags().StringP("bucket", "b", "", "Target bucket (required)") + deleteObjectCmd.Flags().StringP("file", "f", "", "Object to delete (required)") + deleteObjectCmd.MarkFlagRequired("bucket") + deleteObjectCmd.MarkFlagRequired("file") +} diff --git a/cli/cmd/s3/s3.go b/cli/cmd/s3/s3.go new file mode 100644 index 0000000..548cdb1 --- /dev/null +++ b/cli/cmd/s3/s3.go @@ -0,0 +1,17 @@ +package s3 + +import ( + "github.com/spf13/cobra" +) + +// S3Cmd is the parent command for S3 operations +var S3Cmd = &cobra.Command{ + Use: "s3", + Short: "Manage S3-compatible storage", + Long: "Commands for managing S3-compatible object storage, including MinIO.", +} + +func init() { + S3Cmd.AddCommand(bucketCmd) + S3Cmd.AddCommand(objectCmd) +} diff --git a/cli/go.mod b/cli/go.mod index 5885b3e..af9e569 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -14,9 +14,17 @@ require ( github.com/docker/docker v27.4.1+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-ini/ini v1.67.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/klauspost/compress v1.15.9 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/minio/crc64nvme v1.0.1 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/minio-go/v7 v7.0.88 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect @@ -27,7 +35,11 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/rs/xid v1.6.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect ) diff --git a/cli/go.sum b/cli/go.sum index 21900b9..7116fda 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -18,18 +18,37 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/fsouza/go-dockerclient v1.12.0 h1:S2f2crEUbBNCFiF06kR/GvioEB8EMsb3Td/bpawD+aU= github.com/fsouza/go-dockerclient v1.12.0/go.mod h1:YWUtjg8japrqD/80L98nTtCoxQFp5B5wrSsnyeB5lFo= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY= +github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= +github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= +github.com/minio/minio-go/v7 v7.0.88 h1:v8MoIJjwYxOkehp+eiLIuvXk87P2raUtoU5klrAAshs= +github.com/minio/minio-go/v7 v7.0.88/go.mod h1:33+O8h0tO7pCeCWwBVa07RhVVfB/3vS4kEX7rwYKmIg= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= @@ -52,6 +71,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -63,17 +84,22 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -84,10 +110,14 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= From f772b73dd4c4989485db6d42ee3d285ec99692e3 Mon Sep 17 00:00:00 2001 From: Suryansh Prajapati <58465650+drk1rd@users.noreply.github.com> Date: Tue, 25 Mar 2025 11:29:17 +0530 Subject: [PATCH 2/2] s3 refined, automated setup inclusive --- cli/README.md | 184 ++++++++++++++++++-------------------- cli/cmd/s3/README.md | 205 +++++++++++++++++++++++++++++++++++++++++++ cli/cmd/s3/s3.go | 76 ++++++++++++++++ 3 files changed, 368 insertions(+), 97 deletions(-) create mode 100644 cli/cmd/s3/README.md diff --git a/cli/README.md b/cli/README.md index f2d6795..16313eb 100644 --- a/cli/README.md +++ b/cli/README.md @@ -1,121 +1,111 @@ -# HomeCloud CLI +Got it β€” let’s clean up the S3 section to match the brief style of `compute`: -This folder contains the implementation of the HomeCloud CLI tool. The CLI interacts with HomeCloud services and manages various aspects of the system, with an enhanced focus on compute resources using Docker containers. +--- -## Folder Structure +# HomeCloud CLI + +This folder contains the implementation of the HomeCloud CLI tool. The CLI interacts with HomeCloud services and manages various aspects of the system, including compute resources (Docker containers) and S3-compatible storage. + +--- + +## πŸ“ Folder Structure ```plaintext cli/ β”œβ”€β”€ cmd/ β”‚ β”œβ”€β”€ root.go # Root command of the CLI -β”‚ β”œβ”€β”€ compute/ # Component specifc folder -β”‚ β”œβ”€β”€ compute.go # Subcommand for managing compute resources (Docker-based) -β”‚ β”œβ”€β”€ config.go # Subcommand for managing CLI configurations +β”‚ β”œβ”€β”€ compute/ # Compute management commands +β”‚ β”œβ”€β”€ s3/ # S3 storage management commands +β”‚ β”œβ”€β”€ config.go # Configuration management commands β”œβ”€β”€ main.go # Entry point for the CLI application β”œβ”€β”€ go.mod # Go module file ``` -## Commands Overview - -### Root Command -- The base command for the CLI, defined in `cmd/root.go`. -- Provides help and global options for the CLI. - -### `compute` Command -- **Purpose**: Manages compute resources using Docker containers. -- **Operations**: - - **create**: Create a new Docker container and register it as a compute instance. - - **list**: List all compute instances (Docker containers). - - **start**: Start a stopped Docker container and update its status. - - **enter**: Enter a Docker container interactively. - - **stop**: Stop a running Docker container and update its status. - - **delete**: Delete a Docker container and remove its registration. - -Implemented in `cmd/compute.go`. - -### `config` Command -- **Purpose**: Manages configuration for the CLI. -- Includes: - - `set`: Updates configuration values (e.g., API endpoint). - - `get`: Retrieves configuration values. - -Implemented in `cmd/config.go`. - -## Configuration -- Configurations are stored in a JSON file located at `~/.homecloud_config.json`. -- Example keys: - - `api_endpoint`: Specifies the API endpoint for HomeCloud. - -## Getting Started -1. Navigate to the `cli` folder. -2. Run the CLI: - ```bash - go run main.go - ``` -3. Explore the available commands: - ```bash - go run main.go --help - ``` +--- -## `compute` Command Detailed Usage - -### `compute create` -- **Description**: Create a new compute instance (Docker container). -- **Flags**: - - `--name` or `-n` (required): Name of the container/instance. - - `--cpu` or `-c` (default: 1): Number of CPU cores. - - `--ram` or `-r` (default: 512MB): Amount of RAM in MB. - - `--storage` or `-s` (default: 10GB): Storage size in GB. - - `--image` or `-i` (default: "python:3.10-alpine"): Base image for the container. - -- **Example**: - ```bash - go run main.go compute create --name my_instance --cpu 2 --ram 1024 --storage 20 --image python:3.10-alpine - ``` +## πŸ”§ Commands Overview -### `compute list` -- **Description**: List all compute instances (Docker containers). -- **Example**: - ```bash - go run main.go compute list - ``` +### 🌟 Root Command +- The base command for the CLI, defined in `cmd/root.go`. +- Provides help and global options for the CLI. -### `compute start [ID]` -- **Description**: Start a stopped compute instance (Docker container). -- **Example**: - ```bash - go run main.go compute start my_instance_id - ``` +--- + +### πŸ–₯️ `compute` Command +- **Purpose**: Manages compute resources using Docker containers. +- **Operations**: + - **create**: Create a new Docker container and register it as a compute instance. + - **list**: List all compute instances. + - **start**: Start a stopped compute instance. + - **enter**: Enter a running instance interactively. + - **stop**: Stop a running instance. + - **delete**: Delete a compute instance. + +Example: +```bash +go run main.go compute create --name my_instance --cpu 2 --ram 1024 --storage 20 --image python:3.10-alpine +``` -### `compute enter [ID]` -- **Description**: Enter a compute instance (Docker container) interactively. -- **Example**: +--- + +### ☁️ `s3` Command +- **Purpose**: Manages S3-compatible storage (e.g., MinIO). +- **Operations**: + +#### `s3 bucket` + - **create**: Create a new S3 bucket. + - **list**: List all buckets. + - **delete**: Delete a bucket. + +Example: +```bash +go run main.go s3 bucket create --name my_bucket +``` + +#### `s3 object` + - **upload**: Upload a file to a bucket. + - **list**: List objects in a bucket. + - **download**: Download a file from a bucket. + - **delete**: Delete a file from a bucket. + +Example: +```bash +go run main.go s3 object upload --bucket my_bucket --file file.txt +``` + +--- + +## βš™οΈ Configuration + +Configurations are stored in `~/.homecloud_config.json`. + +Example keys: +```json +{ + "api_endpoint": "http://localhost:8080", + "s3_endpoint": "http://localhost:9000", + "s3_access_key": "your_access_key", + "s3_secret_key": "your_secret_key" +} +``` + +--- + +## πŸš€ Getting Started + +1. **Navigate to the CLI folder** ```bash - go run main.go compute enter my_instance_id + cd cli ``` -### `compute stop [ID]` -- **Description**: Stop a running compute instance (Docker container). -- **Example**: +2. **Run the CLI** ```bash - go run main.go compute stop my_instance_id + go run main.go ``` -### `compute delete [ID]` -- **Description**: Delete a compute instance (Docker container) and remove its registration. -- **Example**: +3. **Explore commands** ```bash - go run main.go compute delete my_instance_id + go run main.go --help ``` -## Instance Storage -- The state of instances is saved in a local JSON file named `compute.json`. -- This file tracks the following details for each instance: - - `ID`: Unique container ID - - `Name`: The name of the container/instance - - `CPU`: The allocated number of CPU cores - - `RAM`: The allocated amount of RAM - - `Storage`: The allocated storage space - - `BaseImage`: The base Docker image used for the container - - `Status`: The current status of the instance (running, stopped) - +--- \ No newline at end of file diff --git a/cli/cmd/s3/README.md b/cli/cmd/s3/README.md new file mode 100644 index 0000000..cf81a04 --- /dev/null +++ b/cli/cmd/s3/README.md @@ -0,0 +1,205 @@ + +# πŸš€ HomeCloud CLI: S3 Module + +The `s3` module integrates S3-compatible storage into the HomeCloud CLI, powered by **MinIO**. It supports creating buckets, managing objects, and auto-handles the MinIO setup using Docker containers. + +--- + +## πŸ“ Folder Structure + +```plaintext +cli/ +└── cmd/ + └── s3/ + β”œβ”€β”€ s3.go # Parent command for 'homecloud s3' + β”œβ”€β”€ bucket.go # Bucket commands (create, delete, list) + └── object.go # Object commands (upload, download, list, delete) +``` + +--- + +## πŸ› οΈ MinIO Setup + +When you run any `homecloud s3` command: + +βœ… **Checks if MinIO is running** +βœ… If stopped, **restarts** the container +βœ… If missing, **pulls the latest MinIO image** and **sets it up** + +--- + +### 🚧 **MinIO Configuration Defaults** + +| Setting | Value | +|------------------|---------------------------------| +| Image | `quay.io/minio/minio` | +| Data Directory | `/data` | +| API Address | `http://localhost:9000` | +| Console Address | `http://localhost:9001` | +| Root User | `admin` | +| Root Password | `admin123` | + +--- + +## πŸ”₯ S3 Commands Breakdown + +--- + +### πŸͺ£ 1️⃣ **Bucket Commands** + +```bash +homecloud s3 bucket [command] +``` + +| Command | Description | Example Usage | +|----------------|-------------------------------------|------------------------------------------------------| +| **create** | Create a new bucket | `homecloud s3 bucket create --name mybucket` | +| **delete** | Delete an existing bucket | `homecloud s3 bucket delete --name mybucket` | +| **list** | List all available buckets | `homecloud s3 bucket list` | + +--- + +#### βœ… **Bucket Command Examples** + +--- + +#### **Create a Bucket** + +```bash +homecloud s3 bucket create --name photos +``` + +βœ… **Output:** +```bash +Bucket 'photos' created successfully! +``` + +--- + +#### **List Buckets** + +```bash +homecloud s3 bucket list +``` + +βœ… **Output:** +```bash +Available Buckets: +- photos +- backups +- logs +``` + +--- + +#### **Delete a Bucket** + +```bash +homecloud s3 bucket delete --name logs +``` + +βœ… **Output:** +```bash +Bucket 'logs' deleted successfully! +``` + +--- + +### πŸ“¦ 2️⃣ **Object Commands** + +```bash +homecloud s3 object [command] +``` + +| Command | Description | Example Usage | +|----------------|--------------------------------------|--------------------------------------------------------| +| **upload** | Upload a file to a bucket | `homecloud s3 object upload --bucket photos --file profile.jpg` | +| **download** | Download a file from a bucket | `homecloud s3 object download --bucket photos --file profile.jpg --destination ./downloads` | +| **list** | List all objects in a bucket | `homecloud s3 object list --bucket photos` | +| **delete** | Delete an object from a bucket | `homecloud s3 object delete --bucket photos --file profile.jpg` | + +--- + +#### βœ… **Object Command Examples** + +--- + +#### **Upload a File** + +```bash +homecloud s3 object upload --bucket photos --file vacation.jpg +``` + +βœ… **Output:** +```bash +File 'vacation.jpg' uploaded to bucket 'photos'! +``` + +--- + +#### **List Objects in a Bucket** + +```bash +homecloud s3 object list --bucket photos +``` + +βœ… **Output:** +```bash +Files in 'photos': +- vacation.jpg +- birthday.jpg +``` + +--- + +#### **Download a File** + +```bash +homecloud s3 object download --bucket photos --file vacation.jpg --destination ./saved_pics +``` + +βœ… **Output:** +```bash +File 'vacation.jpg' downloaded to './saved_pics'! +``` + +--- + +#### **Delete an Object** + +```bash +homecloud s3 object delete --bucket photos --file vacation.jpg +``` + +βœ… **Output:** +```bash +File 'vacation.jpg' deleted from bucket 'photos'! +``` + +--- + +## πŸ” MinIO Web UI + +After running any S3 command, MinIO’s web console becomes available: + +- **URL:** `http://localhost:9001` +- **Username:** `admin` +- **Password:** `admin123` + +βœ… **Supports manual file uploads, bucket management, and monitoring!** + +--- + +## βš™οΈ Environment Variables (Optional) + +You can override MinIO settings with these environment variables before running the CLI: + +```bash +export MINIO_ROOT_USER=myuser +export MINIO_ROOT_PASSWORD=supersecurepass +export MINIO_PORT=9000 +export MINIO_CONSOLE_PORT=9001 +``` + +--- + diff --git a/cli/cmd/s3/s3.go b/cli/cmd/s3/s3.go index 548cdb1..39c0736 100644 --- a/cli/cmd/s3/s3.go +++ b/cli/cmd/s3/s3.go @@ -1,6 +1,11 @@ package s3 import ( + "fmt" + "log" + "os/exec" + "strings" + "github.com/spf13/cobra" ) @@ -9,6 +14,77 @@ var S3Cmd = &cobra.Command{ Use: "s3", Short: "Manage S3-compatible storage", Long: "Commands for managing S3-compatible object storage, including MinIO.", + Run: func(cmd *cobra.Command, args []string) { + ensureMinIODocker() + fmt.Println("MinIO is ready! Use 'homecloud s3 --help' for available commands.") + }, +} + +func ensureMinIODocker() { + containerName := "homecloud_minio" + minioImage := "quay.io/minio/minio" + minioPort := "9000" + minioConsolePort := "9001" + minioUser := "admin" + minioPass := "admin123" + + fmt.Println("πŸ” Checking MinIO setup...") + + // Check if any MinIO container exists (by image) + checkCmd := exec.Command("docker", "ps", "-a", "--filter", "ancestor="+minioImage, "--format", "{{.ID}}") + output, _ := checkCmd.Output() + containerID := strings.TrimSpace(string(output)) + + if containerID != "" { + fmt.Println("βœ… MinIO container found!") + + // Check if it's running + statusCmd := exec.Command("docker", "inspect", "-f", "{{.State.Status}}", containerID) + statusOutput, err := statusCmd.Output() + if err != nil { + log.Fatalf("❌ Failed to check MinIO container status: %v", err) + } + + containerStatus := strings.TrimSpace(string(statusOutput)) + if containerStatus == "exited" { + fmt.Println("πŸ”„ MinIO was stopped β€” restarting it...") + restartCmd := exec.Command("docker", "start", containerID) + if err := restartCmd.Run(); err != nil { + log.Fatalf("❌ Failed to restart MinIO container: %v", err) + } + fmt.Println("βœ… MinIO restarted!") + } else if containerStatus == "running" { + fmt.Println("⚑ MinIO is already running!") + } + } else { + fmt.Println("πŸš€ MinIO container not found β€” creating one...") + + // Pull the latest MinIO image (optional but ensures it’s fresh) + fmt.Println("πŸ”„ Pulling latest MinIO image...") + pullCmd := exec.Command("docker", "pull", minioImage) + if err := pullCmd.Run(); err != nil { + log.Fatalf("❌ Failed to pull MinIO image: %v", err) + } + + // Create and start MinIO container + runCmd := exec.Command( + "docker", "run", "-d", + "--name", containerName, + "-p", minioPort+":9000", + "-p", minioConsolePort+":9001", + "-e", "MINIO_ROOT_USER="+minioUser, + "-e", "MINIO_ROOT_PASSWORD="+minioPass, + minioImage, + "server", "/data", "--console-address", ":9001", + ) + + if err := runCmd.Run(); err != nil { + log.Fatalf("❌ Failed to create MinIO container: %v", err) + } + + fmt.Println("βœ… MinIO setup complete!") + fmt.Printf("🌐 Access MinIO Web UI at: http://localhost:%s (user: %s / pass: %s)\n", minioConsolePort, minioUser, minioPass) + } } func init() {