什么是apimachinery

“Package apimachinery contains the generic API machinery code that is common to both server and clients.” apimachinery是对API包及版本管理的一个抽象,主要包含registered和announced两个package:

  • registered: 定义有DefaultAPIRegistrationManager,管理API包及版本;
  • announced:包含group_factory和announced两部分,其中group_factory提供了向DefaultAPIRegistrationManager注册的途径;announced部分是还在开发中的接口,用来接管registered包的部分功能。

关于apimachinery的分析,先介绍apimachinery/registered.go中的APIRegistrationManager,再介绍apimachinery/announced/group_factory.go中的groupMetaFactory。

本次将分析APIRegistrationManager。在介绍之前,先来认识下GroupMeta。

GroupMeta

GroupMetal结构体定义了Group的基本信息,如Group对应的RESTMapper, Codec, GroupVersions等,定义在/pkg/apimachinery/types.go中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// GroupMeta stores the metadata of a group.
type GroupMeta struct {
// GroupVersion represents the preferred version of the group.
GroupVersion unversioned.GroupVersion
// GroupVersions is Group + all versions in that group.
GroupVersions []unversioned.GroupVersion
// Codec is the default codec for serializing output that should use
// the preferred version. Use this Codec when writing to
// disk, a data store that is not dynamically versioned, or in tests.
// This codec can decode any object that the schema is aware of.
Codec runtime.Codec
// SelfLinker can set or get the SelfLink field of all API types.
// TODO: when versioning changes, make this part of each API definition.
// TODO(lavalamp): Combine SelfLinker & ResourceVersioner interfaces, force all uses
// to go through the InterfacesFor method below.
SelfLinker runtime.SelfLinker
// RESTMapper provides the default mapping between REST paths and the objects declared in api.Scheme and all known
// versions.
RESTMapper meta.RESTMapper
// InterfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
// TODO: make this stop being a func pointer and always use the default
// function provided below once every place that populates this field has been changed.
InterfacesFor func(version unversioned.GroupVersion) (*meta.VersionInterfaces, error)
// InterfacesByVersion stores the per-version interfaces.
InterfacesByVersion map[unversioned.GroupVersion]*meta.VersionInterfaces
}

APIRegistrationManager

APIRegistrationManager主要用来管理GroupMeta,定义在/pgk/apimachinery/registered/registered.go中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type APIRegistrationManager struct {
// registeredGroupVersions stores all API group versions for which RegisterGroup is called.
//***所有的group version***//
registeredVersions map[unversioned.GroupVersion]struct{}
// thirdPartyGroupVersions are API versions which are dynamically
// registered (and unregistered) via API calls to the apiserver
//***第三方的group version***//
thirdPartyGroupVersions []unversioned.GroupVersion
// enabledVersions represents all enabled API versions. It should be a
// subset of registeredVersions. Please call EnableVersions() to add
// enabled versions.
enabledVersions map[unversioned.GroupVersion]struct{}
// map of group meta for all groups.
//***groupmeta***//
groupMetaMap map[string]*apimachinery.GroupMeta
// envRequestedVersions represents the versions requested via the
// KUBE_API_VERSIONS environment variable. The install package of each group
// checks this list before add their versions to the latest package and
// Scheme. This list is small and order matters, so represent as a slice
envRequestedVersions []unversioned.GroupVersion
}

其中:

  • registeredGroupVersions存储已经注册的GV,可以使用RegisterVersions()进行注册;
  • thirdPartyGroupVersions存储第三方的API,可以使用AddThirdPartyAPIGroupVersions()进行注册;
  • enabledVersions存储处理enabled的GV,可以通过EnableVersions()添加;
  • groupMetaMap存储Group的GroupMeta信息;
  • envRequestedVersions存储KUBE_API_VERSIONS环境变量包含的版本,如果未指定,则KUBE_API_VERSIONS为空。

