helm源码分析-list命令
| 阅读 | 共 1720 字,阅读约
Overview
helm源码分析-list命令
- helm list 主要用于查看已经安装的release列表
- 源码位置:cmd/helm/list.go
实现逻辑
helm list 的代码比较简单,没有复杂的处理逻辑,核心逻辑都委托给action模块实现了。核心其实就包括两步:
-
构造action的客户端
-
调用action的Run方法得到Release列表
1
client := action.NewList(cfg) client.Run()
1
2- action实现列表查询的逻辑与底层的存储驱动有关
3
4- 默认的secret存储驱动实现:`查询所有含有owner=helm这个label的secret`
5- configmap存储驱动实现:`查询所有含有owner=helm这个label的configmap`
6- memory存储驱动实现:`查询Memory对象中存储的数据`
7- sql存储驱动实现:`查询releases_v1表中的记录`
8
9## 源码分析
10
11### 代码入口
12
13```go
14func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
15// 内部调用调用pkg/action/list.go模块
16// 先构造action的客户端
17 client := action.NewList(cfg)
18 var outfmt output.Format
19
20 cmd := &cobra.Command{
21 Use: "list",
22 Short: "list releases",
23 Long: listHelp,
24 // 可以使用 helm ls 命令
25 Aliases: []string{"ls"},
26 Args: require.NoArgs,
27 ValidArgsFunction: noCompletions,
28 RunE: func(cmd *cobra.Command, args []string) error {
29 ...
30 // 调用action模块的 Run 函数
31 // 返回的结果是 Release 列表
32 results, err := client.Run()
33 ...
34 // 后面都是结果的处理
35 },
36 }
37
38// 下面是入参的处理
39 f := cmd.Flags()
40 ...
41}
action.Run函数
1func (l *List) Run() ([]*release.Release, error) {
2 ...
3 // 调用List方法获取所有的Release
4 results, err := l.cfg.Releases.List(func(rel *release.Release) bool {
5 // 跳过不满足过滤条件的结果
6 if filter != nil && !filter.MatchString(rel.Name) {
7 return false
8 }
9 return true
10 })
11 ...
12
13 // 过滤掉不满足状态条件的结果
14 results = l.filterStateMask(results)
15
16 // 过滤掉不满足label条件的结果
17 selectorObj, err := labels.Parse(l.Selector)
18 if err != nil {
19 return nil, err
20 }
21 results = l.filterSelector(results, selectorObj)
22
23 // 对结果排序
24 l.sort(results)
25 ...
26 return results, err
27}
Releases.List函数
这个是个接口,具体的实现跟配置的存储驱动有关,存储驱动包括:
- secret
- configmap
- sql(只支持postgresql)
- memory
secret存储驱动代码分析
- 根据owner=helm标签来选择secret
源码位置:pkg/storage/driver/secret.go
1func (secrets *Secrets) sList(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
2 // 构造Label选择器,选择owner=helm的label
3 lsel := kblabels.Set{"owner": "helm"}.AsSelector()
4 opts := metav1.ListOptions{LabelSelector: lsel.String()}
5
6 // 调用k8s的原生api,获取所有owner=helm的secret
7 list, err := secrets.impl.List(context.Background(), opts)
8 ...
9 // 结果处理
10 for _, item := range list.Items {
11 // 获取每个secret中的数据,转换为Release对象
12 rls, err := decodeRelease(string(item.Data["release"]))
13 ...
14 }
15 return results, nil
16}
configmap存储驱动代码分析
- 根据owner=helm标签来选择configmap
源码位置:pkg/storage/driver/cfgmaps.go
1func (cfgmaps *ConfigMaps) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
2 // 构造Label选择器,选择owner=helm的label
3 lsel := kblabels.Set{"owner": "helm"}.AsSelector()
4 opts := metav1.ListOptions{LabelSelector: lsel.String()}
5
6 // 调用k8s的原生api,获取所有owner=helm的configmap
7 list, err := cfgmaps.impl.List(context.Background(), opts)
8 ...
9 for _, item := range list.Items {
10 // 获取每个configmap中的数据,转换为Release对象
11 rls, err := decodeRelease(item.Data["release"])
12 ...
13 }
14 return results, nil
15}
memory存储驱动代码实现分析
- 查询Memory这个数据结构
源码位置:pkg/storage/driver/memory.go
1func (mem *Memory) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
2 ...
3 for namespace := range mem.cache {
4 if mem.namespace != "" {
5 // Should only list releases of this namespace
6 namespace = mem.namespace
7 }
8 // 查询 Memory 中的cache信息
9 for _, recs := range mem.cache[namespace] {
10 recs.Iter(func(_ int, rec *record) bool {
11 if filter(rec.rls) {
12 ls = append(ls, rec.rls)
13 }
14 return true
15 })
16 }
17 if mem.namespace != "" {
18 // Should only list releases of this namespace
19 break
20 }
21 }
22 return ls, nil
23}
24
25// 内存作为存储驱动的数据主要存放在Memory这个对象中
26type Memory struct {
27 sync.RWMutex
28 namespace string
29 // 以命名空间为key的 Release 集合
30 cache map[string]memReleases
31}
sql存储驱动代码实现分析
- 通过查询 releases_v1 表得到release列表
源码位置:pkg/storage/driver/sql.go
1func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
2 // 拼接sql查询语句
3 // select body from releases_v1 where owner = helm
4 // 如果指定了命名空间,再追加where条件:and namespace = {ns}
5 sb := s.statementBuilder.
6 Select(sqlReleaseTableBodyColumn).
7 From(sqlReleaseTableName).
8 Where(sq.Eq{sqlReleaseTableOwnerColumn: sqlReleaseDefaultOwner})
9
10 // If a namespace was specified, we only list releases from that namespace
11 if s.namespace != "" {
12 sb = sb.Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace})
13 }
14
15 query, args, err := sb.ToSql()
16 if err != nil {
17 s.Log("failed to build query: %v", err)
18 return nil, err
19 }
20
21 var records = []SQLReleaseWrapper{}
22 if err := s.db.Select(&records, query, args...); err != nil {
23 s.Log("list: failed to list: %v", err)
24 return nil, err
25 }
26
27 var releases []*rspb.Release
28 for _, record := range records {
29 // 将查询结果转换为 Release 对象
30 release, err := decodeRelease(record.Body)
31 if err != nil {
32 s.Log("list: failed to decode release: %v: %v", record, err)
33 continue
34 }
35 if filter(release) {
36 releases = append(releases, release)
37 }
38 }
39
40 return releases, nil
41}