blob: 3db3a1e1fe1fd2d50db7b69ecd1065af8574f4b8 [file] [log] [blame]
// Copyright 2021 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 stackdriver_alpha
// +build stackdriver_alpha
package policyenforcer
import (
"errors"
"policy_manager/devicepolicy"
"policy_manager/systemd"
"policy_manager/policymanagerproto"
"github.com/golang/glog"
"github.com/golang/protobuf/proto"
)
// policyEnforcerImpl implements the PolicyEnforcer interface.
type policyEnforcerImpl struct {
// systemdClient is the interface used to call systemd API.
systemdClient systemd.SystemdClient
// manager is used to read content from device policy file.
manager devicepolicy.Manager
// health monitor is the interface to the logging and monitoring services.
healthMonitor *HealthMonitor
}
// NewPolicyEnforcer returns a new PolicyEnforcer for applying the
// the COS device policy and status check
func NewPolicyEnforcer(systemdClient systemd.SystemdClient, manager devicepolicy.Manager, monitor *HealthMonitor) PolicyEnforcer {
return &policyEnforcerImpl{systemdClient, manager, monitor}
}
func startOrStopUnit(systemdClient systemd.SystemdClient, unitName string, isStartUnit bool) error {
if isStartUnit {
return systemdClient.StartUnit(unitName)
} else {
return systemdClient.StopUnit(unitName)
}
}
// UpdateHealthMonitorState reads device policy from disk, and then apply
// health monitor related configuration to the instance:
// If health monitor feature enforcement is on, the function will start or stop
// the health monitor services to apply the configuration in device policy.
func (client *policyEnforcerImpl) UpdateHealthMonitorState() error {
// Reads the device policy files from disk to get desired state.
config, err := client.manager.GetInstanceConfig()
if err != nil {
return err
}
// Returns when the health monitor feature enforcement is off.
if config == nil || config.HealthMonitorConfig == nil || !config.HealthMonitorConfig.GetEnforced() {
return nil
}
// Gets the current status of health monitor logging & logging.
healthMonitorStatus, err := client.GetHealthMonitorStatus()
if err != nil {
return err
}
updateStateErr := false
// Start or stop the health monitor services to reach desired state.
if healthMonitorStatus.GetLogging() != config.HealthMonitorConfig.GetLoggingEnabled() {
if err = startOrStopUnit(client.systemdClient,
client.healthMonitor.LoggingService(), config.HealthMonitorConfig.GetLoggingEnabled()); err != nil {
glog.Error(err)
updateStateErr = true
}
}
if healthMonitorStatus.GetMonitoring() != config.HealthMonitorConfig.GetMonitoringEnabled() {
if err = startOrStopUnit(client.systemdClient,
client.healthMonitor.MonitoringService(), config.HealthMonitorConfig.GetMonitoringEnabled()); err != nil {
glog.Error(err)
updateStateErr = true
}
}
if updateStateErr {
return errors.New("Unable to apply health monitor policy.")
}
return nil
}
// GetHealthMonitorStatus checks whether health monitor logging/monitoring service
// is running, and returns their status in a HealthMonitorStatus proto.
// Failure to check one service will result in a missing field in the returned
// proto, and will not affect checking the other service's status.
func (client *policyEnforcerImpl) GetHealthMonitorStatus() (*policymanagerproto.HealthMonitorStatus, error) {
healthMonitorStatus := new(policymanagerproto.HealthMonitorStatus)
statusErr := false
isRunning, err := client.systemdClient.IsUnitActiveRunning(client.healthMonitor.LoggingService())
if err != nil {
glog.Error(err)
statusErr = true
} else {
healthMonitorStatus.Logging = proto.Bool(isRunning)
}
isRunning, err = client.systemdClient.IsUnitActiveRunning(client.healthMonitor.MonitoringService())
if err != nil {
glog.Error(err)
statusErr = true
} else {
healthMonitorStatus.Monitoring = proto.Bool(isRunning)
}
if statusErr {
return healthMonitorStatus, errors.New("Unable to get health monitor status.")
}
return healthMonitorStatus, nil
}