关于APIRegistrationManager和announced包中的APIGroupFactoryRegistry的关系,在announced.go中有注释”(Right now APIRegistrationManager has separate ‘registration’ and ‘enabled’ concepts– APIGroupFactory is going to take over the former function; they will overlap untill the refactoring is finished.)”。所以APIGroupFactoryRegistry还在开发中,估计在以后的版本会完善,并接管APIRegistrationManager对GroupMeta的管理功能。

下面来分析APIRegistrationManager结构体提供的方法。

NewOrDie()

NewOrDie()方法可以创建APIRegistrationManager,在registered.go中有DefaultAPIRegistrationManager = NewOrDie(os.Getenv("KUBE_API_VERSIONS"))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//***新建APIRegistrationManager***//
func NewOrDie(kubeAPIVersions string) *APIRegistrationManager {
m, err := NewAPIRegistrationManager(kubeAPIVersions)
if err != nil {
glog.Fatalf("Could not construct version manager: %v (KUBE_API_VERSIONS=%q)", err, kubeAPIVersions)
}
return m
}
// NewAPIRegistrationManager constructs a new manager. The argument ought to be
// the value of the KUBE_API_VERSIONS env var, or a value of this which you
// wish to test.
func NewAPIRegistrationManager(kubeAPIVersions string) (*APIRegistrationManager, error) {
m := &APIRegistrationManager{
registeredVersions: map[unversioned.GroupVersion]struct{}{},
thirdPartyGroupVersions: []unversioned.GroupVersion{},
enabledVersions: map[unversioned.GroupVersion]struct{}{},
groupMetaMap: map[string]*apimachinery.GroupMeta{},
envRequestedVersions: []unversioned.GroupVersion{},
}
if len(kubeAPIVersions) != 0 {
for _, version := range strings.Split(kubeAPIVersions, ",") {
gv, err := unversioned.ParseGroupVersion(version)
if err != nil {
return nil, fmt.Errorf("invalid api version: %s in KUBE_API_VERSIONS: %s.",
version, kubeAPIVersions)
}
m.envRequestedVersions = append(m.envRequestedVersions, gv)
}
}
return m, nil
}

RegisterVersions()

RegisterVersions()可以向APIRegistrationManager注册GroupVersion,即把GroupVerson作为key加入到registeredVersions map中。

1
2
3
4
5
6
//***注册groupversion***//
func (m *APIRegistrationManager) RegisterVersions(availableVersions []unversioned.GroupVersion) {
for _, v := range availableVersions {
m.registeredVersions[v] = struct{}{}
}
}

RegisterGroup()

RegisterGroup()可以向APIRegistrationManager注册groupMeta,即把存入groupMetaMap中。

1
2
3
4
5
6
7
8
9
//***注册group,即把groupMeta注册到groupMetaMap字段***//
func (m *APIRegistrationManager) RegisterGroup(groupMeta apimachinery.GroupMeta) error {
groupName := groupMeta.GroupVersion.Group
if _, found := m.groupMetaMap[groupName]; found {
return fmt.Errorf("group %v is already registered", m.groupMetaMap)
}
m.groupMetaMap[groupName] = &groupMeta
return nil
}

EnableVersions()

EnableVersions()可以把已经注册的GroupVersion置为enabled。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//***若该groupversion在registeredVersions中存在,则放入enabledVersions map***//
func (m *APIRegistrationManager) EnableVersions(versions ...unversioned.GroupVersion) error {
var unregisteredVersions []unversioned.GroupVersion
for _, v := range versions {
if _, found := m.registeredVersions[v]; !found {
unregisteredVersions = append(unregisteredVersions, v)
}
m.enabledVersions[v] = struct{}{}
}
if len(unregisteredVersions) != 0 {
return fmt.Errorf("Please register versions before enabling them: %v", unregisteredVersions)
}
return nil
}

IsAllowedVersion()

IsAllowedVersion()用来判断GroupVersion是否在KUBE_API_VERSIONS环境变量的定义中,如果KUBE_API_VERSIONS为空,则允许所有的GroupVersion。

