agent/association/parser/parser.go (86 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 parser contains utilities for parsing and encoding MDS/SSM messages.
package parser
import (
"encoding/json"
"fmt"
"path"
"path/filepath"
"time"
"github.com/aws/amazon-ssm-agent/agent/appconfig"
"github.com/aws/amazon-ssm-agent/agent/association/model"
"github.com/aws/amazon-ssm-agent/agent/context"
"github.com/aws/amazon-ssm-agent/agent/contracts"
"github.com/aws/amazon-ssm-agent/agent/framework/docparser"
"github.com/aws/amazon-ssm-agent/agent/jsonutil"
"github.com/aws/amazon-ssm-agent/agent/log"
messageContracts "github.com/aws/amazon-ssm-agent/agent/runcommand/contracts"
"github.com/aws/amazon-ssm-agent/agent/times"
)
// ErrorMsg represents the error message to be sent to the customer
const ErrorMsg = "Encountered error while parsing input - internal error"
// ParseDocumentForPayload parses an document and replaces the parameters where needed.
func ParseDocumentForPayload(log log.T,
rawData *model.InstanceAssociation) (*messageContracts.SendCommandPayload, error) {
rawDataContent, err := jsonutil.Marshal(rawData)
if err != nil {
log.Debugf("Could not marshal association! ", err)
return nil, fmt.Errorf("%v", ErrorMsg)
}
log.Debug("Processing association ", jsonutil.Indent(rawDataContent))
payload := &messageContracts.SendCommandPayload{}
if err = json.Unmarshal([]byte(*rawData.Document), &payload.DocumentContent); err != nil {
log.Debugf("Could not unmarshal parameters ", err)
return nil, fmt.Errorf("%v", ErrorMsg)
}
log.Debugf("unmarshal parameters: %v", payload.DocumentContent)
payload.DocumentName = *rawData.Association.Name
payload.CommandID = *rawData.Association.AssociationId
if rawData.Association.OutputLocation != nil && rawData.Association.OutputLocation.S3Location != nil {
if rawData.Association.OutputLocation.S3Location.OutputS3KeyPrefix != nil {
payload.OutputS3KeyPrefix = *rawData.Association.OutputLocation.S3Location.OutputS3KeyPrefix
}
if rawData.Association.OutputLocation.S3Location.OutputS3BucketName != nil {
payload.OutputS3BucketName = *rawData.Association.OutputLocation.S3Location.OutputS3BucketName
}
}
payload.Parameters = docparser.ParseParameters(log, rawData.Association.Parameters, payload.DocumentContent.Parameters)
return payload, nil
}
// InitializeDocumentState - an interim state that is used around during an execution of a document
func InitializeDocumentState(context context.T,
payload *messageContracts.SendCommandPayload,
rawData *model.InstanceAssociation) (contracts.DocumentState, error) {
//initialize document information with relevant values extracted from msg
documentInfo := newDocumentInfo(rawData, payload)
// adapt plugin configuration format from MDS to plugin expected format
s3KeyPrefix := path.Join(payload.OutputS3KeyPrefix, documentInfo.InstanceID, documentInfo.AssociationID, documentInfo.RunID)
orchestrationRootDir := filepath.Join(
appconfig.DefaultDataStorePath,
documentInfo.InstanceID,
appconfig.DefaultDocumentRootDirName,
context.AppConfig().Agent.OrchestrationRootDir)
orchestrationDir := filepath.Join(orchestrationRootDir, documentInfo.AssociationID, documentInfo.RunID)
parserInfo := docparser.DocumentParserInfo{
OrchestrationDir: orchestrationDir,
S3Bucket: payload.OutputS3BucketName,
S3Prefix: s3KeyPrefix,
MessageId: documentInfo.MessageID,
DocumentId: documentInfo.DocumentID,
}
docContent := &docparser.DocContent{
SchemaVersion: payload.DocumentContent.SchemaVersion,
Description: payload.DocumentContent.Description,
RuntimeConfig: payload.DocumentContent.RuntimeConfig,
MainSteps: payload.DocumentContent.MainSteps,
Parameters: payload.DocumentContent.Parameters,
}
return docparser.InitializeDocState(context, contracts.Association, docContent, documentInfo, parserInfo, payload.Parameters)
}
// newDocumentInfo initializes new DocumentInfo object
func newDocumentInfo(rawData *model.InstanceAssociation, payload *messageContracts.SendCommandPayload) contracts.DocumentInfo {
documentInfo := new(contracts.DocumentInfo)
documentInfo.AssociationID = *(rawData.Association.AssociationId)
documentInfo.InstanceID = *(rawData.Association.InstanceId)
documentInfo.MessageID = fmt.Sprintf("aws.ssm.%v.%v", documentInfo.AssociationID, documentInfo.InstanceID)
documentInfo.RunID = times.ToIsoDashUTC(time.Now())
documentInfo.DocumentID = *(rawData.Association.AssociationId) + "." + documentInfo.RunID
rawData.DocumentID = documentInfo.DocumentID
documentInfo.CreatedDate = times.ToIso8601UTC(rawData.CreateDate)
documentInfo.DocumentName = payload.DocumentName
documentInfo.DocumentVersion = *(rawData.Association.DocumentVersion)
documentInfo.DocumentStatus = contracts.ResultStatusInProgress
return *documentInfo
}