Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
-- Copyright (c) 2026 Tencent Inc.
-- SPDX-License-Identifier: Apache-2.0
--
-- Component warehouse: CubeOps-owned inventory of versioned component trees
-- extracted from one-click packages. Coverage uses t_component_node_install,
-- not the live heartbeat matrix.

-- +goose NO TRANSACTION
-- +goose Up

CALL cubemaster_acquire_migration_lock('cubemaster_migration_20260813120000_warehouse', 60);

CREATE TABLE IF NOT EXISTS `t_component_warehouse` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`arch` varchar(16) NOT NULL,
`component` varchar(64) NOT NULL,
`version` varchar(128) NOT NULL,
`source` varchar(32) NOT NULL DEFAULT '',
`source_ref` varchar(256) NOT NULL DEFAULT '',
`rel_path` varchar(512) NOT NULL DEFAULT '',
`size_bytes` bigint NOT NULL DEFAULT 0,
`checksum` varchar(128) NOT NULL DEFAULT '',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_wh_arch_comp_ver` (`arch`, `component`, `version`),
KEY `idx_wh_component` (`component`, `version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE IF NOT EXISTS `t_component_import_job` (
`id` varchar(36) NOT NULL,
`source` varchar(32) NOT NULL,
`source_ref` varchar(256) NOT NULL DEFAULT '',
`tag` varchar(128) NOT NULL DEFAULT '',
`arch` varchar(16) NOT NULL DEFAULT '',
`status` varchar(32) NOT NULL DEFAULT 'pending',
`error` text,
`bytes_total` bigint NOT NULL DEFAULT 0,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_import_status` (`status`, `created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE IF NOT EXISTS `t_component_preinstall_job` (
`id` varchar(36) NOT NULL,
`node_id` varchar(128) NOT NULL,
`arch` varchar(16) NOT NULL,
`component` varchar(64) NOT NULL,
`version` varchar(128) NOT NULL,
`status` varchar(32) NOT NULL DEFAULT 'pending',
`error` text,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_preinstall_node_status` (`node_id`, `status`),
KEY `idx_preinstall_comp` (`arch`, `component`, `version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE IF NOT EXISTS `t_component_node_install` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`node_id` varchar(128) NOT NULL,
`arch` varchar(16) NOT NULL,
`component` varchar(64) NOT NULL,
`version` varchar(128) NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_node_install` (`node_id`, `arch`, `component`, `version`),
KEY `idx_node_install_node` (`node_id`),
KEY `idx_node_install_comp` (`arch`, `component`, `version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

SELECT RELEASE_LOCK('cubemaster_migration_20260813120000_warehouse');

-- +goose Down

CALL cubemaster_acquire_migration_lock('cubemaster_migration_20260813120000_warehouse', 60);

DROP TABLE IF EXISTS `t_component_node_install`;
DROP TABLE IF EXISTS `t_component_preinstall_job`;
DROP TABLE IF EXISTS `t_component_import_job`;
DROP TABLE IF EXISTS `t_component_warehouse`;

SELECT RELEASE_LOCK('cubemaster_migration_20260813120000_warehouse');
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
-- Copyright (c) 2026 Tencent Inc.
-- SPDX-License-Identifier: Apache-2.0
--
-- Component warehouse (PostgreSQL).

-- +goose NO TRANSACTION
-- +goose Up

SELECT cubemaster_acquire_migration_lock('cubemaster_migration_20260813120000_warehouse', 60);

CREATE TABLE IF NOT EXISTS t_component_warehouse (
id bigserial NOT NULL,
arch varchar(16) NOT NULL,
component varchar(64) NOT NULL,
version varchar(128) NOT NULL,
source varchar(32) NOT NULL DEFAULT '',
source_ref varchar(256) NOT NULL DEFAULT '',
rel_path varchar(512) NOT NULL DEFAULT '',
size_bytes bigint NOT NULL DEFAULT 0,
checksum varchar(128) NOT NULL DEFAULT '',
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
CONSTRAINT uk_wh_arch_comp_ver UNIQUE (arch, component, version)
);
CREATE INDEX IF NOT EXISTS idx_wh_component ON t_component_warehouse (component, version);

CREATE TABLE IF NOT EXISTS t_component_import_job (
id varchar(36) NOT NULL,
source varchar(32) NOT NULL,
source_ref varchar(256) NOT NULL DEFAULT '',
tag varchar(128) NOT NULL DEFAULT '',
arch varchar(16) NOT NULL DEFAULT '',
status varchar(32) NOT NULL DEFAULT 'pending',
error text,
bytes_total bigint NOT NULL DEFAULT 0,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX IF NOT EXISTS idx_import_status ON t_component_import_job (status, created_at);

CREATE TABLE IF NOT EXISTS t_component_preinstall_job (
id varchar(36) NOT NULL,
node_id varchar(128) NOT NULL,
arch varchar(16) NOT NULL,
component varchar(64) NOT NULL,
version varchar(128) NOT NULL,
status varchar(32) NOT NULL DEFAULT 'pending',
error text,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX IF NOT EXISTS idx_preinstall_node_status ON t_component_preinstall_job (node_id, status);
CREATE INDEX IF NOT EXISTS idx_preinstall_comp ON t_component_preinstall_job (arch, component, version);

CREATE TABLE IF NOT EXISTS t_component_node_install (
id bigserial NOT NULL,
node_id varchar(128) NOT NULL,
arch varchar(16) NOT NULL,
component varchar(64) NOT NULL,
version varchar(128) NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
CONSTRAINT uk_node_install UNIQUE (node_id, arch, component, version)
);
CREATE INDEX IF NOT EXISTS idx_node_install_node ON t_component_node_install (node_id);
CREATE INDEX IF NOT EXISTS idx_node_install_comp ON t_component_node_install (arch, component, version);

SELECT pg_advisory_unlock(hashtext('cubemaster_migration_20260813120000_warehouse'));

-- +goose Down

SELECT cubemaster_acquire_migration_lock('cubemaster_migration_20260813120000_warehouse', 60);

DROP TABLE IF EXISTS t_component_node_install;
DROP TABLE IF EXISTS t_component_preinstall_job;
DROP TABLE IF EXISTS t_component_import_job;
DROP TABLE IF EXISTS t_component_warehouse;

SELECT pg_advisory_unlock(hashtext('cubemaster_migration_20260813120000_warehouse'));
4 changes: 2 additions & 2 deletions CubeMaster/conf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ cubelet_conf:
create_image_timeout_insec: 300
# See docs/guide/lifecycle.md — Timeout semantics (canonical).
default_timeout_insec: -1
# Create-path RPC/scheduling deadline (seconds).
create_timeout_insec: 300
# Create-path RPC/scheduling deadline (seconds). Must cover warehouse download.
create_timeout_insec: 600
create_concurrent_limit: 100
destroy_concurent_limit: 100
enable_exposed_port: true
Expand Down
2 changes: 1 addition & 1 deletion CubeMaster/pkg/base/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ func preHandleCubeletConf(config *Config) error {
}
// DefaultTimeoutInsec is left untouched — see docs/guide/lifecycle.md.
if config.CubeletConf.CreateTimeoutInsec <= 0 {
config.CubeletConf.CreateTimeoutInsec = 300
config.CubeletConf.CreateTimeoutInsec = 600
}
if config.CubeletConf.MaxRetries == 0 {
config.CubeletConf.MaxRetries = 5
Expand Down
31 changes: 4 additions & 27 deletions CubeMaster/pkg/templatecenter/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,14 @@ func ScheduleCompatScanForNode(nodeID string) {
}

// ScanNodeCompat updates replica compat_status for the compat matrix only.
// It does not touch scheduling caches: READY replicas remain schedulable regardless of STALE.
// It does not touch scheduling caches: READY replicas remain schedulable
// regardless of historical STALE rows. Pinned replicas stay OK even when the
// node has not reported live versions yet.
func ScanNodeCompat(ctx context.Context, nodeID string) error {
if !isReady() {
return ErrTemplateStoreNotInitialized
}
current, ok := nodemeta.GetNodeComponentVersions(ctx, nodeID)
if !ok {
return markNodeReadyReplicasCompat(ctx, nodeID, CompatStatusUnknown)
}
current, _ := nodemeta.GetNodeComponentVersions(ctx, nodeID)

replicas := make([]models.TemplateReplica, 0)
if err := store.db.WithContext(ctx).Table(constants.TemplateReplicaTableName).
Expand All @@ -115,28 +114,6 @@ func ScanNodeCompat(ctx context.Context, nodeID string) error {
return nil
}

func markNodeReadyReplicasCompat(ctx context.Context, nodeID, status string) error {
replicas := make([]models.TemplateReplica, 0)
if err := store.db.WithContext(ctx).Table(constants.TemplateReplicaTableName).
Where("node_id = ? AND status = ?", nodeID, ReplicaStatusReady).
Find(&replicas).Error; err != nil {
return err
}
for _, row := range replicas {
current := normalizeCompatStatus(row.CompatStatus)
if current == CompatStatusStale && status == CompatStatusUnknown {
continue
}
if current == status {
continue
}
if err := updateReplicaCompat(ctx, row.TemplateID, nodeID, status); err != nil {
return err
}
}
return nil
}

func updateReplicaCompat(ctx context.Context, templateID, nodeID, status string) error {
now := time.Now()
return store.db.WithContext(ctx).Table(constants.TemplateReplicaTableName).
Expand Down
70 changes: 63 additions & 7 deletions CubeMaster/pkg/templatecenter/compat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestEvaluateCompat(t *testing.T) {
GuestImageVersion: "v1",
AgentVersion: "a1",
KernelVersion: "k1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v1",
Expand All @@ -32,24 +33,75 @@ func TestEvaluateCompat(t *testing.T) {
want: CompatStatusOK,
},
{
name: "guest mismatch is stale",
name: "pinned replica stays ok when live guest differs",
replica: ReplicaStatus{
GuestImageVersion: "v1",
AgentVersion: "a1",
KernelVersion: "k1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v2",
agent: "a1",
kernel: "k1",
want: CompatStatusStale,
want: CompatStatusOK,
},
{
name: "unpinned replica is unknown",
replica: ReplicaStatus{
CompatPolicy: CompatPolicyStrict,
},
guest: "v2",
agent: "a2",
kernel: "k2",
want: CompatStatusUnknown,
},
{
name: "empty guest pin is unknown even when agent is set",
replica: ReplicaStatus{
AgentVersion: "a1",
KernelVersion: "k1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v2",
agent: "a1",
kernel: "k1",
want: CompatStatusUnknown,
},
{
name: "pre-multiversion guest agent kernel without shim is unknown",
replica: ReplicaStatus{
GuestImageVersion: "v0.6.0",
AgentVersion: "v0.6.0",
KernelVersion: "k1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v0.6.0-test7",
agent: "v0.6.0-test7",
kernel: "k2",
want: CompatStatusUnknown,
},
{
name: "guest agent shim without kernel is unknown",
replica: ReplicaStatus{
GuestImageVersion: "v1",
AgentVersion: "a1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v2",
agent: "a2",
kernel: "k2",
want: CompatStatusUnknown,
},
{
name: "kernel mismatch does not require redo",
replica: ReplicaStatus{
GuestImageVersion: "v1",
AgentVersion: "a1",
KernelVersion: "k1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v1",
Expand All @@ -58,24 +110,26 @@ func TestEvaluateCompat(t *testing.T) {
want: CompatStatusOK,
},
{
name: "missing current agent is unknown, not ok",
name: "pinned replica stays ok when current versions are empty",
replica: ReplicaStatus{
GuestImageVersion: "v1",
AgentVersion: "a1",
KernelVersion: "k1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v1",
guest: "",
agent: "",
kernel: "k1",
want: CompatStatusUnknown,
kernel: "",
want: CompatStatusOK,
},
{
name: "unknown literal is treated as missing",
replica: ReplicaStatus{
GuestImageVersion: "v1",
AgentVersion: "unknown",
KernelVersion: "k1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v1",
Expand All @@ -84,11 +138,12 @@ func TestEvaluateCompat(t *testing.T) {
want: CompatStatusUnknown,
},
{
name: "guest only policy ignores agent mismatch",
name: "guest only policy with restore pins stays ok when agent differs",
replica: ReplicaStatus{
GuestImageVersion: "v1",
AgentVersion: "a1",
KernelVersion: "k1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyGuestOnly,
},
guest: "v1",
Expand All @@ -102,6 +157,7 @@ func TestEvaluateCompat(t *testing.T) {
GuestImageVersion: "v1",
AgentVersion: "a1",
KernelVersion: "k1",
ShimVersion: "s1",
CompatPolicy: CompatPolicyStrict,
},
guest: "v1",
Expand Down
Loading
Loading