forked from ccfos/huatuo
208 lines
5.5 KiB
Go
208 lines
5.5 KiB
Go
// Copyright 2025 The HuaTuo Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package pod
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
"syscall"
|
|
"time"
|
|
|
|
"huatuo-bamai/internal/log"
|
|
)
|
|
|
|
var (
|
|
// all containers, map: ContainerID -> *Container
|
|
containers = map[string]*Container{}
|
|
|
|
// updated
|
|
lastUpdatedAt = time.Now()
|
|
updatedStep = 5 * time.Second
|
|
updatedLock sync.Mutex
|
|
)
|
|
|
|
// Container object
|
|
type Container struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Hostname string `json:"hostname"`
|
|
Type ContainerType `json:"type"`
|
|
Qos ContainerQos `json:"qos"`
|
|
IPAddress string `json:"ip_address"`
|
|
NetNamespaceInode uint64 `json:"net_namespace_inode"`
|
|
InitPid int `json:"init_pid"` // the pid-1 of container
|
|
CgroupSuffix string `json:"cgroup_suffix"`
|
|
CSS map[string]uint64 `json:"css"` // map: Name -> Address
|
|
StartedAt time.Time `json:"started_at"` // started time
|
|
SyncedAt time.Time `json:"synced_at"` // synced time
|
|
lifeResouces map[string]any
|
|
Labels map[string]any `json:"labels"` // custom labels
|
|
}
|
|
|
|
func (c *Container) String() string {
|
|
return fmt.Sprintf("%s:%s/%s/%s:%s/%s", c.ID, c.Hostname, c.Name, c.Type, c.Qos, c.IPAddress)
|
|
}
|
|
|
|
// LifeResouces returns the life resouces of container.
|
|
func (c *Container) LifeResouces(key string) any {
|
|
return c.lifeResouces[key]
|
|
}
|
|
|
|
// LabelHostNamespace returns namespace label
|
|
func (c *Container) LabelHostNamespace() string {
|
|
return c.Labels[labelHostNamespace].(string)
|
|
}
|
|
|
|
// getContainers returns the containers by type and level.
|
|
func getContainers(typeMask ContainerType, minLevel ContainerQos) (map[string]*Container, error) {
|
|
updatedLock.Lock()
|
|
defer updatedLock.Unlock()
|
|
|
|
res := make(map[string]*Container)
|
|
|
|
if time.Since(lastUpdatedAt) > updatedStep {
|
|
if err := kubeletSyncContainers(); err != nil {
|
|
if errors.Is(err, syscall.ECONNREFUSED) { // ignore error of no connections
|
|
log.Debugf("failed to sync containers by ECONNREFUSED, err: %v", err)
|
|
return res, nil
|
|
}
|
|
return res, err
|
|
}
|
|
lastUpdatedAt = time.Now()
|
|
}
|
|
|
|
log.Debugf("sync latest containers: %+v", containers)
|
|
for _, c := range containers {
|
|
// check Type
|
|
if c.Type&typeMask == 0 {
|
|
continue
|
|
}
|
|
|
|
// check Level
|
|
if c.Qos < minLevel {
|
|
continue
|
|
}
|
|
|
|
res[c.ID] = c
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
// GetContainersByType returns the containers by type.
|
|
func GetContainersByType(typeMask ContainerType) (map[string]*Container, error) {
|
|
return getContainers(typeMask, ContainerQosLevelMin)
|
|
}
|
|
|
|
// GetNormalContainers returns the normal containers.
|
|
func GetNormalContainers() (map[string]*Container, error) {
|
|
return GetContainersByType(ContainerTypeNormal)
|
|
}
|
|
|
|
// GetNormalAndSidecarContainers returns the normal and sidecar containers.
|
|
func GetNormalAndSidecarContainers() (map[string]*Container, error) {
|
|
return GetContainersByType(ContainerTypeNormal | ContainerTypeSidecar)
|
|
}
|
|
|
|
// GetAllContainers returns all containers.
|
|
func GetAllContainers() (map[string]*Container, error) {
|
|
return getContainers(ContainerTypeAll, ContainerQosLevelMin)
|
|
}
|
|
|
|
// GetContainerByID returns the special container by id.
|
|
func GetContainerByID(id string) (*Container, error) {
|
|
all, err := GetAllContainers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if c, ok := all[id]; ok {
|
|
return c, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// GetContainerByIPAddress returns the special container by the container ip address.
|
|
func GetContainerByIPAddress(ip string) (*Container, error) {
|
|
// only for normal
|
|
all, err := GetNormalContainers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, c := range all {
|
|
if c.IPAddress == ip {
|
|
return c, nil
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// GetContainerByNetNamespaceInode returns the special container by the net namespace inode.
|
|
func GetContainerByNetNamespaceInode(inode uint64) (*Container, error) {
|
|
// only for normal
|
|
all, err := GetNormalContainers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, c := range all {
|
|
if c.NetNamespaceInode == inode {
|
|
return c, nil
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// GetContainerByCSS returns the special container by the css address.
|
|
func GetContainerByCSS(css uint64, subsys string) (*Container, error) {
|
|
all, err := GetAllContainers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, c := range all {
|
|
if addr, ok := c.CSS[subsys]; ok {
|
|
if addr == css {
|
|
return c, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// GetCSSToContainerID Build mapping from css address to container id
|
|
// Usage: return_val = GetCSSToContainerID('cpu')
|
|
//
|
|
// container_id = return_val[0xffffffffc0601000]
|
|
func GetCSSToContainerID(subsys string) (map[uint64]string, error) {
|
|
containers, err := GetAllContainers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cssToContainerMap := make(map[uint64]string)
|
|
for _, container := range containers {
|
|
if addr, ok := container.CSS[subsys]; ok {
|
|
cssToContainerMap[addr] = container.ID
|
|
}
|
|
}
|
|
|
|
return cssToContainerMap, nil
|
|
}
|