github.com/qiniu/go-sdk/v7@v7.27.0/examples/sandbox_templates/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"os"
     8  	"time"
     9  
    10  	"github.com/qiniu/go-sdk/v7/sandbox"
    11  )
    12  
    13  func main() {
    14  	apiKey := os.Getenv("QINIU_API_KEY")
    15  	if apiKey == "" {
    16  		log.Fatal("请设置 QINIU_API_KEY 环境变量")
    17  	}
    18  
    19  	apiURL := os.Getenv("QINIU_SANDBOX_API_URL")
    20  
    21  	c, err := sandbox.NewClient(&sandbox.Config{
    22  		APIKey:   apiKey,
    23  		Endpoint: apiURL,
    24  	})
    25  	if err != nil {
    26  		log.Fatalf("创建客户端失败: %v", err)
    27  	}
    28  
    29  	ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
    30  	defer cancel()
    31  
    32  	// 1. 列出默认模板
    33  	fmt.Println("=== 列出默认模板 ===")
    34  	defaultTemplates, err := c.ListDefaultTemplates(ctx)
    35  	if err != nil {
    36  		log.Fatalf("列出默认模板失败: %v", err)
    37  	}
    38  	fmt.Printf("共 %d 个默认模板:\n", len(defaultTemplates))
    39  	for _, tmpl := range defaultTemplates {
    40  		fmt.Printf("  - %s (名称: %v, 构建状态: %s)\n",
    41  			tmpl.TemplateID, tmpl.Names, tmpl.BuildStatus)
    42  	}
    43  
    44  	// 2. 列出所有模板
    45  	fmt.Println("\n=== 列出模板 ===")
    46  	templates, err := c.ListTemplates(ctx, nil)
    47  	if err != nil {
    48  		log.Fatalf("列出模板失败: %v", err)
    49  	}
    50  	fmt.Printf("共 %d 个模板:\n", len(templates))
    51  	for _, tmpl := range templates {
    52  		names := "-"
    53  		if len(tmpl.Names) > 0 {
    54  			names = fmt.Sprintf("%v", tmpl.Names)
    55  		}
    56  		aliases := "-"
    57  		if len(tmpl.Aliases) > 0 {
    58  			aliases = fmt.Sprintf("%v", tmpl.Aliases)
    59  		}
    60  		fmt.Printf("  - %s\n", tmpl.TemplateID)
    61  		fmt.Printf("    名称: %s, 旧别名: %s, 公开: %v\n", names, aliases, tmpl.Public)
    62  		fmt.Printf("    CPU: %d 核, 内存: %d MB, 磁盘: %d MB, envd: %s\n",
    63  			tmpl.CPUCount, tmpl.MemoryMB, tmpl.DiskSizeMB, tmpl.EnvdVersion)
    64  		fmt.Printf("    构建状态: %s, 构建次数: %d, 使用次数: %d\n",
    65  			tmpl.BuildStatus, tmpl.BuildCount, tmpl.SpawnCount)
    66  		fmt.Printf("    创建时间: %s, 更新时间: %s\n",
    67  			tmpl.CreatedAt.Format(time.RFC3339), tmpl.UpdatedAt.Format(time.RFC3339))
    68  	}
    69  
    70  	// 3. 获取单个模板详情
    71  	if len(templates) > 0 {
    72  		fmt.Println("\n=== 获取模板详情 ===")
    73  		detail, err := c.GetTemplate(ctx, templates[0].TemplateID, nil)
    74  		if err != nil {
    75  			log.Fatalf("获取模板详情失败: %v", err)
    76  		}
    77  		fmt.Printf("模板: %s, 名称: %v, 当前用户拥有: %v, 构建数: %d\n",
    78  			detail.TemplateID, detail.Names, detail.IsOwner, len(detail.Builds))
    79  		for i, build := range detail.Builds {
    80  			if i >= 3 {
    81  				fmt.Printf("  ... 省略 %d 条\n", len(detail.Builds)-3)
    82  				break
    83  			}
    84  			fmt.Printf("  - %s (状态: %s, CPU: %d, 内存: %d MB)\n",
    85  				build.BuildID, build.Status, build.CPUCount, build.MemoryMB)
    86  		}
    87  	}
    88  
    89  	// 模板创建和构建会消耗云端资源,默认只运行上面的只读示例。
    90  	// 如需继续验证写操作,请显式设置 QINIU_SANDBOX_TEMPLATE_MUTATION_EXAMPLE=true。
    91  	if os.Getenv("QINIU_SANDBOX_TEMPLATE_MUTATION_EXAMPLE") != "true" {
    92  		fmt.Println("\n未启用模板写操作示例,跳过创建、构建和删除流程")
    93  		return
    94  	}
    95  
    96  	// 4. 创建模板
    97  	fmt.Println("\n=== 创建模板 ===")
    98  	cpuCount := int32(2)
    99  	memoryMB := int32(512)
   100  	templateName := "sdk-example-template"
   101  	resp, err := c.CreateTemplate(ctx, sandbox.CreateTemplateParams{
   102  		Name:     &templateName,
   103  		CPUCount: &cpuCount,
   104  		MemoryMB: &memoryMB,
   105  	})
   106  	if err != nil {
   107  		log.Fatalf("创建模板失败: %v", err)
   108  	}
   109  	templateID := resp.TemplateID
   110  	buildID := resp.BuildID
   111  	fmt.Printf("模板已创建: %s (构建: %s)\n", templateID, buildID)
   112  
   113  	// 确保测试结束时清理
   114  	defer func() {
   115  		fmt.Println("\n=== 删除模板 ===")
   116  		if err := c.DeleteTemplate(context.Background(), templateID); err != nil {
   117  			fmt.Printf("删除模板失败: %v\n", err)
   118  		} else {
   119  			fmt.Printf("模板 %s 已删除\n", templateID)
   120  		}
   121  	}()
   122  
   123  	// 5. 更新模板
   124  	fmt.Println("\n=== 更新模板 ===")
   125  	public := true
   126  	if err := c.UpdateTemplate(ctx, templateID, sandbox.UpdateTemplateParams{
   127  		Public: &public,
   128  	}); err != nil {
   129  		log.Fatalf("更新模板失败: %v", err)
   130  	}
   131  	fmt.Println("模板已更新为公开")
   132  
   133  	// 6. 获取构建状态
   134  	fmt.Println("\n=== 获取构建状态 ===")
   135  	buildInfo, err := c.GetTemplateBuildStatus(ctx, templateID, buildID, nil)
   136  	if err != nil {
   137  		fmt.Printf("获取构建状态失败: %v\n", err)
   138  	} else {
   139  		fmt.Printf("构建 %s: 状态=%s, 模板=%s\n", buildInfo.BuildID, buildInfo.Status, buildInfo.TemplateID)
   140  	}
   141  
   142  	// 7. 获取构建日志
   143  	fmt.Println("\n=== 获取构建日志 ===")
   144  	buildLogs, err := c.GetTemplateBuildLogs(ctx, templateID, buildID, nil)
   145  	if err != nil {
   146  		fmt.Printf("获取构建日志失败: %v\n", err)
   147  	} else {
   148  		fmt.Printf("构建日志 (%d 条):\n", len(buildLogs.Logs))
   149  		for i, entry := range buildLogs.Logs {
   150  			if i >= 5 {
   151  				fmt.Printf("  ... 省略 %d 条\n", len(buildLogs.Logs)-5)
   152  				break
   153  			}
   154  			step := "-"
   155  			if entry.Step != nil {
   156  				step = *entry.Step
   157  			}
   158  			fmt.Printf("  [%s] [%s] %s: %s\n",
   159  				entry.Timestamp.Format(time.RFC3339), entry.Level, step, entry.Message)
   160  		}
   161  	}
   162  
   163  	// 8. 分配模板标签(AssignTemplateTags)
   164  	fmt.Println("\n=== 分配模板标签 ===")
   165  	tagResult, err := c.AssignTemplateTags(ctx, sandbox.ManageTagsParams{
   166  		Target: fmt.Sprintf("%s:%s", templateName, "v1"),
   167  		Tags:   []string{"latest", "stable"},
   168  	})
   169  	if err != nil {
   170  		fmt.Printf("管理模板标签失败: %v\n", err)
   171  	} else {
   172  		fmt.Printf("标签已分配, 构建: %s, 标签: %v\n", tagResult.BuildID, tagResult.Tags)
   173  	}
   174  
   175  	// 9. 删除模板标签(DeleteTemplateTags)
   176  	fmt.Println("\n=== 删除模板标签 ===")
   177  	if err := c.DeleteTemplateTags(ctx, sandbox.DeleteTagsParams{
   178  		Name: templateName,
   179  		Tags: []string{"stable"},
   180  	}); err != nil {
   181  		fmt.Printf("删除模板标签失败: %v\n", err)
   182  	} else {
   183  		fmt.Println("标签 'stable' 已删除")
   184  	}
   185  
   186  	// 10. 通过别名查找模板(GetTemplateByAlias)
   187  	fmt.Println("\n=== 通过别名查找模板 ===")
   188  	if len(templates) > 0 && len(templates[0].Aliases) > 0 {
   189  		alias := templates[0].Aliases[0]
   190  		aliasResp, err := c.GetTemplateByAlias(ctx, alias)
   191  		if err != nil {
   192  			fmt.Printf("通过别名查找模板失败: %v\n", err)
   193  		} else {
   194  			fmt.Printf("别名 '%s' -> 模板: %s (公开: %v)\n", alias, aliasResp.TemplateID, aliasResp.Public)
   195  		}
   196  	} else {
   197  		fmt.Println("没有可用的模板别名,跳过")
   198  	}
   199  
   200  	// 11. 获取模板文件上传链接(GetTemplateFiles)
   201  	fmt.Println("\n=== 获取模板文件上传链接 ===")
   202  	fileUpload, err := c.GetTemplateFiles(ctx, templateID, "example-hash-value")
   203  	if err != nil {
   204  		fmt.Printf("获取文件上传链接失败: %v\n", err)
   205  	} else {
   206  		fmt.Printf("文件是否已存在: %v, 已获得上传地址: %v\n", fileUpload.Present, fileUpload.URL != nil)
   207  	}
   208  
   209  	// 12. 启动模板构建(StartTemplateBuild)
   210  	fmt.Println("\n=== 启动模板构建 ===")
   211  	fromImage := "ubuntu:latest"
   212  	if err := c.StartTemplateBuild(ctx, templateID, buildID, sandbox.StartTemplateBuildParams{
   213  		FromImage: &fromImage,
   214  	}); err != nil {
   215  		fmt.Printf("启动构建失败(可能已在构建中): %v\n", err)
   216  	} else {
   217  		fmt.Println("构建已启动")
   218  	}
   219  
   220  	// 13. 等待构建完成(WaitForBuild)
   221  	fmt.Println("\n=== 等待构建完成 ===")
   222  	finalBuild, err := c.WaitForBuild(ctx, templateID, buildID, sandbox.WithPollInterval(3*time.Second))
   223  	if err != nil {
   224  		fmt.Printf("等待构建完成失败: %v\n", err)
   225  	} else {
   226  		fmt.Printf("构建已完成: %s (状态: %s)\n", finalBuild.BuildID, finalBuild.Status)
   227  	}
   228  
   229  	// 14. 删除模板(通过 defer 执行)
   230  }