// 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 contracts provides model definitions for document state package contracts import ( "strings" "github.com/aws/amazon-ssm-agent/agent/appconfig" "github.com/aws/amazon-ssm-agent/agent/context" "github.com/aws/amazon-ssm-agent/agent/jsonutil" ) // TODO deprecate this functionality once we update the windows update document type managedInstanceDocumentProperties struct { RunCommand []string ID string } type documentListType map[string]bool var managedInstanceIncompatibleAWSSSMDocuments documentListType func init() { var documentList = documentListType{} documentList["AWS-ConfigureWindowsUpdate"] = true documentList["AWS-FindWindowsUpdates"] = true documentList["AWS-InstallMissingWindowsUpdates"] = true documentList["AWS-InstallSpecificWindowsUpdates"] = true documentList["AWS-ListWindowsInventory"] = true managedInstanceIncompatibleAWSSSMDocuments = documentList } // RemoveDependencyOnInstanceMetadata looks for array of commands which will be executed as a part of this document and replace the incompatible code. func RemoveDependencyOnInstanceMetadata(context context.T, docState *DocumentState) error { log := context.Log() var properties []interface{} var parsedDocumentProperties managedInstanceDocumentProperties for index, pluginState := range docState.InstancePluginsInformation { if pluginState.Name == appconfig.PluginNameAwsRunPowerShellScript { err := jsonutil.Remarshal(pluginState.Configuration.Properties, &properties) if err != nil { log.Debugf("properties format unmatch in %v document. error: %v", docState.DocumentInformation.DocumentName, err) return nil } // Since 'Properties' is an array and we use only one property block for the above documents, array location '0' of 'Properties' is used. err = jsonutil.Remarshal(properties[0], &parsedDocumentProperties) if err != nil { log.Debugf("property format unmatch in %v document. error: %v", docState.DocumentInformation.DocumentName, err) return nil } region, err := context.Identity().Region() if err != nil { log.Errorf("Error retrieving agent region. error: %v", err) return err } // Comment or replace the incompatible code from this document. log.Info("Replacing managed instance incompatible code for AWS SSM Document.") for i, command := range parsedDocumentProperties.RunCommand { // remove the call to metadata service to retrieve the region for onprem instances if strings.Contains(command, "$metadataLocation = 'http://169.254.169.254/latest/dynamic/instance-identity/document/region'") { parsedDocumentProperties.RunCommand[i] = strings.Replace(command, "$metadataLocation = 'http://169.254.169.254/latest/dynamic/instance-identity/document/region'", "# $metadataLocation = 'http://169.254.169.254/latest/dynamic/instance-identity/document/region' (This is done to make it managed instance compatible)", 1) } if strings.Contains(command, "$metadata = (New-Object Net.WebClient).DownloadString($metadataLocation)") { parsedDocumentProperties.RunCommand[i] = strings.Replace(command, "$metadata = (New-Object Net.WebClient).DownloadString($metadataLocation)", "# $metadata = (New-Object Net.WebClient).DownloadString($metadataLocation) (This is done to make it managed instance compatible)", 1) } if strings.Contains(command, "$region = (ConvertFrom-JSON $metadata).region") { parsedDocumentProperties.RunCommand[i] = strings.Replace(command, "$region = (ConvertFrom-JSON $metadata).region", "$region = '"+region+"'", 1) } } // Plug-in the compatible 'Properties' block back to the document. properties[0] = parsedDocumentProperties var documentProperties interface{} = properties pluginState.Configuration.Properties = documentProperties docState.InstancePluginsInformation[index] = pluginState } } return nil } // IsManagedInstanceIncompatibleAWSSSMDocument checks if doc could contain incompatible code for managed instance func IsManagedInstanceIncompatibleAWSSSMDocument(documentName string) bool { return managedInstanceIncompatibleAWSSSMDocuments[documentName] }