// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #pragma once // Standard Library #include <fstream> #include <iostream> #include <regex> #include <unordered_set> // AWS SDK #include <aws/core/utils/base64/Base64.h> #include <aws/cloudformation/CloudFormationClient.h> #include <aws/cloudformation/model/CreateStackRequest.h> #include <aws/cloudformation/model/DeleteStackRequest.h> #include <aws/cloudformation/model/DescribeStackEventsRequest.h> #include <aws/cloudformation/model/DescribeStackResourcesRequest.h> #include <aws/cloudformation/model/DescribeStacksRequest.h> #include <aws/cloudformation/model/GetTemplateRequest.h> #include <aws/cloudformation/model/ListStacksRequest.h> #include <aws/cloudformation/model/StackStatus.h> #include <aws/cloudformation/model/UpdateStackRequest.h> #include <aws/lambda/LambdaClient.h> #include <aws/lambda/model/DeleteLayerVersionRequest.h> #include <aws/lambda/model/PublishLayerVersionRequest.h> #include <aws/s3/S3Client.h> #include <aws/s3/model/PutObjectRequest.h> #include <aws/ssm/SSMClient.h> #include <aws/ssm/model/GetParameterRequest.h> #include <aws/ssm/model/PutParameterRequest.h> // GameKit #include <aws/gamekit/core/aws_region_mappings.h> #include <aws/gamekit/core/awsclients/api_initializer.h> #include <aws/gamekit/core/awsclients/default_clients.h> #include <aws/gamekit/core/enums.h> #include <aws/gamekit/core/exports.h> #include <aws/gamekit/core/feature_resources_callback.h> #include <aws/gamekit/core/gamekit_feature.h> #include <aws/gamekit/core/model/account_credentials.h> #include <aws/gamekit/core/model/account_info.h> #include <aws/gamekit/core/model/config_consts.h> #include <aws/gamekit/core/model/template_consts.h> #include <aws/gamekit/core/paramstore_keys.h> #include <aws/gamekit/core/utils/file_utils.h> #include <aws/gamekit/core/zipper.h> // yaml-cpp #include <yaml-cpp/yaml.h> namespace GameKit { /** * GameKitFeatureResources offers methods for working on the AWS resources of a single GAMEKIT feature (ex: "achievements"). * * Each instance of this class operates on one feature, which is specified in it's constructor. * * For example, it can deploy/delete the feature's CloudFormation stack and create it's instance template files for deployment. */ class GAMEKIT_API GameKitFeatureResources { private: AccountInfoCopy m_accountInfo; AccountCredentialsCopy m_credentials; FeatureType m_featureType; FuncLogCallback m_logCb = nullptr; Aws::S3::S3Client* m_s3Client; Aws::SSM::SSMClient* m_ssmClient; Aws::CloudFormation::CloudFormationClient* m_cfClient; Aws::Lambda::LambdaClient* m_lambdaClient; bool m_isUsingSharedS3Client = false; bool m_isUsingSharedSSMClient = false; bool m_isUsingSharedCfClient = false; bool m_isUsingSharedLambdaClient = false; std::string m_stackName; std::string m_layersReplacementId; std::string m_functionsReplacementId; std::string m_pluginRoot; std::string m_gamekitRoot; std::string m_baseLayersPath; std::string m_baseFunctionsPath; std::string m_baseCloudformationPath; std::string m_baseConfigOutputsPath; std::string m_instanceLayersPath; std::string m_instanceFunctionsPath; std::string m_instanceCloudformationPath; std::unordered_map<std::string, bool> m_resouceStatusMap; Aws::Vector<Aws::CloudFormation::Model::Parameter> getStackParameters(TemplateType templateType) const; std::string getRawStackParameters(TemplateType templateType) const; std::string getFeatureDashboardTemplate(TemplateType templateType) const; std::string getCloudFormationTemplate(TemplateType templateType) const; unsigned int createStack() const; unsigned int updateStack() const; unsigned int deleteStack() const; Aws::CloudFormation::Model::StackStatus periodicallyDescribeStackEvents(); void describeStackEvents(); unsigned int getDeployedTemplateBody(const std::string& stackName, std::string& templateBody) const; bool isTerminalState(Aws::CloudFormation::Model::StackStatus status); bool isFailedState(Aws::CloudFormation::Model::StackStatus status); std::string getTempLayersPath() const; std::string getTempFunctionsPath() const; YAML::Node getClientConfigYaml() const; std::vector<std::tuple<std::string, std::string>> getConfigOutputParameters() const; unsigned int writeCloudFormationParameterInstance(const std::string& cfParams) const; unsigned int writeCloudFormationTemplateInstance(const std::string& cfParams) const; unsigned int writeCloudFormationDashboardInstance(const std::string& cfTemplate) const; std::string getClientConfigFilePath() const; unsigned int writeClientConfigYamlToDisk(const YAML::Node& paramsYml) const; unsigned int removeOutputsFromClientConfiguration() const; unsigned int writeClientConfigurationWithOutputs(Aws::Vector<Aws::CloudFormation::Model::Output> outputs) const; std::string getFeatureLayerNameFromDirName(const std::string& layerDirName) const; Aws::Lambda::Model::PublishLayerVersionOutcome createFeatureLayer(const std::string& layerDirName, const std::string& s3ObjectName); bool lambdaLayerHashChanged(const std::string& layerName, const std::string& layerHash) const; unsigned int createAndSetLambdaLayerHash(const std::string& layerName, const std::string& layerHash) const; unsigned int createAndSetLambdaLayerArn(const std::string& layerName, const std::string& layerArn) const; std::string getShortRegionCode(); std::string getStackName(FeatureType featureType) const; unsigned int internalDescribeFeatureResources(FuncResourceInfoCallback resourceInfoCb = nullptr, DISPATCH_RECEIVER_HANDLE receiver = nullptr, DispatchedResourceInfoCallback = nullptr) const; public: GameKitFeatureResources(const AccountInfo accountInfo, const AccountCredentials credentials, FeatureType featureType, FuncLogCallback logCb); GameKitFeatureResources(const AccountInfoCopy& accountInfo, const AccountCredentialsCopy& credentials, FeatureType featureType, FuncLogCallback logCb); virtual ~GameKitFeatureResources(); // Clients initialized with his method will be deleted in the class destructor. void InitializeDefaultAwsClients(); // Returns Account Info AccountInfoCopy GetAccountInfo() { return m_accountInfo; } // Returns Account Credentials AccountCredentialsCopy GetAccountCredentials() { return m_credentials; } // Sets the root directory of the plugin's installation inline void SetPluginRoot(const std::string& pluginRoot) { m_pluginRoot = pluginRoot; m_baseLayersPath = pluginRoot + ResourceDirectories::LAYERS_DIRECTORY + GetFeatureTypeString(m_featureType) + "/"; m_baseFunctionsPath = pluginRoot + ResourceDirectories::FUNCTIONS_DIRECTORY + GetFeatureTypeString(m_featureType) + "/"; m_baseCloudformationPath = pluginRoot + ResourceDirectories::CLOUDFORMATION_DIRECTORY + GetFeatureTypeString(m_featureType) + "/"; m_baseConfigOutputsPath = pluginRoot + ResourceDirectories::CONFIG_OUTPUTS_DIRECTORY + GetFeatureTypeString(m_featureType) + "/"; } // Returns the root directory of the plugin's installation inline const std::string& GetPluginRoot() { return m_pluginRoot; } // The value GAMEKIT_ROOT where instance templates and settings are going to be stored inline void SetGameKitRoot(const std::string& gamekitRoot) { const std::string shortRegionCode = getShortRegionCode(); m_gamekitRoot = gamekitRoot; m_instanceLayersPath = gamekitRoot + "/" + m_accountInfo.gameName + "/" + m_accountInfo.environment.GetEnvironmentString() + "/" + shortRegionCode + ResourceDirectories::LAYERS_DIRECTORY + GetFeatureTypeString(m_featureType) + "/"; m_instanceFunctionsPath = gamekitRoot + "/" + m_accountInfo.gameName + "/" + m_accountInfo.environment.GetEnvironmentString() + "/" + shortRegionCode + ResourceDirectories::FUNCTIONS_DIRECTORY + GetFeatureTypeString(m_featureType) + "/"; m_instanceCloudformationPath = gamekitRoot + "/" + m_accountInfo.gameName + "/" + m_accountInfo.environment.GetEnvironmentString() + "/" + shortRegionCode + ResourceDirectories::CLOUDFORMATION_DIRECTORY + GetFeatureTypeString(m_featureType) + "/"; } // Returns the GAMEKIT_ROOT where instance templates and settings are stored inline const std::string& GetGameKitRoot() { return m_gamekitRoot; } // Sets the base CloudFormation path inline void SetBaseCloudFormationPath(const std::string& cloudFormationPath) { m_baseCloudformationPath = cloudFormationPath + GetFeatureTypeString(m_featureType) + "/"; } // Sets the base Lambda Layers path inline void SetBaseLayersPath(const std::string& layersPath) { m_baseLayersPath = layersPath + GetFeatureTypeString(m_featureType) + "/"; } // Sets the base Lambda Functions path inline void SetBaseFunctionsPath(const std::string& functionsPath) { m_baseFunctionsPath = functionsPath + GetFeatureTypeString(m_featureType) + "/"; } // Sets the instance CloudFormation path inline void SetInstanceCloudFormationPath(const std::string& cloudFormationPath) { m_instanceCloudformationPath = cloudFormationPath + GetFeatureTypeString(m_featureType) + "/"; } // Sets the instance Lambda Layers path void SetInstanceLayersPath(const std::string& layersPath) { m_instanceLayersPath = layersPath + GetFeatureTypeString(m_featureType) + "/"; } // Sets the instance Lambda Functions path void SetInstanceFunctionsPath(const std::string& functionsPath) { m_instanceFunctionsPath = functionsPath + GetFeatureTypeString(m_featureType) + "/"; } // Returns the base Lambda Functions path inline const std::string& GetBaseFunctionsPath() const { return m_baseFunctionsPath; } // Returns the base CloudFormation path inline const std::string& GetBaseCloudFormationPath() const { return m_baseCloudformationPath; } // Returns the instance Lambda Functions path inline const std::string& GetInstanceFunctionsPath() const { return m_instanceFunctionsPath; } // Returns the instance CloudFormation path inline const std::string& GetInstanceCloudFormationPath() const { return m_instanceCloudformationPath; } inline std::string GetLambdaFunctionReplacementIDParamName() const { return std::string(GAMEKIT_LAMBDA_FUNCTIONS_REPLACEMENT_ID_PREFIX) .append(GetFeatureTypeString(m_featureType)) .append("_") .append(m_accountInfo.gameName) .append("_") .append(m_accountInfo.environment.GetEnvironmentString()); } inline std::string GetLambdaLayerReplacementIDParamName() const { return std::string(GAMEKIT_LAMBDA_LAYERS_REPLACEMENT_ID_PREFIX) .append(GetFeatureTypeString(m_featureType)) .append("_") .append(m_accountInfo.gameName) .append("_") .append(m_accountInfo.environment.GetEnvironmentString()); } inline std::string GetLambdaLayerARNParamName(const std::string& layerName) const { return std::string(GAMEKIT_LAMBDA_LAYER_ARN_PREFIX) .append(GetFeatureTypeString(m_featureType)) .append("_") .append(layerName) .append("_") .append(m_accountInfo.gameName) .append("_") .append(m_accountInfo.environment.GetEnvironmentString()); } inline std::string GetLambdaLayerHashParamName(const std::string& layerName) const { return std::string(GAMEKIT_LAMBDA_LAYER_HASH_PREFIX) .append(GetFeatureTypeString(m_featureType)) .append("_") .append(layerName) .append("_") .append(m_accountInfo.gameName) .append("_") .append(m_accountInfo.environment.GetEnvironmentString()); } inline void SetS3Client(Aws::S3::S3Client* s3Client, bool isShared) { m_isUsingSharedS3Client = isShared; m_s3Client = s3Client; } inline void SetSSMClient(Aws::SSM::SSMClient* ssmClient, bool isShared) { m_isUsingSharedSSMClient = isShared; m_ssmClient = ssmClient; } inline void SetCloudFormationClient(Aws::CloudFormation::CloudFormationClient* cfClient, bool isShared) { m_isUsingSharedCfClient = isShared; m_cfClient = cfClient; } inline void SetLambdaClient(Aws::Lambda::LambdaClient* lambdaClient, bool isShared) { m_isUsingSharedLambdaClient = isShared; m_lambdaClient = lambdaClient; } std::string GetStackName() const; void SetLayersReplacementId(const std::string& replacementId); void SetFunctionsReplacementId(const std::string& replacementId); unsigned int ConditionallyCreateOrUpdateFeatureResources(FeatureType targetFeature, const DISPATCH_RECEIVER_HANDLE dispatchReceiver, const CharPtrCallback responseCallback); unsigned int CreateAndSetLayersReplacementId(); unsigned int CreateAndSetFunctionsReplacementId(); unsigned int CompressFeatureLayers(); unsigned int CompressFeatureFunctions(); void CleanupTempFiles(); unsigned int DescribeStackResources(FuncResourceInfoCallback resourceInfoCb) const; unsigned int DescribeStackResources(const DISPATCH_RECEIVER_HANDLE receiver, DispatchedResourceInfoCallback resourceInfoCb) const; unsigned int WriteEmptyClientConfiguration() const; unsigned int WriteClientConfiguration() const; virtual bool IsCloudFormationInstanceTemplatePresent() const; virtual bool AreLayerInstancesPresent() const; virtual bool AreFunctionInstancesPresent() const; virtual unsigned int SaveDeployedCloudFormationTemplate() const; virtual unsigned int GetDeployedCloudFormationParameters(DeployedParametersCallback callback) const; virtual unsigned int SaveCloudFormationInstance(); virtual unsigned int SaveCloudFormationInstance(std::string sourceEngine, std::string pluginVersion); virtual unsigned int UpdateCloudFormationParameters(); virtual unsigned int SaveLayerInstances() const; virtual unsigned int SaveFunctionInstances() const; virtual unsigned int UploadDashboard(const std::string& path); virtual unsigned int UploadFeatureLayers(); virtual unsigned int UploadFeatureFunctions(); virtual unsigned int DeployFeatureLayers(); virtual unsigned int DeployFeatureFunctions(); virtual std::string GetCurrentStackStatus() const; virtual void UpdateDashboardDeployStatus(std::unordered_set<FeatureType> features) const; virtual unsigned int CreateOrUpdateFeatureStack(); virtual unsigned int DeleteFeatureStack(); }; }