1
2
3
4
5
6
7
8
9
10
11
12
//***是否是envRequestedVesions要求***//
func (m *APIRegistrationManager) IsAllowedVersion(v unversioned.GroupVersion) bool {
if len(m.envRequestedVersions) == 0 {
return true
}
for _, envGV := range m.envRequestedVersions {
if v == envGV {
return true
}
}
return false
}

IsEnabledVersion()

IsEnabledVersion()用来判断GroupVersion是否为被标记为enabled。

1
2
3
4
5
//***判断该groupversion是否在enabledVersions变量中***//
func (m *APIRegistrationManager) IsEnabledVersion(v unversioned.GroupVersion) bool {
_, found := m.enabledVersions[v]
return found
}

EnabledVersions()

返回所有enabled的GroupVersion。

1
2
3
4
5
6
7
8
9
10
11
func (m *APIRegistrationManager) EnabledVersions() []unversioned.GroupVersion {
ret := []unversioned.GroupVersion{}
for _, groupMeta := range m.groupMetaMap {
for _, version := range groupMeta.GroupVersions {
if m.IsEnabledVersion(version) {
ret = append(ret, version)
}
}
}
return ret
}

EnabledVersionsForGroup()

返回某一个group下的enabled的GroupVersion。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func (m *APIRegistrationManager) EnabledVersionsForGroup(group string) []unversioned.GroupVersion {
groupMeta, ok := m.groupMetaMap[group]
if !ok {
return []unversioned.GroupVersion{}
}
ret := []unversioned.GroupVersion{}
for _, version := range groupMeta.GroupVersions {
if m.IsEnabledVersion(version) {
ret = append(ret, version)
}
}
return ret
}

Group()

获取某一group的groupMeta。

1
2
3
4
5
6
7
8
func (m *APIRegistrationManager) Group(group string) (*apimachinery.GroupMeta, error) {
groupMeta, found := m.groupMetaMap[group]
if !found {
return nil, fmt.Errorf("group %v has not been registered", group)
}
groupMetaCopy := *groupMeta
return &groupMetaCopy, nil
}

IsRegistered()

IsRegistered()可以查看某一group是否已经注册。

1
2
3
4
func (m *APIRegistrationManager) IsRegistered(group string) bool {
_, found := m.groupMetaMap[group]
return found
}

IsRegisteredVersion()

IsRegisteredVersion()可以查看某一GroupVersion是否已经注册。

1
2
3
4
func (m *APIRegistrationManager) IsRegisteredVersion(v unversioned.GroupVersion) bool {
_, found := m.registeredVersions[v]
return found
}

RegisteredGroupVersions()

返回所有GroupVersions。

1
2
3
4
5
6
7
func (m *APIRegistrationManager) RegisteredGroupVersions() []unversioned.GroupVersion {
ret := []unversioned.GroupVersion{}
for groupVersion := range m.registeredVersions {
ret = append(ret, groupVersion)
}
return ret
}

IsThirdPartyAPIGroupVersion()

判断是否是第三方的GroupVersion。

1
2
3
4
5
6
7
8
func (m *APIRegistrationManager) IsThirdPartyAPIGroupVersion(gv unversioned.GroupVersion) bool {
for ix := range m.thirdPartyGroupVersions {
if m.thirdPartyGroupVersions[ix] == gv {
return true
}
}
return false
}

AddThirdPartyAPIGroupVersions()

