背景:
随着项目的时间越长nexus占的磁盘空间越多,因此我们需要一个清理工具;nexus自带的Cleanup Policy也可以清理但是无法满足我们的版本保留要求;网络上介绍的nexus-cli、由于我们的服务器是arm64版本所以有需要我们去源码编译、这边小小的尝试过发现有些包下不到哦、或者包名有所更改、所以还是选择调用nexus自带的api进行删除、各位好友有好方法给我留言哦。
1、代码功能:输出私钥文件和加密字符串、分别放到下面脚本及 配置文件里
//功能加密文明密码,输出加密字符串到文件encrypted_password.txt、私钥到到文件private_key.pem
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"encoding/base64"
"fmt"
"log"
"os"
)
func main() {
// 假设这是您的明文密码
password := "admin@123456"
// 生成 RSA 密钥对
privateKey, publicKey := generateRSAKeyPair()
// 加密密码
encryptedPassword := encryptRSA(publicKey, []byte(password))
fmt.Println(encryptedPassword)
// 将加密后的密码写入文件
if err := writeEncryptedPassword("encrypted_password.txt", encryptedPassword); err != nil {
log.Fatalf("Error writing encrypted password to file: %v", err)
}
// 将私钥写入文件
if err := writePrivateKey("private_key.pem", privateKey); err != nil {
log.Fatalf("Error writing private key to file: %v", err)
}
}
// generateRSAKeyPair 生成 RSA 密钥对
func generateRSAKeyPair() (*rsa.PrivateKey, *rsa.PublicKey) {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("Error generating RSA private key: %v", err)
}
return privateKey, &privateKey.PublicKey
}
// encryptRSA 使用 RSA 公钥加密数据
func encryptRSA(pubKey *rsa.PublicKey, data []byte) []byte {
encryptedData, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
if err != nil {
log.Fatalf("Error encrypting data: %v", err)
}
return encryptedData
}
// writeEncryptedPassword 将加密后的密码写入文件
func writeEncryptedPassword(filename string, encryptedPassword []byte) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
// 使用 base64 编码后再写入文件
encodedPassword := base64.StdEncoding.EncodeToString(encryptedPassword)
_, err = file.WriteString(encodedPassword)
if err != nil {
return err
}
return nil
}
// writePrivateKey 将私钥写入文件
func writePrivateKey(filename string, privateKey *rsa.PrivateKey) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
privateKeyPEM := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
}
err = pem.Encode(file, privateKeyPEM)
if err != nil {
return err
}
return nil
}
2、代码主要功能:字符串密码解密、调用api、保留指定数量版本、清理过多镜像
package main
import (
"encoding/base64"
"crypto/x509"
"encoding/pem"
"encoding/json"
"fmt"
"flag"
"crypto/rsa"
"io/ioutil"
"net/http"
"sort"
"github.com/fatih/color"
"gopkg.in/yaml.v2"
)
//设置保留数量
var num int = 2
var help bool
var fileContent = `
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAp40hbR13CSowc0tc/dLPdVSto/uxME2narLRgdfkUEzG6AAh
AxSQXikbjQ0iVEKV48RDQmlKNiYPq++IVHMOcenlj52kpQCxEP6MEtsoAxw3EYxb
TDo9mXKrbqs4jxXHlgSEavp35V1iY0acG191sDFaW0HFeAVw7y21JLaZGxGQ7GmB
1q4NVswpXRo1D4a0L+A0x6YczIRl3QiTXtgIlEKJxybx5n4NswUcWgMMWifmVaYM
HNGam5/5O1q6TdcGCH4jM3I+Sf9Gb9GyCvcVfr4M2WNm+vtX8iWeTyXEM18Dvd6t
0/bdtC/kT32OjTKBJEail368f664/hD+rWBePwIDAQABAoIBAF2yTZQAWzXT0v5W
ka0bu4oIjYXbVW4Gru27C/AJdBL3rG/Gyq83S7hsUozhYGYwSjPx6A72ZFq9lBv5
OorHQLexLf/PD2h6Z4pyXpCY39pFaAI3NEL/er0Z5AZiV6Gkc1VQN2C/qlaoj0Gn
Fds02dJq9vV7ZVtF567JJ7hdKGd61l/0ehgZdwGmJrxZR4JZEdDZuhy01wcNH1En
4Fwv2iIAzil+gt64mrOUB7XP1iqij2REIiedpwU9lnvU1jljBlti+FxdLCia40O9
gOwnVAp1+RS4NG98VH8/maYlHL23W2LySfYjSrHGH4R0NUeqnDQiAlXwvJaF6CI2
R5od16ECgYEA2Xd/4DTez/t9z3wV4pGd0bjOZJ8TSofkmEunPzm8zwCR8CsOs/5n
90iClP2jV2dbizdApdIp9HTDA0LkPlVSK3l0okp/8+wUYOAHpaZ5fKszHqa//zrA
F9y/3dU2EIV0w0O0WgiotjJE2A9K4NNzjtx5K5CjRhPuz9zBvc7AdG8CgYEAxT1q
l2w1U9AwIzIJtXQa/sUHBXIHsTxjPSd9jV38Nydw3baT6z/RHrE1c8S8VJzKpr+f
2wsyIgHA6s/yT2rvPWkB615pnV+UaDcUO8Eltwu0FyIU1/TBMsXUHIr1/UT7oVpE
KolkLgYypqPoCWvDmXVr3VwuSD88khY/yFLTuzECgYB+mNqQozayzS1IhGwZIbxG
QtekLBcG5GVnY2NRo0MPHr3WmrpMfmX3xvZ91copL7pTKS8xWU+jR/XfCCnnP7Q+
Ks6DS+uBDIYwfzr0bB19PgzcYyaSZpk9Sv1HHsACji6THe74GuJcbpc1UHG+wFod
aKwBeIoUWbZEu7bt0FapcQKBgFtH8x6k64EgZkbDj460bxHdKUSx4zF5GwxgTFCy
YFk+HZPePVKwNB2aMXykXexiq77EDD0ZT1hBq4CAQEnU2Wd4Q3UkOoikhVA9vVVy
K/wspGnYUgEnuom+2E1lWjaeSD4CQm3VK9HI+IP6cxZ5EwrgNs05LgotieCp/1a8
TlThAoGBAIzdBPDOf7pmL/Dpb7BVSZQg2o1tyaZhxA701zgSQYTYFijgirhassQB
zZzQF8a75z/64iuuT90y3b3zG4TBSyBb1mGM6PZOHvr0jgBuxSGOAfZH6ZW7VI7G
NZTERW7XVJRRZK+JlPVszXM5FYY2g4pkJMOtMChPu8r/dq8RcAId
-----END RSA PRIVATE KEY-----
`
func init() {
flag.BoolVar(&help, "help", false, "Show help information")
flag.BoolVar(&help, "h", false, "Show help information (shorthand)")
}
// Item 结构体用于解析 JSON 中的每个条目
type Item struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Assets []struct {
BlobCreated string `json:"blobCreated"`
} `json:"assets"`
}
// NexusConfig 结构体用于解析 Nexus 配置
type NexusConfig struct {
URL string `yaml:"url"`
Username string `yaml:"username"`
Password string `yaml:"password"`
}
// Config 结构体用于解析整个配置文件
type Config struct {
Nexus []NexusConfig `yaml:"nexus"`
}
func main() {
flag.Parse()
if help {
showHelp()
return
}
runClean()
// 读取配置文件
config := readConfig("config/config.yaml")
// 解密密码
for i, nexus := range config.Nexus {
encryptedPassword, err := readEncryptedPassword(nexus.Password)
if err != nil {
fmt.Printf("Error reading encrypted password: %v\n", err)
return
}
privateKey, err := readPrivateKey()
if err != nil {
fmt.Printf("Error reading private key: %v\n", err)
return
}
decryptedPassword, err := decryptRSA(privateKey, encryptedPassword)
if err != nil {
fmt.Printf("Error decrypting password: %v\n", err)
return
}
config.Nexus[i].Password = string(decryptedPassword)
}
// 创建HTTP客户端
client := &http.Client{}
// 遍历每个Nexus配置
for _, nexus := range config.Nexus {
// 创建GET请求
req, err := http.NewRequest("GET", nexus.URL, nil)
if err != nil {
fmt.Println("Error creating request:", err)
return
}
// 添加Basic Auth头部
req.SetBasicAuth(nexus.Username, nexus.Password)
// 发送请求
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error sending request:", err)
return
}
defer resp.Body.Close()
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
// 如果响应体为空,则跳过解析
if len(body) == 0 {
fmt.Println("Response body is empty")
continue
}
// 解析 JSON 数据
var data struct {
Items []Item `json:"items"`
}
if err := json.Unmarshal(body, &data); err != nil {
fmt.Println("Error:", err)
return
}
// 创建 map 以按照 name 进行分类
nameMap := make(map[string][]Item)
// 将数据按照 name 分类存储在 map 中
for _, item := range data.Items {
nameMap[item.Name] = append(nameMap[item.Name], item)
}
// 创建 map 以存储要删除的旧 ID
oldIDs := make(map[string]bool)
// 遍历分类后的数据,按照 blobCreated 排序,并保留除最新的两个外的其他值
for name, items := range nameMap {
// 按照 blobCreated 排序
sort.Slice(items, func(i, j int) bool {
return items[i].Assets[0].BlobCreated < items[j].Assets[0].BlobCreated
})
// 输出除最新的两个外的其他值,并将旧 ID 存储在 map 中
if len(items) > num {
fmt.Printf("Name: %s\n", name)
for _, item := range items[:len(items)-num] {
fmt.Printf("Old ID: %s\n", item.ID)
oldIDs[item.ID] = true
}
}
}
// 删除旧 ID
for id := range oldIDs {
deleteURL := fmt.Sprintf("http://192.168.145.101:8081/service/rest/v1/components/%s", id)
reqDelete, err := http.NewRequest("DELETE", deleteURL, nil)
if err != nil {
fmt.Println("Error creating delete request:", err)
continue
}
reqDelete.SetBasicAuth(nexus.Username, nexus.Password)
respDelete, err := client.Do(reqDelete)
if err != nil {
fmt.Println("Error sending delete request:", err)
continue
}
defer respDelete.Body.Close()
bodyDelete, err := ioutil.ReadAll(respDelete.Body)
fmt.Println("-----------:", string(bodyDelete))
if err != nil {
fmt.Println("Error reading delete response:", err)
continue
}
if respDelete.StatusCode < 400 {
color.Green("Deleted ID: %s, Status: Deleted Successfully, Response: %s\n", id, respDelete.Status)
} else {
color.Red("Deleted ID: %s, Status: Delete Failed, Response: %s\n", id, respDelete.Status)
}
}
}
}
// readConfig 函数用于从配置文件中读取配置信息
func readConfig(filename string) Config {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println("Error reading config file:", err)
return Config{}
}
var config Config
err = yaml.Unmarshal(data, &config)
if err != nil {
fmt.Println("Error unmarshalling config data:", err)
return Config{}
}
return config
}
func decryptRSA(privKey *rsa.PrivateKey, data []byte) ([]byte, error) {
// 使用 RSA 私钥解密数据
return rsa.DecryptPKCS1v15(nil, privKey, data)
}
func readPrivateKey() (*rsa.PrivateKey, error) {
// 解码 PEM 格式的 RSA 私钥
block, _ := pem.Decode([]byte(fileContent))
if block == nil {
return nil, fmt.Errorf("failed to parse PEM block containing the key")
}
// 解析 RSA 私钥
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return key, nil
}
func readEncryptedPassword(zll string) ([]byte, error) {
// 解码 Base64 编码的加密密码
decodedPassword, err := base64.StdEncoding.DecodeString(zll)
if err != nil {
return nil, err
}
return decodedPassword, nil
}
func showHelp() {
fmt.Println("Usage: clean [options]")
fmt.Println("Options:")
fmt.Println(" -h, --help Show help information")
fmt.Println()
fmt.Println("Nexus Configuration Example:")
fmt.Println(nexusExample)
}
func runClean() {
// Your existing code goes here
}
// This is the example Nexus configuration information
var nexusExample = `nexus:
- url: "http://xxxx:8081/service/rest/v1/components?repository=docker"
username: "admin"
password: "encryption password
- url: "http://xxx:8081/service/rest/v1/components?repository=docker2"
username: "admin"
password: "encryption password
`
3、接合nexus的task任务Compact blob store释放磁盘空间