mirror of
https://github.com/kubesphere/kubekey.git
synced 2025-12-25 17:12:50 +00:00
* feat: enhance precheck tasks for image registry and network validation - Added a task to ensure successful authentication to the image registry. - Updated existing tasks to provide clearer failure messages for required configurations. - Improved validation for network interfaces and CIDR configurations, ensuring dual-stack support. - Enhanced error handling in the resource handler for playbook creation. Signed-off-by: joyceliu <joyceliu@yunify.com> * feat: enhance configuration and query handling - Added `-trimpath` flag to Go build configuration for improved binary paths. - Updated REST configuration to set QPS and Burst limits for better performance. - Refactored query handling to use string types for field and value, improving type consistency. - Enhanced error handling in resource configuration updates and improved parsing of request bodies. Signed-off-by: joyceliu <joyceliu@yunify.com> * feat: check inventory when it's changed Signed-off-by: joyceliu <joyceliu@yunify.com> * feat: enhance playbook execution and query handling - Added a new optional query parameter `promise` to the playbook and inventory endpoints, allowing for asynchronous execution control. - Introduced a new result state `ResultPending` to indicate ongoing operations. - Refactored the executor function to handle the `promise` parameter, enabling conditional execution of playbooks. - Improved error handling and logging during playbook execution. Signed-off-by: joyceliu <joyceliu@yunify.com> --------- Signed-off-by: joyceliu <joyceliu@yunify.com>
105 lines
3.3 KiB
Go
105 lines
3.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"github.com/cockroachdb/errors"
|
|
kkcorev1 "github.com/kubesphere/kubekey/api/core/v1"
|
|
"k8s.io/klog/v2"
|
|
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
_const "github.com/kubesphere/kubekey/v4/pkg/const"
|
|
"github.com/kubesphere/kubekey/v4/pkg/executor"
|
|
)
|
|
|
|
var playbookManager = &manager{
|
|
manager: make(map[string]context.CancelFunc),
|
|
}
|
|
|
|
// playbookManager is responsible for managing playbook execution contexts and their cancellation.
|
|
// It uses a mutex to ensure thread-safe access to the manager map.
|
|
type manager struct {
|
|
sync.Mutex
|
|
manager map[string]context.CancelFunc // Map of playbook key to its cancel function
|
|
}
|
|
|
|
func (m *manager) executor(playbook *kkcorev1.Playbook, client ctrlclient.Client, promise string) error {
|
|
f := func() error {
|
|
// Build the log file path for the playbook execution
|
|
filename := filepath.Join(
|
|
_const.GetWorkdirFromConfig(playbook.Spec.Config),
|
|
_const.RuntimeDir,
|
|
kkcorev1.SchemeGroupVersion.Group,
|
|
kkcorev1.SchemeGroupVersion.Version,
|
|
"playbooks",
|
|
playbook.Namespace,
|
|
playbook.Name,
|
|
playbook.Name+".log",
|
|
)
|
|
// Ensure the directory for the log file exists
|
|
if _, err := os.Stat(filepath.Dir(filename)); err != nil {
|
|
if !os.IsNotExist(err) {
|
|
return errors.Wrapf(err, "failed to stat playbook dir %q", filepath.Dir(filename))
|
|
}
|
|
// If directory does not exist, create it
|
|
if err := os.MkdirAll(filepath.Dir(filename), os.ModePerm); err != nil {
|
|
return errors.Wrapf(err, "failed to create playbook dir %q", filepath.Dir(filename))
|
|
}
|
|
}
|
|
// Open the log file for writing
|
|
file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "failed to open log file", "file", filename)
|
|
}
|
|
defer file.Close()
|
|
|
|
// Create a cancellable context for playbook execution
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
// Register the playbook and its cancel function in the playbookManager
|
|
m.addPlaybook(playbook, cancel)
|
|
// Execute the playbook and write output to the log file
|
|
if err := executor.NewPlaybookExecutor(ctx, client, playbook, file).Exec(ctx); err != nil {
|
|
klog.ErrorS(err, "failed to exec playbook", "playbook", playbook.Name)
|
|
}
|
|
// Remove the playbook from the playbookManager after execution
|
|
m.deletePlaybook(playbook)
|
|
return nil
|
|
}
|
|
if promise == "true" {
|
|
go func() {
|
|
if err := f(); err != nil {
|
|
klog.ErrorS(err, "failed to execute playbook", "playbook", ctrlclient.ObjectKeyFromObject(playbook))
|
|
}
|
|
}()
|
|
return nil
|
|
}
|
|
return f()
|
|
}
|
|
|
|
// addPlaybook adds a playbook and its cancel function to the manager map.
|
|
func (m *manager) addPlaybook(playbook *kkcorev1.Playbook, cancel context.CancelFunc) {
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
|
|
m.manager[ctrlclient.ObjectKeyFromObject(playbook).String()] = cancel
|
|
}
|
|
|
|
// deletePlaybook removes a playbook from the manager map.
|
|
func (m *manager) deletePlaybook(playbook *kkcorev1.Playbook) {
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
|
|
delete(m.manager, ctrlclient.ObjectKeyFromObject(playbook).String())
|
|
}
|
|
|
|
// stopPlaybook cancels the context for a running playbook, if it exists.
|
|
func (m *manager) stopPlaybook(playbook *kkcorev1.Playbook) {
|
|
// Attempt to cancel the playbook's context if it exists in the manager
|
|
if cancel, ok := m.manager[ctrlclient.ObjectKeyFromObject(playbook).String()]; ok {
|
|
cancel()
|
|
}
|
|
}
|