AddThirdPartyAPIGroupVersions()可以向APIRegistrationManager注册第三方的GroupVersion:先调用RegistrerVersions(),再调用EnableVersions,加入到thirdPartyGroupVersions字段中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//***注册第三方groupversion***//
func (m *APIRegistrationManager) AddThirdPartyAPIGroupVersions(gvs ...unversioned.GroupVersion) []unversioned.GroupVersion {
filteredGVs := []unversioned.GroupVersion{}
skippedGVs := []unversioned.GroupVersion{}
for ix := range gvs {
if !m.IsRegisteredVersion(gvs[ix]) {
filteredGVs = append(filteredGVs, gvs[ix])
} else {
glog.V(3).Infof("Skipping %s, because its already registered", gvs[ix].String())
skippedGVs = append(skippedGVs, gvs[ix])
}
}
if len(filteredGVs) == 0 {
return skippedGVs
}
m.RegisterVersions(filteredGVs)
m.EnableVersions(filteredGVs...)
m.thirdPartyGroupVersions = append(m.thirdPartyGroupVersions, filteredGVs...)
return skippedGVs
}

InterfacesFor()

InterfacesFor()方法先获取GV对应的groupMeta,然后通过groupMeta获取

1
2
3
4
5
6
7
8
// InterfacesFor is a union meta.VersionInterfacesFunc func for all registered types
func (m *APIRegistrationManager) InterfacesFor(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) {
groupMeta, err := m.Group(version.Group)
if err != nil {
return nil, err
}
return groupMeta.InterfacesFor(version)
}

GroupOrDie()

获取group对应的GroupMeta。

1
2
3
4
5
6
7
8
9
10
11
12
func (m *APIRegistrationManager) GroupOrDie(group string) *apimachinery.GroupMeta {
groupMeta, found := m.groupMetaMap[group]
if !found {
if group == "" {
panic("The legacy v1 API is not registered.")
} else {
panic(fmt.Sprintf("Group %s is not registered.", group))
}
}
groupMetaCopy := *groupMeta
return &groupMetaCopy
}

RESTMapper()

收集GroupMeta中的RESTMapper,组成MultiRESTMapper,然后再封装成PriorityRESTMapper返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// RESTMapper returns a union RESTMapper of all known types with priorities chosen in the following order:
// 1. if KUBE_API_VERSIONS is specified, then KUBE_API_VERSIONS in order, OR
// 1. legacy kube group preferred version, extensions preferred version, metrics perferred version, legacy
// kube any version, extensions any version, metrics any version, all other groups alphabetical preferred version,
// all other groups alphabetical.
func (m *APIRegistrationManager) RESTMapper(versionPatterns ...unversioned.GroupVersion) meta.RESTMapper {
unionMapper := meta.MultiRESTMapper{}
unionedGroups := sets.NewString()
for enabledVersion := range m.enabledVersions {
if !unionedGroups.Has(enabledVersion.Group) {
unionedGroups.Insert(enabledVersion.Group)
groupMeta := m.groupMetaMap[enabledVersion.Group]
unionMapper = append(unionMapper, groupMeta.RESTMapper)
}
}
//***如果versionPatterns不为空,则使用versionPatterns作为优先级依据***//
if len(versionPatterns) != 0 {
resourcePriority := []unversioned.GroupVersionResource{}
kindPriority := []unversioned.GroupVersionKind{}
for _, versionPriority := range versionPatterns {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
//***如果envRequestedVersions不为空,则使用envRequestedVersions作为优先级依据***//
if len(m.envRequestedVersions) != 0 {
resourcePriority := []unversioned.GroupVersionResource{}
kindPriority := []unversioned.GroupVersionKind{}
for _, versionPriority := range m.envRequestedVersions {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
//***使用默认的优先级***//
prioritizedGroups := []string{"", "extensions", "metrics"}
resourcePriority, kindPriority := m.prioritiesForGroups(prioritizedGroups...)
prioritizedGroupsSet := sets.NewString(prioritizedGroups...)
remainingGroups := sets.String{}
for enabledVersion := range m.enabledVersions {
if !prioritizedGroupsSet.Has(enabledVersion.Group) {
remainingGroups.Insert(enabledVersion.Group)
}
}
remainingResourcePriority, remainingKindPriority := m.prioritiesForGroups(remainingGroups.List()...)
resourcePriority = append(resourcePriority, remainingResourcePriority...)
kindPriority = append(kindPriority, remainingKindPriority...)
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}