agent/framework/processor/executer/plugin/plugin.go (163 lines of code) (raw):
// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may not
// use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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.
// Package plugin contains general interfaces and types relevant to plugins.
// It also provides the methods for registering plugins.
package plugin
import (
"runtime/debug"
"sync"
"github.com/aws/amazon-ssm-agent/agent/appconfig"
"github.com/aws/amazon-ssm-agent/agent/context"
"github.com/aws/amazon-ssm-agent/agent/framework/runpluginutil"
"github.com/aws/amazon-ssm-agent/agent/plugins/configurecontainers"
"github.com/aws/amazon-ssm-agent/agent/plugins/configurepackage"
"github.com/aws/amazon-ssm-agent/agent/plugins/dockercontainer"
"github.com/aws/amazon-ssm-agent/agent/plugins/downloadcontent"
"github.com/aws/amazon-ssm-agent/agent/plugins/inventory"
"github.com/aws/amazon-ssm-agent/agent/plugins/lrpminvoker"
"github.com/aws/amazon-ssm-agent/agent/plugins/refreshassociation"
"github.com/aws/amazon-ssm-agent/agent/plugins/rundocument"
"github.com/aws/amazon-ssm-agent/agent/plugins/runscript"
"github.com/aws/amazon-ssm-agent/agent/plugins/updatessmagent"
"github.com/aws/amazon-ssm-agent/agent/session/plugins/interactivecommands"
"github.com/aws/amazon-ssm-agent/agent/session/plugins/noninteractivecommands"
"github.com/aws/amazon-ssm-agent/agent/session/plugins/port"
"github.com/aws/amazon-ssm-agent/agent/session/plugins/sessionplugin"
"github.com/aws/amazon-ssm-agent/agent/session/plugins/standardstream"
)
// allPlugins is the list of all known plugins.
// This allows us to differentiate between the case where a document asks for a plugin that exists but isn't supported on this platform
// and the case where a plugin name isn't known at all to this version of the agent (and the user should probably upgrade their agent)
var allPlugins = map[string]struct{}{
appconfig.PluginNameAwsAgentUpdate: {},
appconfig.PluginNameAwsApplications: {},
appconfig.PluginNameAwsConfigureDaemon: {},
appconfig.PluginNameAwsConfigurePackage: {},
appconfig.PluginNameAwsPowerShellModule: {},
appconfig.PluginNameAwsRunPowerShellScript: {},
appconfig.PluginNameAwsRunShellScript: {},
appconfig.PluginNameAwsSoftwareInventory: {},
appconfig.PluginNameCloudWatch: {},
appconfig.PluginNameConfigureDocker: {},
appconfig.PluginNameDockerContainer: {},
appconfig.PluginNameDomainJoin: {},
appconfig.PluginEC2ConfigUpdate: {},
appconfig.PluginNameRefreshAssociation: {},
appconfig.PluginDownloadContent: {},
appconfig.PluginRunDocument: {},
}
var once sync.Once
// registeredPlugins stores the registered plugins.
var registeredPlugins *runpluginutil.PluginRegistry
type CloudWatchFactory struct {
}
func (f CloudWatchFactory) Create(context context.T) (runpluginutil.T, error) {
return lrpminvoker.NewPlugin(context, appconfig.PluginNameCloudWatch)
}
type InventoryGathererFactory struct {
}
func (f InventoryGathererFactory) Create(context context.T) (runpluginutil.T, error) {
return inventory.NewPlugin(context)
}
type RunPowerShellFactory struct {
}
func (f RunPowerShellFactory) Create(context context.T) (runpluginutil.T, error) {
return runscript.NewRunPowerShellPlugin(context)
}
type UpdateAgentFactory struct {
}
func (f UpdateAgentFactory) Create(context context.T) (runpluginutil.T, error) {
return updatessmagent.NewPlugin(context)
}
type ConfigureContainerFactory struct {
}
func (f ConfigureContainerFactory) Create(context context.T) (runpluginutil.T, error) {
return configurecontainers.NewPlugin(context)
}
type RunDockerFactory struct {
}
func (f RunDockerFactory) Create(context context.T) (runpluginutil.T, error) {
return dockercontainer.NewPlugin(context)
}
type ConfigurePackageFactory struct {
}
func (f ConfigurePackageFactory) Create(context context.T) (runpluginutil.T, error) {
return configurepackage.NewPlugin(context)
}
type RefreshAssociationFactory struct {
}
func (f RefreshAssociationFactory) Create(context context.T) (runpluginutil.T, error) {
return refreshassociation.NewPlugin(context)
}
type DownloadContentFactory struct {
}
func (d DownloadContentFactory) Create(context context.T) (runpluginutil.T, error) {
return downloadcontent.NewPlugin(context)
}
type RunDocumentFactory struct {
}
func (r RunDocumentFactory) Create(context context.T) (runpluginutil.T, error) {
return rundocument.NewPlugin(context)
}
type SessionPluginFactory struct {
newPluginFunc sessionplugin.NewPluginFunc
}
func (f SessionPluginFactory) Create(context context.T) (runpluginutil.T, error) {
return sessionplugin.NewPlugin(context, f.newPluginFunc)
}
// RegisteredWorkerPlugins returns all registered core modules.
func RegisteredWorkerPlugins(context context.T) runpluginutil.PluginRegistry {
defer func() {
if msg := recover(); msg != nil {
context.Log().Errorf("Agent failed while getting registered worker plugins %v!", msg)
context.Log().Errorf("Stacktrace:\n%s", debug.Stack())
}
}()
once.Do(func() {
loadWorkers(context)
})
return *registeredPlugins
}
// RegisteredSessionWorkerPlugins returns all registered session plugins.
func RegisteredSessionWorkerPlugins() runpluginutil.PluginRegistry {
once.Do(func() {
loadSessionPlugins()
})
return *registeredPlugins
}
// loadWorkers loads all worker plugins that are invokers for interacting with long running plugins and
// then all standard worker plugins (if there are any conflicting names, the standard worker plugin wins)
func loadWorkers(context context.T) {
plugins := runpluginutil.PluginRegistry{}
//Long running plugins are handled by lrpm. lrpminvoker is a worker plugin that can communicate with lrpm.
//that's why all long running plugins are first handled by lrpminvoker - which then hands off the work to lrpm.
plugins[appconfig.PluginNameCloudWatch] = CloudWatchFactory{}
for key, value := range loadPlatformIndependentPlugins(context) {
plugins[key] = value
context.Log().Infof("Successfully loaded platform independent plugin %v", key)
}
for key, value := range loadPlatformDependentPlugins(context) {
plugins[key] = value
context.Log().Infof("Successfully loaded platform dependent plugin %v", key)
}
registeredPlugins = &plugins
}
// loadSessionPlugins loads all session plugins
func loadSessionPlugins() {
var sessionPlugins = runpluginutil.PluginRegistry{}
standardStreamPluginName := appconfig.PluginNameStandardStream
sessionPlugins[standardStreamPluginName] = SessionPluginFactory{standardstream.NewPlugin}
interactiveCommandsPluginName := appconfig.PluginNameInteractiveCommands
sessionPlugins[interactiveCommandsPluginName] = SessionPluginFactory{interactivecommands.NewPlugin}
portPluginName := appconfig.PluginNamePort
sessionPlugins[portPluginName] = SessionPluginFactory{port.NewPlugin}
nonInteractiveCommandsPluginName := appconfig.PluginNameNonInteractiveCommands
sessionPlugins[nonInteractiveCommandsPluginName] = SessionPluginFactory{noninteractivecommands.NewPlugin}
registeredPlugins = &sessionPlugins
}
// loadPlatformIndependentPlugins registers plugins common to all platforms
func loadPlatformIndependentPlugins(context context.T) runpluginutil.PluginRegistry {
var workerPlugins = runpluginutil.PluginRegistry{}
inventoryPluginName := inventory.Name()
workerPlugins[inventoryPluginName] = InventoryGathererFactory{}
// registering aws:runPowerShellScript plugin
workerPlugins[appconfig.PluginNameAwsRunPowerShellScript] = RunPowerShellFactory{}
// registering aws:updateSsmAgent plugin
updateAgentPluginName := updatessmagent.Name()
workerPlugins[updateAgentPluginName] = UpdateAgentFactory{}
// registering aws:configureContainers plugin
configureContainersPluginName := configurecontainers.Name()
workerPlugins[configureContainersPluginName] = ConfigureContainerFactory{}
// registering aws:runDockerAction plugin
runDockerPluginName := dockercontainer.Name()
workerPlugins[runDockerPluginName] = RunDockerFactory{}
// registering aws:refreshAssociation plugin
refreshAssociationPluginName := refreshassociation.Name()
workerPlugins[refreshAssociationPluginName] = RefreshAssociationFactory{}
// registering aws:configurePackage
configurePackagePluginName := configurepackage.Name()
workerPlugins[configurePackagePluginName] = ConfigurePackageFactory{}
//registering aws:downloadContent
downloadContentPluginName := downloadcontent.Name()
workerPlugins[downloadContentPluginName] = DownloadContentFactory{}
//registering aws:runDocument
runDocumentPluginName := rundocument.Name()
workerPlugins[runDocumentPluginName] = RunDocumentFactory{}
return workerPlugins
}