cmd/core_plugin/platscript/platscript_linux.go (81 lines of code) (raw):
// Copyright 2024 Google LLC
//
// 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.
//go:build linux
// Package platscript is responsible for running platform specific setup scripts.
package platscript
import (
"context"
"fmt"
"path/filepath"
"strings"
"github.com/GoogleCloudPlatform/galog"
"github.com/GoogleCloudPlatform/google-guest-agent/cmd/core_plugin/manager"
"github.com/GoogleCloudPlatform/google-guest-agent/internal/cfg"
"github.com/GoogleCloudPlatform/google-guest-agent/internal/metadata"
"github.com/GoogleCloudPlatform/google-guest-agent/internal/run"
)
// platformScript is a single platform script to run.
type platformScript struct {
// enabled is true if the script should be run/is enabled.
enabled bool
// script is the name of the script to run.
script string
}
var (
// scriptsConfig is the list of platform scripts to run - and their "enabled"
// flag. Scripts are enabled via guest agent configuration.
scriptsConfig []*platformScript
// scriptsPathPrefix is the path to the platform scripts directory. If set
// (not empty) the scripts will be run from this directory(useful for
// testing).
scriptsPathPrefix = ""
// overcommitCommand is the command to run to set the overcommit memory
// setting to 1 for e2 instances.
overcommitCommand = []string{"sysctl", "vm.overcommit_memory=1"}
)
const (
// platscriptModuleID is the module ID for the platform script manager.
platscriptModuleID = "platform-scripts"
)
// NewModule returns the first boot module for late stage registration.
func NewModule(context.Context) *manager.Module {
return &manager.Module{
ID: platscriptModuleID,
Setup: moduleSetup,
Description: "Executes platform configuration scripts available in the guest environment",
}
}
// initScriptsMapping initializes the scripts list, sets its "enabled" flag
// and the script path (if set).
func initScriptsMapping() {
config := cfg.Retrieve()
// Map the scripts to their "enabled" flag.
scriptsConfig = []*platformScript{
&platformScript{enabled: config.InstanceSetup.OptimizeLocalSSD, script: "google_optimize_local_ssd"},
&platformScript{enabled: config.InstanceSetup.SetMultiqueue, script: "google_set_multiqueue"},
}
// Prepend scriptsPathPrefix to the script name.
for _, curr := range scriptsConfig {
curr.script = filepath.Join(scriptsPathPrefix, curr.script)
}
}
// moduleSetup runs the platform scripts on Linux.
func moduleSetup(ctx context.Context, data any) error {
initScriptsMapping()
desc, ok := data.(*metadata.Descriptor)
if !ok {
return fmt.Errorf("platform script module expects a metadata descriptor in the data pointer")
}
// Iterate over the scripts and run the enabled ones.
for _, curr := range scriptsConfig {
galog.V(2).Debugf("Platform script(%q) enabled: (%t)", curr.script, curr.enabled)
if !curr.enabled {
continue
}
galog.Debugf("Running platform script: %q", curr.script)
opts := run.Options{Name: curr.script, OutputType: run.OutputNone}
if _, err := run.WithContext(ctx, opts); err != nil {
return fmt.Errorf("failed to run platform script %q: %w", curr.script, err)
}
}
if err := overCommitMemory(ctx, desc); err != nil {
return fmt.Errorf("failed to run overcommit memory setup: %w", err)
}
return nil
}
// overCommitMemory sets the overcommit memory setting to 1 for e2 instances.
func overCommitMemory(ctx context.Context, desc *metadata.Descriptor) error {
// Ignore overcommit accounting if not e2 instances.
if !validMachineType(desc.Instance().MachineType()) {
galog.V(2).Debug("Not an e2 instance, skipping overcommit memory.")
return nil
}
// Run the overcommit command.
opts := run.Options{Name: overcommitCommand[0], Args: overcommitCommand[1:], OutputType: run.OutputNone}
if _, err := run.WithContext(ctx, opts); err != nil {
return fmt.Errorf("failed to run 'sysctl vm.overcommit_memory=1': %w", err)
}
return nil
}
// validMachineType returns true if the machine type is an e2 instance.
func validMachineType(machineType string) bool {
parts := strings.Split(machineType, "/")
if !strings.HasPrefix(parts[len(parts)-1], "e2-") {
return false
}
return true
}