| // 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 |
| } |