Repository: boto/botocore

Issue:
Can not PUT a 0 bytes object when Object Lock is enabled on s3 bucket
When uploading an empty file to an s3 bucket which has object lock enabled:

    An error occurred (InvalidRequest) when calling the PutObject operation: Content-MD5 HTTP header is required for Put Object requests with Object Lock parameters

The API requires this header, but in botocore it does not inject it, I think problem is probably here within the [handler for `before-call.s3.PutObject`](https://github.com/boto/botocore/blame/1aac4d7c1f311826a1a4686e54444f6ded72ea45/botocore/handlers.py#L951):

https://github.com/boto/botocore/blame/1aac4d7c1f311826a1a4686e54444f6ded72ea45/botocore/handlers.py#L187-L196

Look at the if-statement:

    if request_dict['body'] and 'Content-MD5' not in params['headers']:
        # ... the params['headers']['Content-MD5'] gets set ...

It neglects the possibility that `request_dict["body"]` is empty.

For >= 1 bytes files, `content-md5` gets automatically set and upload succeeds.

Discussion:

Patch:
diff --git a/.changes/1.19.19.json b/.changes/1.19.19.json
deleted file mode 100644
index 3669e5582..000000000
--- a/.changes/1.19.19.json
+++ /dev/null
@@ -1,47 +0,0 @@
-[
-  {
-    "category": "``sagemaker``", 
-    "description": "Update sagemaker client to latest version", 
-    "type": "api-change"
-  }, 
-  {
-    "category": "``iotsitewise``", 
-    "description": "Update iotsitewise client to latest version", 
-    "type": "api-change"
-  }, 
-  {
-    "category": "``dms``", 
-    "description": "Update dms client to latest version", 
-    "type": "api-change"
-  }, 
-  {
-    "category": "``iotsecuretunneling``", 
-    "description": "Update iotsecuretunneling client to latest version", 
-    "type": "api-change"
-  }, 
-  {
-    "category": "``sns``", 
-    "description": "Update sns client to latest version", 
-    "type": "api-change"
-  }, 
-  {
-    "category": "``synthetics``", 
-    "description": "Update synthetics client to latest version", 
-    "type": "api-change"
-  }, 
-  {
-    "category": "``servicecatalog``", 
-    "description": "Update servicecatalog client to latest version", 
-    "type": "api-change"
-  }, 
-  {
-    "category": "``codepipeline``", 
-    "description": "Update codepipeline client to latest version", 
-    "type": "api-change"
-  }, 
-  {
-    "category": "``quicksight``", 
-    "description": "Update quicksight client to latest version", 
-    "type": "api-change"
-  }
-]
\ No newline at end of file
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a5cbb4c02..c32a4a5b8 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,20 +2,6 @@
 CHANGELOG
 =========
 
-1.19.19
-=======
-
-* api-change:``sagemaker``: Update sagemaker client to latest version
-* api-change:``iotsitewise``: Update iotsitewise client to latest version
-* api-change:``dms``: Update dms client to latest version
-* api-change:``iotsecuretunneling``: Update iotsecuretunneling client to latest version
-* api-change:``sns``: Update sns client to latest version
-* api-change:``synthetics``: Update synthetics client to latest version
-* api-change:``servicecatalog``: Update servicecatalog client to latest version
-* api-change:``codepipeline``: Update codepipeline client to latest version
-* api-change:``quicksight``: Update quicksight client to latest version
-
-
 1.19.18
 =======
 
diff --git a/botocore/__init__.py b/botocore/__init__.py
index a27f6878d..c2586ce1f 100644
--- a/botocore/__init__.py
+++ b/botocore/__init__.py
@@ -16,7 +16,7 @@ import os
 import re
 import logging
 
-__version__ = '1.19.19'
+__version__ = '1.19.18'
 
 
 class NullHandler(logging.Handler):
diff --git a/botocore/data/codepipeline/2015-07-09/service-2.json b/botocore/data/codepipeline/2015-07-09/service-2.json
index c858dd61d..3ba303bad 100644
--- a/botocore/data/codepipeline/2015-07-09/service-2.json
+++ b/botocore/data/codepipeline/2015-07-09/service-2.json
@@ -493,7 +493,6 @@
       "output":{"shape":"RetryStageExecutionOutput"},
       "errors":[
         {"shape":"ValidationException"},
-        {"shape":"ConflictException"},
         {"shape":"PipelineNotFoundException"},
         {"shape":"StageNotFoundException"},
         {"shape":"StageNotRetryableException"},
@@ -511,7 +510,6 @@
       "output":{"shape":"StartPipelineExecutionOutput"},
       "errors":[
         {"shape":"ValidationException"},
-        {"shape":"ConflictException"},
         {"shape":"PipelineNotFoundException"}
       ],
       "documentation":"<p>Starts the specified pipeline. Specifically, it begins processing the latest commit to the source location specified as part of the pipeline.</p>"
@@ -526,7 +524,6 @@
       "output":{"shape":"StopPipelineExecutionOutput"},
       "errors":[
         {"shape":"ValidationException"},
-        {"shape":"ConflictException"},
         {"shape":"PipelineNotFoundException"},
         {"shape":"PipelineExecutionNotStoppableException"},
         {"shape":"DuplicatedStopRequestException"}
@@ -841,10 +838,6 @@
     "ActionExecution":{
       "type":"structure",
       "members":{
-        "actionExecutionId":{
-          "shape":"ActionExecutionId",
-          "documentation":"<p>ID of the workflow action execution in the current stage. Use the <a>GetPipelineState</a> action to retrieve the current action execution details of the current stage.</p> <note> <p>For older executions, this field might be empty. The action execution ID is available for executions run on or after March 2020.</p> </note>"
-        },
         "status":{
           "shape":"ActionExecutionStatus",
           "documentation":"<p>The status of the action, or for a completed action, the last status of the action.</p>"
@@ -1155,11 +1148,11 @@
       "members":{
         "category":{
           "shape":"ActionCategory",
-          "documentation":"<p>A category defines what kind of action can be taken in the stage, and constrains the provider type for the action. Valid categories are limited to one of the following values. </p> <ul> <li> <p>Source</p> </li> <li> <p>Build</p> </li> <li> <p>Test</p> </li> <li> <p>Deploy</p> </li> <li> <p>Invoke</p> </li> <li> <p>Approval</p> </li> </ul>"
+          "documentation":"<p>A category defines what kind of action can be taken in the stage, and constrains the provider type for the action. Valid categories are limited to one of the following values. </p>"
         },
         "owner":{
           "shape":"ActionOwner",
-          "documentation":"<p>The creator of the action being called. There are three valid values for the <code>Owner</code> field in the action category section within your pipeline structure: <code>AWS</code>, <code>ThirdParty</code>, and <code>Custom</code>. For more information, see <a href=\"https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#actions-valid-providers\">Valid Action Types and Providers in CodePipeline</a>.</p>"
+          "documentation":"<p>The creator of the action being called.</p>"
         },
         "provider":{
           "shape":"ActionProvider",
@@ -1451,14 +1444,6 @@
       "documentation":"<p>Unable to modify the tag due to a simultaneous update request.</p>",
       "exception":true
     },
-    "ConflictException":{
-      "type":"structure",
-      "members":{
-        "message":{"shape":"Message"}
-      },
-      "documentation":"<p>Your request cannot be handled because the pipeline is busy handling ongoing activities. Try again later.</p>",
-      "exception":true
-    },
     "ContinuationToken":{
       "type":"string",
       "max":2048,
@@ -1476,7 +1461,7 @@
       "members":{
         "category":{
           "shape":"ActionCategory",
-          "documentation":"<p>The category of the custom action, such as a build action or a test action.</p>"
+          "documentation":"<p>The category of the custom action, such as a build action or a test action.</p> <note> <p>Although <code>Source</code> and <code>Approval</code> are listed as valid values, they are not currently functional. These values are reserved for future use.</p> </note>"
         },
         "provider":{
           "shape":"ActionProvider",
@@ -1733,7 +1718,7 @@
     },
     "EncryptionKeyId":{
       "type":"string",
-      "max":400,
+      "max":100,
       "min":1
     },
     "EncryptionKeyType":{
@@ -2549,7 +2534,7 @@
       "members":{
         "name":{
           "shape":"PipelineName",
-          "documentation":"<p>The name of the pipeline.</p>"
+          "documentation":"<p>The name of the action to be performed.</p>"
         },
         "roleArn":{
           "shape":"RoleArn",
@@ -3274,7 +3259,6 @@
           "shape":"StageName",
           "documentation":"<p>The name of the stage.</p>"
         },
-        "inboundExecution":{"shape":"StageExecution"},
         "inboundTransitionState":{
           "shape":"TransitionState",
           "documentation":"<p>The state of the inbound transition, which is either enabled or disabled.</p>"
diff --git a/botocore/data/dms/2016-01-01/service-2.json b/botocore/data/dms/2016-01-01/service-2.json
index abc8a2f3b..5e6a541c2 100644
--- a/botocore/data/dms/2016-01-01/service-2.json
+++ b/botocore/data/dms/2016-01-01/service-2.json
@@ -67,8 +67,7 @@
         {"shape":"ResourceQuotaExceededFault"},
         {"shape":"InvalidResourceStateFault"},
         {"shape":"ResourceNotFoundFault"},
-        {"shape":"AccessDeniedFault"},
-        {"shape":"S3AccessDeniedFault"}
+        {"shape":"AccessDeniedFault"}
       ],
       "documentation":"<p>Creates an endpoint using the provided settings.</p>"
     },
@@ -649,21 +648,6 @@
       ],
       "documentation":"<p>Modifies the specified replication task.</p> <p>You can't modify the task endpoints. The task must be stopped before you can modify it. </p> <p>For more information about AWS DMS tasks, see <a href=\"https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.html\">Working with Migration Tasks</a> in the <i>AWS Database Migration Service User Guide</i>.</p>"
     },
-    "MoveReplicationTask":{
-      "name":"MoveReplicationTask",
-      "http":{
-        "method":"POST",
-        "requestUri":"/"
-      },
-      "input":{"shape":"MoveReplicationTaskMessage"},
-      "output":{"shape":"MoveReplicationTaskResponse"},
-      "errors":[
-        {"shape":"AccessDeniedFault"},
-        {"shape":"InvalidResourceStateFault"},
-        {"shape":"ResourceNotFoundFault"}
-      ],
-      "documentation":"<p>Moves a replication task from its current replication instance to a different target replication instance using the specified parameters. The target replication instance must be created with the same or later AWS DMS version as the current replication instance.</p>"
-    },
     "RebootReplicationInstance":{
       "name":"RebootReplicationInstance",
       "http":{
@@ -3441,34 +3425,6 @@
       },
       "documentation":"<p>Provides information that defines a MongoDB endpoint.</p>"
     },
-    "MoveReplicationTaskMessage":{
-      "type":"structure",
-      "required":[
-        "ReplicationTaskArn",
-        "TargetReplicationInstanceArn"
-      ],
-      "members":{
-        "ReplicationTaskArn":{
-          "shape":"String",
-          "documentation":"<p>The Amazon Resource Name (ARN) of the task that you want to move.</p>"
-        },
-        "TargetReplicationInstanceArn":{
-          "shape":"String",
-          "documentation":"<p>The ARN of the replication instance where you want to move the task to.</p>"
-        }
-      },
-      "documentation":"<p/>"
-    },
-    "MoveReplicationTaskResponse":{
-      "type":"structure",
-      "members":{
-        "ReplicationTask":{
-          "shape":"ReplicationTask",
-          "documentation":"<p>The replication task that was moved.</p>"
-        }
-      },
-      "documentation":"<p/>"
-    },
     "MySQLSettings":{
       "type":"structure",
       "members":{
@@ -4316,15 +4272,15 @@
         },
         "SourceEndpointArn":{
           "shape":"String",
-          "documentation":"<p>The Amazon Resource Name (ARN) that uniquely identifies the endpoint.</p>"
+          "documentation":"<p>The Amazon Resource Name (ARN) string that uniquely identifies the endpoint.</p>"
         },
         "TargetEndpointArn":{
           "shape":"String",
-          "documentation":"<p>The ARN that uniquely identifies the endpoint.</p>"
+          "documentation":"<p>The Amazon Resource Name (ARN) string that uniquely identifies the endpoint.</p>"
         },
         "ReplicationInstanceArn":{
           "shape":"String",
-          "documentation":"<p>The ARN of the replication instance.</p>"
+          "documentation":"<p>The Amazon Resource Name (ARN) of the replication instance.</p>"
         },
         "MigrationType":{
           "shape":"MigrationTypeValue",
@@ -4340,7 +4296,7 @@
         },
         "Status":{
           "shape":"String",
-          "documentation":"<p>The status of the replication task. This response parameter can return one of the following values:</p> <ul> <li> <p> <code>\"moving\"</code> – The task is being moved in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_MoveReplicationTask.html\"> <code>MoveReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"creating\"</code> – The task is being created in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_CreateReplicationTask.html\"> <code>CreateReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"deleting\"</code> – The task is being deleted in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_DeleteReplicationTask.html\"> <code>DeleteReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"failed\"</code> – The task failed to successfully complete the database migration in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTask.html\"> <code>StartReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"failed-move\"</code> – The task failed to move in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_MoveReplicationTask.html\"> <code>MoveReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"modifying\"</code> – The task definition is being modified in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_ModifyReplicationTask.html\"> <code>ModifyReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"ready\"</code> – The task is in a <code>ready</code> state where it can respond to other task operations, such as <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTask.html\"> <code>StartReplicationTask</code> </a> or <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_DeleteReplicationTask.html\"> <code>DeleteReplicationTask</code> </a>. </p> </li> <li> <p> <code>\"running\"</code> – The task is performing a database migration in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTask.html\"> <code>StartReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"starting\"</code> – The task is preparing to perform a database migration in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTask.html\"> <code>StartReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"stopped\"</code> – The task has stopped in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StopReplicationTask.html\"> <code>StopReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"stopping\"</code> – The task is preparing to stop in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StopReplicationTask.html\"> <code>StopReplicationTask</code> </a> operation.</p> </li> <li> <p> <code>\"testing\"</code> – The database migration specified for this task is being tested in response to running either the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTaskAssessmentRun.html\"> <code>StartReplicationTaskAssessmentRun</code> </a> or the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTaskAssessment.html\"> <code>StartReplicationTaskAssessment</code> </a> operation.</p> <note> <p> <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTaskAssessmentRun.html\"> <code>StartReplicationTaskAssessmentRun</code> </a> is an improved premigration task assessment operation. The <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTaskAssessment.html\"> <code>StartReplicationTaskAssessment</code> </a> operation assesses data type compatibility only between the source and target database of a given migration task. In contrast, <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_StartReplicationTaskAssessmentRun.html\"> <code>StartReplicationTaskAssessmentRun</code> </a> enables you to specify a variety of premigration task assessments in addition to data type compatibility. These assessments include ones for the validity of primary key definitions and likely issues with database migration performance, among others.</p> </note> </li> </ul>"
+          "documentation":"<p>The status of the replication task.</p>"
         },
         "LastFailureMessage":{
           "shape":"String",
@@ -4348,7 +4304,7 @@
         },
         "StopReason":{
           "shape":"String",
-          "documentation":"<p>The reason the replication task was stopped. This response parameter can return one of the following values:</p> <ul> <li> <p> <code>\"STOP_REASON_FULL_LOAD_COMPLETED\"</code> – Full-load migration completed.</p> </li> <li> <p> <code>\"STOP_REASON_CACHED_CHANGES_APPLIED\"</code> – Change data capture (CDC) load completed.</p> </li> <li> <p> <code>\"STOP_REASON_CACHED_CHANGES_NOT_APPLIED\"</code> – In a full-load and CDC migration, the full load stopped as specified before starting the CDC migration.</p> </li> <li> <p> <code>\"STOP_REASON_SERVER_TIME\"</code> – The migration stopped at the specified server time.</p> </li> </ul>"
+          "documentation":"<p>The reason the replication task was stopped. This response parameter can return one of the following values:</p> <ul> <li> <p> <code>\"STOP_REASON_FULL_LOAD_COMPLETED\"</code> – Full-load migration completed.</p> </li> <li> <p> <code>\"STOP_REASON_CACHED_CHANGES_APPLIED\"</code> – Change data capture (CDC) load completed.</p> </li> <li> <p> <code>\"STOP_REASON_CACHED_CHANGES_NOT_APPLIED\"</code> – In a full-load and CDC migration, the full-load stopped as specified before starting the CDC migration.</p> </li> <li> <p> <code>\"STOP_REASON_SERVER_TIME\"</code> – The migration stopped at the specified server time.</p> </li> </ul>"
         },
         "ReplicationTaskCreationDate":{
           "shape":"TStamp",
@@ -4381,10 +4337,6 @@
         "TaskData":{
           "shape":"String",
           "documentation":"<p>Supplemental information that the task requires to migrate the data for certain source and target endpoints. For more information, see <a href=\"https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.TaskData.html\">Specifying Supplemental Data for Task Settings</a> in the <i>AWS Database Migration Service User Guide.</i> </p>"
-        },
-        "TargetReplicationInstanceArn":{
-          "shape":"String",
-          "documentation":"<p>The ARN of the replication instance to which this task is moved in response to running the <a href=\"https://docs.aws.amazon.com/dms/latest/APIReference/API_MoveReplicationTask.html\"> <code>MoveReplicationTask</code> </a> operation. Otherwise, this response parameter isn't a member of the <code>ReplicationTask</code> object.</p>"
         }
       },
       "documentation":"<p>Provides information that describes a replication task created by the <code>CreateReplicationTask</code> operation.</p>"
diff --git a/botocore/data/iotsecuretunneling/2018-10-05/service-2.json b/botocore/data/iotsecuretunneling/2018-10-05/service-2.json
index 622d36f63..effc6f031 100644
--- a/botocore/data/iotsecuretunneling/2018-10-05/service-2.json
+++ b/botocore/data/iotsecuretunneling/2018-10-05/service-2.json
@@ -73,7 +73,7 @@
       "errors":[
         {"shape":"LimitExceededException"}
       ],
-      "documentation":"<p>Creates a new tunnel, and returns two client access tokens for clients to use to connect to the AWS IoT Secure Tunneling proxy server.</p>"
+      "documentation":"<p>Creates a new tunnel, and returns two client access tokens for clients to use to connect to the AWS IoT Secure Tunneling proxy server. .</p>"
     },
     "TagResource":{
       "name":"TagResource",
@@ -180,7 +180,10 @@
     },
     "DestinationConfig":{
       "type":"structure",
-      "required":["services"],
+      "required":[
+        "thingName",
+        "services"
+      ],
       "members":{
         "thingName":{
           "shape":"ThingName",
@@ -188,7 +191,7 @@
         },
         "services":{
           "shape":"ServiceList",
-          "documentation":"<p>A list of service names that identity the target application. The AWS IoT client running on the destination device reads this value and uses it to look up a port or an IP address and a port. The AWS IoT client instantiates the local proxy which uses this information to connect to the destination application.</p>"
+          "documentation":"<p>A list of service names that identity the target application. Currently, you can only specify a single name. The AWS IoT client running on the destination device reads this value and uses it to look up a port or an IP address and a port. The AWS IoT client instantiates the local proxy which uses this information to connect to the destination application.</p>"
         }
       },
       "documentation":"<p>The destination configuration.</p>"
@@ -313,13 +316,14 @@
     },
     "Service":{
       "type":"string",
-      "max":128,
+      "max":8,
       "min":1,
       "pattern":"[a-zA-Z0-9:_-]+"
     },
     "ServiceList":{
       "type":"list",
       "member":{"shape":"Service"},
+      "max":1,
       "min":1
     },
     "Tag":{
@@ -531,5 +535,5 @@
       }
     }
   },
-  "documentation":"<fullname>AWS IoT Secure Tunneling</fullname> <p>AWS IoT Secure Tunnling enables you to create remote connections to devices deployed in the field.</p> <p>For more information about how AWS IoT Secure Tunneling works, see <a href=\"https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling.html\">AWS IoT Secure Tunneling</a>.</p>"
+  "documentation":"<fullname>AWS IoT Secure Tunneling</fullname> <p>AWS IoT Secure Tunnling enables you to create remote connections to devices deployed in the field.</p> <p>For more information about how AWS IoT Secure Tunneling works, see the <a href=\"https://docs.aws.amazon.com/secure-tunneling/latest/ug/what-is-secure-tunneling.html\">User Guide</a>.</p>"
 }
diff --git a/botocore/data/iotsitewise/2019-12-02/service-2.json b/botocore/data/iotsitewise/2019-12-02/service-2.json
index 3b4248128..6c5db160b 100644
--- a/botocore/data/iotsitewise/2019-12-02/service-2.json
+++ b/botocore/data/iotsitewise/2019-12-02/service-2.json
@@ -205,23 +205,6 @@
       "documentation":"<p>Creates a portal, which can contain projects and dashboards. AWS IoT SiteWise Monitor uses AWS SSO or IAM to authenticate portal users and manage user permissions.</p> <note> <p>Before you can sign in to a new portal, you must add at least one identity to that portal. For more information, see <a href=\"https://docs.aws.amazon.com/iot-sitewise/latest/userguide/administer-portals.html#portal-change-admins\">Adding or removing portal administrators</a> in the <i>AWS IoT SiteWise User Guide</i>.</p> </note>",
       "endpoint":{"hostPrefix":"monitor."}
     },
-    "CreatePresignedPortalUrl":{
-      "name":"CreatePresignedPortalUrl",
-      "http":{
-        "method":"GET",
-        "requestUri":"/portals/{portalId}/presigned-url",
-        "responseCode":200
-      },
-      "input":{"shape":"CreatePresignedPortalUrlRequest"},
-      "output":{"shape":"CreatePresignedPortalUrlResponse"},
-      "errors":[
-        {"shape":"InvalidRequestException"},
-        {"shape":"InternalFailureException"},
-        {"shape":"ThrottlingException"}
-      ],
-      "documentation":"<p>Creates a pre-signed URL to a portal. Use this operation to create URLs to portals that use AWS Identity and Access Management (IAM) to authenticate users. An IAM user with access to a portal can call this API to get a URL to that portal. The URL contains a session token that lets the IAM user access the portal.</p>",
-      "endpoint":{"hostPrefix":"monitor."}
-    },
     "CreateProject":{
       "name":"CreateProject",
       "http":{
@@ -2131,34 +2114,6 @@
         }
       }
     },
-    "CreatePresignedPortalUrlRequest":{
-      "type":"structure",
-      "required":["portalId"],
-      "members":{
-        "portalId":{
-          "shape":"ID",
-          "documentation":"<p>The ID of the portal to access.</p>",
-          "location":"uri",
-          "locationName":"portalId"
-        },
-        "sessionDurationSeconds":{
-          "shape":"SessionDurationSeconds",
-          "documentation":"<p>The duration (in seconds) for which the session at the URL is valid.</p> <p>Default: 900 seconds (15 minutes)</p>",
-          "location":"querystring",
-          "locationName":"sessionDurationSeconds"
-        }
-      }
-    },
-    "CreatePresignedPortalUrlResponse":{
-      "type":"structure",
-      "required":["presignedPortalUrl"],
-      "members":{
-        "presignedPortalUrl":{
-          "shape":"Url",
-          "documentation":"<p>The pre-signed URL to the portal. The URL contains the portal ID and a session token that lets you access the portal. The URL has the following format.</p> <p> <code>https://&lt;portal-id&gt;.app.iotsitewise.aws/auth?token=&lt;encrypted-token&gt;</code> </p>"
-        }
-      }
-    },
     "CreateProjectRequest":{
       "type":"structure",
       "required":[
@@ -3037,7 +2992,8 @@
     "Expression":{
       "type":"string",
       "max":1024,
-      "min":1
+      "min":1,
+      "pattern":"^[a-z0-9._+\\-*%/^, ()]+$"
     },
     "ExpressionVariable":{
       "type":"structure",
@@ -4389,11 +4345,6 @@
       "exception":true,
       "fault":true
     },
-    "SessionDurationSeconds":{
-      "type":"integer",
-      "max":43200,
-      "min":900
-    },
     "TagKey":{
       "type":"string",
       "max":128,
diff --git a/botocore/data/quicksight/2018-04-01/service-2.json b/botocore/data/quicksight/2018-04-01/service-2.json
index d2e7de23d..719f97839 100644
--- a/botocore/data/quicksight/2018-04-01/service-2.json
+++ b/botocore/data/quicksight/2018-04-01/service-2.json
@@ -6088,23 +6088,17 @@
           "locationName":"session-lifetime"
         },
         "UndoRedoDisabled":{
-          "shape":"Boolean",
+          "shape":"boolean",
           "documentation":"<p>Remove the undo/redo button on the embedded dashboard. The default is FALSE, which enables the undo/redo button.</p>",
           "location":"querystring",
           "locationName":"undo-redo-disabled"
         },
         "ResetDisabled":{
-          "shape":"Boolean",
+          "shape":"boolean",
           "documentation":"<p>Remove the reset button on the embedded dashboard. The default is FALSE, which enables the reset button.</p>",
           "location":"querystring",
           "locationName":"reset-disabled"
         },
-        "StatePersistenceEnabled":{
-          "shape":"Boolean",
-          "documentation":"<p>Adds persistence of state for the user session in an embedded dashboard. Persistence applies to the sheet and the parameter settings. These are control settings that the dashboard subscriber (QuickSight reader) chooses while viewing the dashboard. If this is set to <code>TRUE</code>, the settings are the same when the the subscriber reopens the same dashboard URL. The state is stored in QuickSight, not in a browser cookie. If this is set to FALSE, the state of the user session is not persisted. The default is <code>FALSE</code>.</p>",
-          "location":"querystring",
-          "locationName":"state-persistence-enabled"
-        },
         "UserArn":{
           "shape":"Arn",
           "documentation":"<p>The Amazon QuickSight user's Amazon Resource Name (ARN), for use with <code>QUICKSIGHT</code> identity type. You can use this for any Amazon QuickSight users in your account (readers, authors, or admins) authenticated as one of the following:</p> <ul> <li> <p>Active Directory (AD) users or group members</p> </li> <li> <p>Invited nonfederated users</p> </li> <li> <p>IAM users and IAM role-based sessions authenticated through Federated Single Sign-On using SAML, OpenID Connect, or IAM federation.</p> </li> </ul> <p>Omit this parameter for users in the third group – IAM users and IAM role-based sessions.</p>",
@@ -7962,8 +7956,7 @@
           "shape":"Database",
           "documentation":"<p>Database.</p>"
         }
-      },
-      "documentation":"<p>Oracle parameters.</p>"
+      }
     },
     "OutputColumn":{
       "type":"structure",
diff --git a/botocore/data/sagemaker/2017-07-24/service-2.json b/botocore/data/sagemaker/2017-07-24/service-2.json
index 1cdd96b46..8ed720837 100644
--- a/botocore/data/sagemaker/2017-07-24/service-2.json
+++ b/botocore/data/sagemaker/2017-07-24/service-2.json
@@ -73,7 +73,7 @@
       "errors":[
         {"shape":"ResourceInUse"}
       ],
-      "documentation":"<p>Creates a configuration for running a SageMaker image as a KernelGateway app. The configuration specifies the Amazon Elastic File System (EFS) storage volume on the image, and a list of the kernels in the image.</p>"
+      "documentation":"<p>Creates a configuration for running an Amazon SageMaker image as a KernelGateway app.</p>"
     },
     "CreateAutoMLJob":{
       "name":"CreateAutoMLJob",
@@ -138,7 +138,7 @@
       "errors":[
         {"shape":"ResourceLimitExceeded"}
       ],
-      "documentation":"<p>Creates an endpoint using the endpoint configuration specified in the request. Amazon SageMaker uses the endpoint to provision resources and deploy models. You create the endpoint configuration with the <a>CreateEndpointConfig</a> API. </p> <p> Use this API to deploy models using Amazon SageMaker hosting services. </p> <p>For an example that calls this method when deploying a model to Amazon SageMaker hosting services, see <a href=\"https://docs.aws.amazon.com/sagemaker/latest/dg/ex1-deploy-model.html#ex1-deploy-model-boto\">Deploy the Model to Amazon SageMaker Hosting Services (AWS SDK for Python (Boto 3)).</a> </p> <note> <p> You must not delete an <code>EndpointConfig</code> that is in use by an endpoint that is live or while the <code>UpdateEndpoint</code> or <code>CreateEndpoint</code> operations are being performed on the endpoint. To update an endpoint, you must create a new <code>EndpointConfig</code>.</p> </note> <p>The endpoint name must be unique within an AWS Region in your AWS account. </p> <p>When it receives the request, Amazon SageMaker creates the endpoint, launches the resources (ML compute instances), and deploys the model(s) on them. </p> <note> <p>When you call <a>CreateEndpoint</a>, a load call is made to DynamoDB to verify that your endpoint configuration exists. When you read data from a DynamoDB table supporting <a href=\"https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html\"> <code>Eventually Consistent Reads</code> </a>, the response might not reflect the results of a recently completed write operation. The response might include some stale data. If the dependent entities are not yet in DynamoDB, this causes a validation error. If you repeat your read request after a short time, the response should return the latest data. So retry logic is recommended to handle these possible issues. We also recommend that customers call <a>DescribeEndpointConfig</a> before calling <a>CreateEndpoint</a> to minimize the potential impact of a DynamoDB eventually consistent read.</p> </note> <p>When Amazon SageMaker receives the request, it sets the endpoint status to <code>Creating</code>. After it creates the endpoint, it sets the status to <code>InService</code>. Amazon SageMaker can then process incoming requests for inferences. To check the status of an endpoint, use the <a>DescribeEndpoint</a> API.</p> <p>If any of the models hosted at this endpoint get model data from an Amazon S3 location, Amazon SageMaker uses AWS Security Token Service to download model artifacts from the S3 path you provided. AWS STS is activated in your IAM user account by default. If you previously deactivated AWS STS for a region, you need to reactivate AWS STS for that region. For more information, see <a href=\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html\">Activating and Deactivating AWS STS in an AWS Region</a> in the <i>AWS Identity and Access Management User Guide</i>.</p> <note> <p> To add the IAM role policies for using this API operation, go to the <a href=\"https://console.aws.amazon.com/iam/\">IAM console</a>, and choose Roles in the left navigation pane. Search the IAM role that you want to grant access to use the <a>CreateEndpoint</a> and <a>CreateEndpointConfig</a> API operations, add the following policies to the role. </p> <ul> <li> <p>Option 1: For a full Amazon SageMaker access, search and attach the <code>AmazonSageMakerFullAccess</code> policy.</p> </li> <li> <p>Option 2: For granting a limited access to an IAM role, paste the following Action elements manually into the JSON file of the IAM role: </p> <p> <code>\"Action\": [\"sagemaker:CreateEndpoint\", \"sagemaker:CreateEndpointConfig\"]</code> </p> <p> <code>\"Resource\": [</code> </p> <p> <code>\"arn:aws:sagemaker:region:account-id:endpoint/endpointName\"</code> </p> <p> <code>\"arn:aws:sagemaker:region:account-id:endpoint-config/endpointConfigName\"</code> </p> <p> <code>]</code> </p> <p>For more information, see <a href=\"https://docs.aws.amazon.com/sagemaker/latest/dg/api-permissions-reference.html\">Amazon SageMaker API Permissions: Actions, Permissions, and Resources Reference</a>.</p> </li> </ul> </note>"
+      "documentation":"<p>Creates an endpoint using the endpoint configuration specified in the request. Amazon SageMaker uses the endpoint to provision resources and deploy models. You create the endpoint configuration with the <a>CreateEndpointConfig</a> API. </p> <p> Use this API to deploy models using Amazon SageMaker hosting services. </p> <p>For an example that calls this method when deploying a model to Amazon SageMaker hosting services, see <a href=\"https://docs.aws.amazon.com/sagemaker/latest/dg/ex1-deploy-model.html#ex1-deploy-model-boto\">Deploy the Model to Amazon SageMaker Hosting Services (AWS SDK for Python (Boto 3)).</a> </p> <note> <p> You must not delete an <code>EndpointConfig</code> that is in use by an endpoint that is live or while the <code>UpdateEndpoint</code> or <code>CreateEndpoint</code> operations are being performed on the endpoint. To update an endpoint, you must create a new <code>EndpointConfig</code>.</p> </note> <p>The endpoint name must be unique within an AWS Region in your AWS account. </p> <p>When it receives the request, Amazon SageMaker creates the endpoint, launches the resources (ML compute instances), and deploys the model(s) on them. </p> <note> <p>When you call <a>CreateEndpoint</a>, a load call is made to DynamoDB to verify that your endpoint configuration exists. When you read data from a DynamoDB table supporting <a href=\"https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html\"> <code>Eventually Consistent Reads</code> </a>, the response might not reflect the results of a recently completed write operation. The response might include some stale data. If the dependent entities are not yet in DynamoDB, this causes a validation error. If you repeat your read request after a short time, the response should return the latest data. So retry logic is recommended to handle these possible issues. We also recommend that customers call <a>DescribeEndpointConfig</a> before calling <a>CreateEndpoint</a> to minimize the potential impact of a DynamoDB eventually consistent read.</p> </note> <p>When Amazon SageMaker receives the request, it sets the endpoint status to <code>Creating</code>. After it creates the endpoint, it sets the status to <code>InService</code>. Amazon SageMaker can then process incoming requests for inferences. To check the status of an endpoint, use the <a>DescribeEndpoint</a> API.</p> <p>If any of the models hosted at this endpoint get model data from an Amazon S3 location, Amazon SageMaker uses AWS Security Token Service to download model artifacts from the S3 path you provided. AWS STS is activated in your IAM user account by default. If you previously deactivated AWS STS for a region, you need to reactivate AWS STS for that region. For more information, see <a href=\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html\">Activating and Deactivating AWS STS in an AWS Region</a> in the <i>AWS Identity and Access Management User Guide</i>.</p>"
     },
     "CreateEndpointConfig":{
       "name":"CreateEndpointConfig",
@@ -220,7 +220,7 @@
         {"shape":"ResourceInUse"},
         {"shape":"ResourceLimitExceeded"}
       ],
-      "documentation":"<p>Creates a custom SageMaker image. A SageMaker image is a set of image versions. Each image version represents a container image stored in Amazon Container Registry (ECR). For more information, see <a href=\"https://docs.aws.amazon.com/sagemaker/latest/dg/studio-byoi.html\">Bring your own SageMaker image</a>.</p>"
+      "documentation":"<p>Creates a SageMaker <code>Image</code>. A SageMaker image represents a set of container images. Each of these container images is represented by a SageMaker <code>ImageVersion</code>.</p>"
     },
     "CreateImageVersion":{
       "name":"CreateImageVersion",
@@ -2093,7 +2093,7 @@
         },
         "AppImageConfigName":{
           "shape":"AppImageConfigName",
-          "documentation":"<p>The name of the AppImageConfig. Must be unique to your account.</p>"
+          "documentation":"<p>The name of the AppImageConfig.</p>"
         },
         "CreationTime":{
           "shape":"Timestamp",
@@ -2105,10 +2105,10 @@
         },
         "KernelGatewayImageConfig":{
           "shape":"KernelGatewayImageConfig",
-          "documentation":"<p>The configuration for the file system and kernels in the SageMaker image.</p>"
+          "documentation":"<p>The KernelGateway app.</p>"
         }
       },
-      "documentation":"<p>The configuration for running a SageMaker image as a KernelGateway app.</p>"
+      "documentation":"<p>The configuration for running an Amazon SageMaker image as a KernelGateway app.</p>"
     },
     "AppImageConfigList":{
       "type":"list",
@@ -3676,13 +3676,7 @@
         },
         "HomeEfsFileSystemKmsKeyId":{
           "shape":"KmsKeyId",
-          "documentation":"<p>This member is deprecated and replaced with <code>KmsKeyId</code>.</p>",
-          "deprecated":true,
-          "deprecatedMessage":"This property is deprecated, use KmsKeyId instead."
-        },
-        "KmsKeyId":{
-          "shape":"KmsKeyId",
-          "documentation":"<p>SageMaker uses AWS KMS to encrypt the EFS volume attached to the domain with an AWS managed customer master key (CMK) by default. For more control, specify a customer managed CMK.</p>"
+          "documentation":"<p>The AWS Key Management Service (KMS) encryption key ID. Encryption with a customer master key (CMK) is not supported.</p>"
         }
       }
     },
@@ -3930,7 +3924,7 @@
         },
         "DisplayName":{
           "shape":"ImageDisplayName",
-          "documentation":"<p>The display name of the image. If not provided, <code>ImageName</code> is displayed.</p>"
+          "documentation":"<p>The display name of the image. When the image is added to a domain, <code>DisplayName</code> must be unique to the domain.</p>"
         },
         "ImageName":{
           "shape":"ImageName",
@@ -4778,7 +4772,7 @@
           "documentation":"<p>The name of the AppImageConfig.</p>"
         }
       },
-      "documentation":"<p>A custom SageMaker image. For more information, see <a href=\"https://docs.aws.amazon.com/sagemaker/latest/dg/studio-byoi.html\">Bring your own SageMaker image</a>.</p>"
+      "documentation":"<p>A custom image.</p>"
     },
     "CustomImages":{
       "type":"list",
@@ -5463,7 +5457,7 @@
         },
         "KernelGatewayImageConfig":{
           "shape":"KernelGatewayImageConfig",
-          "documentation":"<p>The configuration of a KernelGateway app.</p>"
+          "documentation":"<p>The KernelGateway app.</p>"
         }
       }
     },
@@ -5817,7 +5811,7 @@
         },
         "DefaultUserSettings":{
           "shape":"UserSettings",
-          "documentation":"<p>Settings which are applied to all UserProfiles in this domain, if settings are not explicitly specified in a given UserProfile. </p>"
+          "documentation":"<p>Settings which are applied to all UserProfile in this domain, if settings are not explicitly specified in a given UserProfile. </p>"
         },
         "AppNetworkAccessType":{
           "shape":"AppNetworkAccessType",
@@ -5825,9 +5819,7 @@
         },
         "HomeEfsFileSystemKmsKeyId":{
           "shape":"KmsKeyId",
-          "documentation":"<p>This member is deprecated and replaced with <code>KmsKeyId</code>.</p>",
-          "deprecated":true,
-          "deprecatedMessage":"This property is deprecated, use KmsKeyId instead."
+          "documentation":"<p>The AWS Key Management Service encryption key ID.</p>"
         },
         "SubnetIds":{
           "shape":"Subnets",
@@ -5840,10 +5832,6 @@
         "VpcId":{
           "shape":"VpcId",
           "documentation":"<p>The ID of the Amazon Virtual Private Cloud (VPC) that Studio uses for communication.</p>"
-        },
-        "KmsKeyId":{
-          "shape":"KmsKeyId",
-          "documentation":"<p>The AWS KMS customer managed CMK used to encrypt the EFS volume attached to the domain.</p>"
         }
       }
     },
@@ -7808,16 +7796,16 @@
         },
         "DefaultUid":{
           "shape":"DefaultUid",
-          "documentation":"<p>The default POSIX user ID (UID). If not specified, defaults to <code>1000</code>.</p>",
+          "documentation":"<p>The default POSIX user ID. If not specified, defaults to <code>1000</code>.</p>",
           "box":true
         },
         "DefaultGid":{
           "shape":"DefaultGid",
-          "documentation":"<p>The default POSIX group ID (GID). If not specified, defaults to <code>100</code>.</p>",
+          "documentation":"<p>The default POSIX group ID. If not specified, defaults to <code>100</code>.</p>",
           "box":true
         }
       },
-      "documentation":"<p>The Amazon Elastic File System (EFS) storage configuration for a SageMaker image.</p>"
+      "documentation":"<p>The Amazon Elastic File System (EFS) storage configuration for an image.</p>"
     },
     "FileSystemDataSource":{
       "type":"structure",
@@ -9025,7 +9013,7 @@
         },
         "DataInputConfig":{
           "shape":"DataInputConfig",
-          "documentation":"<p>Specifies the name and shape of the expected data inputs for your trained model with a JSON dictionary form. The data inputs are <a>InputConfig$Framework</a> specific. </p> <ul> <li> <p> <code>TensorFlow</code>: You must specify the name and shape (NHWC format) of the expected data inputs using a dictionary format for your trained model. The dictionary formats required for the console and CLI are different.</p> <ul> <li> <p>Examples for one input:</p> <ul> <li> <p>If using the console, <code>{\"input\":[1,1024,1024,3]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input\\\":[1,1024,1024,3]}</code> </p> </li> </ul> </li> <li> <p>Examples for two inputs:</p> <ul> <li> <p>If using the console, <code>{\"data1\": [1,28,28,1], \"data2\":[1,28,28,1]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"data1\\\": [1,28,28,1], \\\"data2\\\":[1,28,28,1]}</code> </p> </li> </ul> </li> </ul> </li> <li> <p> <code>KERAS</code>: You must specify the name and shape (NCHW format) of expected data inputs using a dictionary format for your trained model. Note that while Keras model artifacts should be uploaded in NHWC (channel-last) format, <code>DataInputConfig</code> should be specified in NCHW (channel-first) format. The dictionary formats required for the console and CLI are different.</p> <ul> <li> <p>Examples for one input:</p> <ul> <li> <p>If using the console, <code>{\"input_1\":[1,3,224,224]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input_1\\\":[1,3,224,224]}</code> </p> </li> </ul> </li> <li> <p>Examples for two inputs:</p> <ul> <li> <p>If using the console, <code>{\"input_1\": [1,3,224,224], \"input_2\":[1,3,224,224]} </code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input_1\\\": [1,3,224,224], \\\"input_2\\\":[1,3,224,224]}</code> </p> </li> </ul> </li> </ul> </li> <li> <p> <code>MXNET/ONNX/DARKNET</code>: You must specify the name and shape (NCHW format) of the expected data inputs in order using a dictionary format for your trained model. The dictionary formats required for the console and CLI are different.</p> <ul> <li> <p>Examples for one input:</p> <ul> <li> <p>If using the console, <code>{\"data\":[1,3,1024,1024]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"data\\\":[1,3,1024,1024]}</code> </p> </li> </ul> </li> <li> <p>Examples for two inputs:</p> <ul> <li> <p>If using the console, <code>{\"var1\": [1,1,28,28], \"var2\":[1,1,28,28]} </code> </p> </li> <li> <p>If using the CLI, <code>{\\\"var1\\\": [1,1,28,28], \\\"var2\\\":[1,1,28,28]}</code> </p> </li> </ul> </li> </ul> </li> <li> <p> <code>PyTorch</code>: You can either specify the name and shape (NCHW format) of expected data inputs in order using a dictionary format for your trained model or you can specify the shape only using a list format. The dictionary formats required for the console and CLI are different. The list formats for the console and CLI are the same.</p> <ul> <li> <p>Examples for one input in dictionary format:</p> <ul> <li> <p>If using the console, <code>{\"input0\":[1,3,224,224]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input0\\\":[1,3,224,224]}</code> </p> </li> </ul> </li> <li> <p>Example for one input in list format: <code>[[1,3,224,224]]</code> </p> </li> <li> <p>Examples for two inputs in dictionary format:</p> <ul> <li> <p>If using the console, <code>{\"input0\":[1,3,224,224], \"input1\":[1,3,224,224]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input0\\\":[1,3,224,224], \\\"input1\\\":[1,3,224,224]} </code> </p> </li> </ul> </li> <li> <p>Example for two inputs in list format: <code>[[1,3,224,224], [1,3,224,224]]</code> </p> </li> </ul> </li> <li> <p> <code>XGBOOST</code>: input data name and shape are not needed.</p> </li> </ul> <p> <code>DataInputConfig</code> supports the following parameters for <code>CoreML</code> <a>OutputConfig$TargetDevice</a> (ML Model format):</p> <ul> <li> <p> <code>shape</code>: Input shape, for example <code>{\"input_1\": {\"shape\": [1,224,224,3]}}</code>. In addition to static input shapes, CoreML converter supports Flexible input shapes:</p> <ul> <li> <p>Range Dimension. You can use the Range Dimension feature if you know the input shape will be within some specific interval in that dimension, for example: <code>{\"input_1\": {\"shape\": [\"1..10\", 224, 224, 3]}}</code> </p> </li> <li> <p>Enumerated shapes. Sometimes, the models are trained to work only on a select set of inputs. You can enumerate all supported input shapes, for example: <code>{\"input_1\": {\"shape\": [[1, 224, 224, 3], [1, 160, 160, 3]]}}</code> </p> </li> </ul> </li> <li> <p> <code>default_shape</code>: Default input shape. You can set a default shape during conversion for both Range Dimension and Enumerated Shapes. For example <code>{\"input_1\": {\"shape\": [\"1..10\", 224, 224, 3], \"default_shape\": [1, 224, 224, 3]}}</code> </p> </li> <li> <p> <code>type</code>: Input type. Allowed values: <code>Image</code> and <code>Tensor</code>. By default, the converter generates an ML Model with inputs of type Tensor (MultiArray). User can set input type to be Image. Image input type requires additional input parameters such as <code>bias</code> and <code>scale</code>.</p> </li> <li> <p> <code>bias</code>: If the input type is an Image, you need to provide the bias vector.</p> </li> <li> <p> <code>scale</code>: If the input type is an Image, you need to provide a scale factor.</p> </li> </ul> <p>CoreML <code>ClassifierConfig</code> parameters can be specified using <a>OutputConfig$CompilerOptions</a>. CoreML converter supports Tensorflow and PyTorch models. CoreML conversion examples:</p> <ul> <li> <p>Tensor type input:</p> <ul> <li> <p> <code>\"DataInputConfig\": {\"input_1\": {\"shape\": [[1,224,224,3], [1,160,160,3]], \"default_shape\": [1,224,224,3]}}</code> </p> </li> </ul> </li> <li> <p>Tensor type input without input name (PyTorch):</p> <ul> <li> <p> <code>\"DataInputConfig\": [{\"shape\": [[1,3,224,224], [1,3,160,160]], \"default_shape\": [1,3,224,224]}]</code> </p> </li> </ul> </li> <li> <p>Image type input:</p> <ul> <li> <p> <code>\"DataInputConfig\": {\"input_1\": {\"shape\": [[1,224,224,3], [1,160,160,3]], \"default_shape\": [1,224,224,3], \"type\": \"Image\", \"bias\": [-1,-1,-1], \"scale\": 0.007843137255}}</code> </p> </li> <li> <p> <code>\"CompilerOptions\": {\"class_labels\": \"imagenet_labels_1000.txt\"}</code> </p> </li> </ul> </li> <li> <p>Image type input without input name (PyTorch):</p> <ul> <li> <p> <code>\"DataInputConfig\": [{\"shape\": [[1,3,224,224], [1,3,160,160]], \"default_shape\": [1,3,224,224], \"type\": \"Image\", \"bias\": [-1,-1,-1], \"scale\": 0.007843137255}]</code> </p> </li> <li> <p> <code>\"CompilerOptions\": {\"class_labels\": \"imagenet_labels_1000.txt\"}</code> </p> </li> </ul> </li> </ul>"
+          "documentation":"<p>Specifies the name and shape of the expected data inputs for your trained model with a JSON dictionary form. The data inputs are <a>InputConfig$Framework</a> specific. </p> <ul> <li> <p> <code>TensorFlow</code>: You must specify the name and shape (NHWC format) of the expected data inputs using a dictionary format for your trained model. The dictionary formats required for the console and CLI are different.</p> <ul> <li> <p>Examples for one input:</p> <ul> <li> <p>If using the console, <code>{\"input\":[1,1024,1024,3]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input\\\":[1,1024,1024,3]}</code> </p> </li> </ul> </li> <li> <p>Examples for two inputs:</p> <ul> <li> <p>If using the console, <code>{\"data1\": [1,28,28,1], \"data2\":[1,28,28,1]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"data1\\\": [1,28,28,1], \\\"data2\\\":[1,28,28,1]}</code> </p> </li> </ul> </li> </ul> </li> <li> <p> <code>KERAS</code>: You must specify the name and shape (NCHW format) of expected data inputs using a dictionary format for your trained model. Note that while Keras model artifacts should be uploaded in NHWC (channel-last) format, <code>DataInputConfig</code> should be specified in NCHW (channel-first) format. The dictionary formats required for the console and CLI are different.</p> <ul> <li> <p>Examples for one input:</p> <ul> <li> <p>If using the console, <code>{\"input_1\":[1,3,224,224]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input_1\\\":[1,3,224,224]}</code> </p> </li> </ul> </li> <li> <p>Examples for two inputs:</p> <ul> <li> <p>If using the console, <code>{\"input_1\": [1,3,224,224], \"input_2\":[1,3,224,224]} </code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input_1\\\": [1,3,224,224], \\\"input_2\\\":[1,3,224,224]}</code> </p> </li> </ul> </li> </ul> </li> <li> <p> <code>MXNET/ONNX</code>: You must specify the name and shape (NCHW format) of the expected data inputs in order using a dictionary format for your trained model. The dictionary formats required for the console and CLI are different.</p> <ul> <li> <p>Examples for one input:</p> <ul> <li> <p>If using the console, <code>{\"data\":[1,3,1024,1024]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"data\\\":[1,3,1024,1024]}</code> </p> </li> </ul> </li> <li> <p>Examples for two inputs:</p> <ul> <li> <p>If using the console, <code>{\"var1\": [1,1,28,28], \"var2\":[1,1,28,28]} </code> </p> </li> <li> <p>If using the CLI, <code>{\\\"var1\\\": [1,1,28,28], \\\"var2\\\":[1,1,28,28]}</code> </p> </li> </ul> </li> </ul> </li> <li> <p> <code>PyTorch</code>: You can either specify the name and shape (NCHW format) of expected data inputs in order using a dictionary format for your trained model or you can specify the shape only using a list format. The dictionary formats required for the console and CLI are different. The list formats for the console and CLI are the same.</p> <ul> <li> <p>Examples for one input in dictionary format:</p> <ul> <li> <p>If using the console, <code>{\"input0\":[1,3,224,224]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input0\\\":[1,3,224,224]}</code> </p> </li> </ul> </li> <li> <p>Example for one input in list format: <code>[[1,3,224,224]]</code> </p> </li> <li> <p>Examples for two inputs in dictionary format:</p> <ul> <li> <p>If using the console, <code>{\"input0\":[1,3,224,224], \"input1\":[1,3,224,224]}</code> </p> </li> <li> <p>If using the CLI, <code>{\\\"input0\\\":[1,3,224,224], \\\"input1\\\":[1,3,224,224]} </code> </p> </li> </ul> </li> <li> <p>Example for two inputs in list format: <code>[[1,3,224,224], [1,3,224,224]]</code> </p> </li> </ul> </li> <li> <p> <code>XGBOOST</code>: input data name and shape are not needed.</p> </li> </ul> <p> <code>DataInputConfig</code> supports the following parameters for <code>CoreML</code> <a>OutputConfig$TargetDevice</a> (ML Model format):</p> <ul> <li> <p> <code>shape</code>: Input shape, for example <code>{\"input_1\": {\"shape\": [1,224,224,3]}}</code>. In addition to static input shapes, CoreML converter supports Flexible input shapes:</p> <ul> <li> <p>Range Dimension. You can use the Range Dimension feature if you know the input shape will be within some specific interval in that dimension, for example: <code>{\"input_1\": {\"shape\": [\"1..10\", 224, 224, 3]}}</code> </p> </li> <li> <p>Enumerated shapes. Sometimes, the models are trained to work only on a select set of inputs. You can enumerate all supported input shapes, for example: <code>{\"input_1\": {\"shape\": [[1, 224, 224, 3], [1, 160, 160, 3]]}}</code> </p> </li> </ul> </li> <li> <p> <code>default_shape</code>: Default input shape. You can set a default shape during conversion for both Range Dimension and Enumerated Shapes. For example <code>{\"input_1\": {\"shape\": [\"1..10\", 224, 224, 3], \"default_shape\": [1, 224, 224, 3]}}</code> </p> </li> <li> <p> <code>type</code>: Input type. Allowed values: <code>Image</code> and <code>Tensor</code>. By default, the converter generates an ML Model with inputs of type Tensor (MultiArray). User can set input type to be Image. Image input type requires additional input parameters such as <code>bias</code> and <code>scale</code>.</p> </li> <li> <p> <code>bias</code>: If the input type is an Image, you need to provide the bias vector.</p> </li> <li> <p> <code>scale</code>: If the input type is an Image, you need to provide a scale factor.</p> </li> </ul> <p>CoreML <code>ClassifierConfig</code> parameters can be specified using <a>OutputConfig$CompilerOptions</a>. CoreML converter supports Tensorflow and PyTorch models. CoreML conversion examples:</p> <ul> <li> <p>Tensor type input:</p> <ul> <li> <p> <code>\"DataInputConfig\": {\"input_1\": {\"shape\": [[1,224,224,3], [1,160,160,3]], \"default_shape\": [1,224,224,3]}}</code> </p> </li> </ul> </li> <li> <p>Tensor type input without input name (PyTorch):</p> <ul> <li> <p> <code>\"DataInputConfig\": [{\"shape\": [[1,3,224,224], [1,3,160,160]], \"default_shape\": [1,3,224,224]}]</code> </p> </li> </ul> </li> <li> <p>Image type input:</p> <ul> <li> <p> <code>\"DataInputConfig\": {\"input_1\": {\"shape\": [[1,224,224,3], [1,160,160,3]], \"default_shape\": [1,224,224,3], \"type\": \"Image\", \"bias\": [-1,-1,-1], \"scale\": 0.007843137255}}</code> </p> </li> <li> <p> <code>\"CompilerOptions\": {\"class_labels\": \"imagenet_labels_1000.txt\"}</code> </p> </li> </ul> </li> <li> <p>Image type input without input name (PyTorch):</p> <ul> <li> <p> <code>\"DataInputConfig\": [{\"shape\": [[1,3,224,224], [1,3,160,160]], \"default_shape\": [1,3,224,224], \"type\": \"Image\", \"bias\": [-1,-1,-1], \"scale\": 0.007843137255}]</code> </p> </li> <li> <p> <code>\"CompilerOptions\": {\"class_labels\": \"imagenet_labels_1000.txt\"}</code> </p> </li> </ul> </li> </ul>"
         },
         "Framework":{
           "shape":"Framework",
@@ -9189,10 +9177,10 @@
       "members":{
         "DefaultResourceSpec":{
           "shape":"ResourceSpec",
-          "documentation":"<p>The default instance type and the Amazon Resource Name (ARN) of the default SageMaker image used by the JupyterServer app.</p>"
+          "documentation":"<p>The default instance type and the Amazon Resource Name (ARN) of the SageMaker image created on the instance.</p>"
         }
       },
-      "documentation":"<p>The JupyterServer app settings.</p>"
+      "documentation":"<p>Jupyter server's app settings.</p>"
     },
     "KernelDisplayName":{
       "type":"string",
@@ -9207,7 +9195,7 @@
         },
         "CustomImages":{
           "shape":"CustomImages",
-          "documentation":"<p>A list of custom SageMaker images that are configured to run as a KernelGateway app.</p>"
+          "documentation":"<p>A list of custom images that are configured to run as a KernelGateway app.</p>"
         }
       },
       "documentation":"<p>The KernelGateway app settings.</p>"
@@ -9218,14 +9206,14 @@
       "members":{
         "KernelSpecs":{
           "shape":"KernelSpecs",
-          "documentation":"<p>The specification of the Jupyter kernels in the image.</p>"
+          "documentation":"<p>Defines how a kernel is started and the arguments, environment variables, and metadata that are available to the kernel.</p>"
         },
         "FileSystemConfig":{
           "shape":"FileSystemConfig",
-          "documentation":"<p>The Amazon Elastic File System (EFS) storage configuration for a SageMaker image.</p>"
+          "documentation":"<p>The file system configuration.</p>"
         }
       },
-      "documentation":"<p>The configuration for the file system and kernels in a SageMaker image running as a KernelGateway app.</p>"
+      "documentation":"<p>The configuration for an Amazon SageMaker KernelGateway app.</p>"
     },
     "KernelName":{
       "type":"string",
@@ -9237,14 +9225,14 @@
       "members":{
         "Name":{
           "shape":"KernelName",
-          "documentation":"<p>The name of the kernel.</p>"
+          "documentation":"<p>The name of the kernel. Must be unique to your account.</p>"
         },
         "DisplayName":{
           "shape":"KernelDisplayName",
           "documentation":"<p>The display name of the kernel.</p>"
         }
       },
-      "documentation":"<p>The specification of a Jupyter kernel.</p>"
+      "documentation":"<p>Defines how a kernel is started and the arguments, environment variables, and metadata that are available to the kernel.</p>"
     },
     "KernelSpecs":{
       "type":"list",
diff --git a/botocore/data/servicecatalog/2015-12-10/service-2.json b/botocore/data/servicecatalog/2015-12-10/service-2.json
index 8a76284b8..31dd633f4 100644
--- a/botocore/data/servicecatalog/2015-12-10/service-2.json
+++ b/botocore/data/servicecatalog/2015-12-10/service-2.json
@@ -751,22 +751,6 @@
       ],
       "documentation":"<p>This API takes either a <code>ProvisonedProductId</code> or a <code>ProvisionedProductName</code>, along with a list of one or more output keys, and responds with the key/value pairs of those outputs.</p>"
     },
-    "ImportAsProvisionedProduct":{
-      "name":"ImportAsProvisionedProduct",
-      "http":{
-        "method":"POST",
-        "requestUri":"/"
-      },
-      "input":{"shape":"ImportAsProvisionedProductInput"},
-      "output":{"shape":"ImportAsProvisionedProductOutput"},
-      "errors":[
-        {"shape":"DuplicateResourceException"},
-        {"shape":"InvalidStateException"},
-        {"shape":"ResourceNotFoundException"},
-        {"shape":"InvalidParametersException"}
-      ],
-      "documentation":"<p>Requests the import of a resource as a Service Catalog provisioned product that is associated to a Service Catalog product and provisioning artifact. Once imported all supported Service Catalog governance actions are supported on the provisioned product.</p> <p>Resource import only supports CloudFormation stack ARNs. CloudFormation StackSets and non-root nested stacks are not supported.</p> <p>The CloudFormation stack must have one of the following statuses to be imported: CREATE_COMPLETE, UPDATE_COMPLETE, UPDATE_ROLLBACK_COMPLETE, IMPORT_COMPLETE, IMPORT_ROLLBACK_COMPLETE.</p> <p>Import of the resource requires that the CloudFormation stack template matches the associated Service Catalog product provisioning artifact. </p>"
-    },
     "ListAcceptedPortfolioShares":{
       "name":"ListAcceptedPortfolioShares",
       "http":{
@@ -1849,7 +1833,7 @@
         },
         "ProvisioningArtifactParameters":{
           "shape":"ProvisioningArtifactProperties",
-          "documentation":"<p>The configuration of the provisioning artifact. The <code>info</code> field accepts <code>ImportFromPhysicalID</code>.</p>"
+          "documentation":"<p>The configuration of the provisioning artifact.</p>"
         },
         "IdempotencyToken":{
           "shape":"IdempotencyToken",
@@ -1867,7 +1851,7 @@
         },
         "ProvisioningArtifactDetail":{
           "shape":"ProvisioningArtifactDetail",
-          "documentation":"<p>Information about the provisioning artifact. </p>"
+          "documentation":"<p>Information about the provisioning artifact.</p>"
         },
         "Tags":{
           "shape":"Tags",
@@ -1976,7 +1960,7 @@
         },
         "Parameters":{
           "shape":"ProvisioningArtifactProperties",
-          "documentation":"<p>The configuration for the provisioning artifact. The <code>info</code> field accepts <code>ImportFromPhysicalID</code>. </p>"
+          "documentation":"<p>The configuration for the provisioning artifact.</p>"
         },
         "IdempotencyToken":{
           "shape":"IdempotencyToken",
@@ -3163,49 +3147,6 @@
       "pattern":"[a-zA-Z0-9][a-zA-Z0-9_-]*"
     },
     "IgnoreErrors":{"type":"boolean"},
-    "ImportAsProvisionedProductInput":{
-      "type":"structure",
-      "required":[
-        "ProductId",
-        "ProvisioningArtifactId",
-        "ProvisionedProductName",
-        "PhysicalId",
-        "IdempotencyToken"
-      ],
-      "members":{
-        "AcceptLanguage":{
-          "shape":"AcceptLanguage",
-          "documentation":"<p>The language code.</p> <ul> <li> <p> <code>en</code> - English (default)</p> </li> <li> <p> <code>jp</code> - Japanese</p> </li> <li> <p> <code>zh</code> - Chinese</p> </li> </ul>"
-        },
-        "ProductId":{
-          "shape":"Id",
-          "documentation":"<p>The product identifier.</p>"
-        },
-        "ProvisioningArtifactId":{
-          "shape":"Id",
-          "documentation":"<p>The identifier of the provisioning artifact.</p>"
-        },
-        "ProvisionedProductName":{
-          "shape":"ProvisionedProductName",
-          "documentation":"<p>The user-friendly name of the provisioned product. The value must be unique for the AWS account. The name cannot be updated after the product is provisioned. </p>"
-        },
-        "PhysicalId":{
-          "shape":"PhysicalId",
-          "documentation":"<p>The unique identifier of the resource to be imported. It only currently supports CloudFormation stack IDs.</p>"
-        },
-        "IdempotencyToken":{
-          "shape":"IdempotencyToken",
-          "documentation":"<p>A unique identifier that you provide to ensure idempotency. If multiple requests differ only by the idempotency token, the same response is returned for each repeated request.</p>",
-          "idempotencyToken":true
-        }
-      }
-    },
-    "ImportAsProvisionedProductOutput":{
-      "type":"structure",
-      "members":{
-        "RecordDetail":{"shape":"RecordDetail"}
-      }
-    },
     "InstructionType":{"type":"string"},
     "InstructionValue":{"type":"string"},
     "InvalidParametersException":{
@@ -5330,7 +5271,6 @@
       "documentation":"<p>Information about a change to a resource attribute.</p>"
     },
     "ResourceType":{"type":"string"},
-    "RetainPhysicalResources":{"type":"boolean"},
     "RoleArn":{
       "type":"string",
       "max":1224,
@@ -5939,10 +5879,6 @@
         "AcceptLanguage":{
           "shape":"AcceptLanguage",
           "documentation":"<p>The language code.</p> <ul> <li> <p> <code>en</code> - English (default)</p> </li> <li> <p> <code>jp</code> - Japanese</p> </li> <li> <p> <code>zh</code> - Chinese</p> </li> </ul>"
-        },
-        "RetainPhysicalResources":{
-          "shape":"RetainPhysicalResources",
-          "documentation":"<p>When this boolean parameter is set to true, the TerminateProvisionedProduct API deletes the Service Catalog provisioned product. However, it does not remove the CloudFormation stack, stack set, or the underlying resources of the deleted provisioned product. The default value is false.</p>"
         }
       }
     },
@@ -6191,7 +6127,7 @@
         },
         "ProvisionedProductProperties":{
           "shape":"ProvisionedProductProperties",
-          "documentation":"<p>A map that contains the provisioned product properties to be updated.</p> <p>The <code>LAUNCH_ROLE</code> key accepts role ARNs. This key allows an administrator to call <code>UpdateProvisionedProductProperties</code> to update the launch role that is associated with a provisioned product. This role is used when an end user calls a provisioning operation such as <code>UpdateProvisionedProduct</code>, <code>TerminateProvisionedProduct</code>, or <code>ExecuteProvisionedProductServiceAction</code>. Only a role ARN is valid. A user ARN is invalid. </p> <p>The <code>OWNER</code> key accepts user ARNs and role ARNs. The owner is the user that has permission to see, update, terminate, and execute service actions in the provisioned product.</p> <p>The administrator can change the owner of a provisioned product to another IAM user within the same account. Both end user owners and administrators can see ownership history of the provisioned product using the <code>ListRecordHistory</code> API. The new owner can describe all past records for the provisioned product using the <code>DescribeRecord</code> API. The previous owner can no longer use <code>DescribeRecord</code>, but can still see the product's history from when he was an owner using <code>ListRecordHistory</code>.</p> <p>If a provisioned product ownership is assigned to an end user, they can see and perform any action through the API or Service Catalog console such as update, terminate, and execute service actions. If an end user provisions a product and the owner is updated to someone else, they will no longer be able to see or perform any actions through API or the Service Catalog console on that provisioned product.</p>"
+          "documentation":"<p>A map that contains the provisioned product properties to be updated.</p> <p>The <code>LAUNCH_ROLE</code> key accepts role ARNs. This key allows an administrator to call <code>UpdateProvisionedProductProperties</code> to update the launch role that is associated with a provisioned product. This role is used when an end user calls a provisioning operation such as <code>UpdateProvisionedProduct</code>, <code>TerminateProvisionedProduct</code>, or <code>ExecuteProvisionedProductServiceAction</code>. Only a role ARN or an empty string <code>\"\"</code> is valid. A user ARN is invalid. if an admin user passes an empty string <code>\"\"</code> as the value for the key <code>LAUNCH_ROLE</code>, the admin removes the launch role that is associated with the provisioned product. As a result, the end user operations use the credentials of the end user.</p> <p>The <code>OWNER</code> key accepts user ARNs and role ARNs. The owner is the user that has permission to see, update, terminate, and execute service actions in the provisioned product.</p> <p>The administrator can change the owner of a provisioned product to another IAM user within the same account. Both end user owners and administrators can see ownership history of the provisioned product using the <code>ListRecordHistory</code> API. The new owner can describe all past records for the provisioned product using the <code>DescribeRecord</code> API. The previous owner can no longer use <code>DescribeRecord</code>, but can still see the product's history from when he was an owner using <code>ListRecordHistory</code>.</p> <p>If a provisioned product ownership is assigned to an end user, they can see and perform any action through the API or Service Catalog console such as update, terminate, and execute service actions. If an end user provisions a product and the owner is updated to someone else, they will no longer be able to see or perform any actions through API or the Service Catalog console on that provisioned product.</p>"
         },
         "IdempotencyToken":{
           "shape":"IdempotencyToken",
@@ -6417,5 +6353,5 @@
     "UserArnSession":{"type":"string"},
     "Verbose":{"type":"boolean"}
   },
-  "documentation":"<fullname>AWS Service Catalog</fullname> <p> <a href=\"https://aws.amazon.com/servicecatalog/\">AWS Service Catalog</a> enables organizations to create and manage catalogs of IT services that are approved for AWS. To get the most out of this documentation, you should be familiar with the terminology discussed in <a href=\"http://docs.aws.amazon.com/servicecatalog/latest/adminguide/what-is_concepts.html\">AWS Service Catalog Concepts</a>.</p>"
+  "documentation":"<fullname>AWS Service Catalog</fullname> <p> <a href=\"https://aws.amazon.com/servicecatalog/\">AWS Service Catalog</a> enables organizations to create and manage catalogs of IT services that are approved for use on AWS. To get the most out of this documentation, you should be familiar with the terminology discussed in <a href=\"http://docs.aws.amazon.com/servicecatalog/latest/adminguide/what-is_concepts.html\">AWS Service Catalog Concepts</a>.</p>"
 }
diff --git a/botocore/data/sns/2010-03-31/service-2.json b/botocore/data/sns/2010-03-31/service-2.json
index 977b5d984..febd979fc 100644
--- a/botocore/data/sns/2010-03-31/service-2.json
+++ b/botocore/data/sns/2010-03-31/service-2.json
@@ -565,7 +565,7 @@
         {"shape":"AuthorizationErrorException"},
         {"shape":"InvalidSecurityException"}
       ],
-      "documentation":"<p>Subscribes an endpoint to an Amazon SNS topic. If the endpoint type is HTTP/S or email, or if the endpoint and the topic are not in the same AWS account, the endpoint owner must run the <code>ConfirmSubscription</code> action to confirm the subscription.</p> <p>You call the <code>ConfirmSubscription</code> action with the token from the subscription response. Confirmation tokens are valid for three days.</p> <p>This action is throttled at 100 transactions per second (TPS).</p>"
+      "documentation":"<p>Subscribes an endpoint to an Amazon SNS topic. If the endpoint type is HTTP/S or email, or if the endpoint and the topic are not in the same AWS account, the endpoint owner must the <code>ConfirmSubscription</code> action to confirm the subscription.</p> <p>You call the <code>ConfirmSubscription</code> action with the token from the subscription response. Confirmation tokens are valid for three days.</p> <p>This action is throttled at 100 transactions per second (TPS).</p>"
     },
     "TagResource":{
       "name":"TagResource",
@@ -1597,7 +1597,7 @@
         },
         "AttributeName":{
           "shape":"attributeName",
-          "documentation":"<p>A map of attributes with their corresponding values.</p> <p>The following lists the names, descriptions, and values of the special request parameters that this action uses:</p> <ul> <li> <p> <code>DeliveryPolicy</code> – The policy that defines how Amazon SNS retries failed deliveries to HTTP/S endpoints.</p> </li> <li> <p> <code>FilterPolicy</code> – The simple JSON object that lets your subscriber receive only a subset of messages, rather than receiving every message published to the topic.</p> </li> <li> <p> <code>RawMessageDelivery</code> – When set to <code>true</code>, enables raw message delivery to Amazon SQS or HTTP/S endpoints. This eliminates the need for the endpoints to process JSON formatting, which is otherwise created for Amazon SNS metadata.</p> </li> <li> <p> <code>RedrivePolicy</code> – When specified, sends undeliverable messages to the specified Amazon SQS dead-letter queue. Messages that can't be delivered due to client errors (for example, when the subscribed endpoint is unreachable) or server errors (for example, when the service that powers the subscribed endpoint becomes unavailable) are held in the dead-letter queue for further analysis or reprocessing.</p> </li> </ul>"
+          "documentation":"<p>A map of attributes with their corresponding values.</p> <p>The following lists the names, descriptions, and values of the special request parameters that the <code>SetTopicAttributes</code> action uses:</p> <ul> <li> <p> <code>DeliveryPolicy</code> – The policy that defines how Amazon SNS retries failed deliveries to HTTP/S endpoints.</p> </li> <li> <p> <code>FilterPolicy</code> – The simple JSON object that lets your subscriber receive only a subset of messages, rather than receiving every message published to the topic.</p> </li> <li> <p> <code>RawMessageDelivery</code> – When set to <code>true</code>, enables raw message delivery to Amazon SQS or HTTP/S endpoints. This eliminates the need for the endpoints to process JSON formatting, which is otherwise created for Amazon SNS metadata.</p> </li> <li> <p> <code>RedrivePolicy</code> – When specified, sends undeliverable messages to the specified Amazon SQS dead-letter queue. Messages that can't be delivered due to client errors (for example, when the subscribed endpoint is unreachable) or server errors (for example, when the service that powers the subscribed endpoint becomes unavailable) are held in the dead-letter queue for further analysis or reprocessing.</p> </li> </ul>"
         },
         "AttributeValue":{
           "shape":"attributeValue",
@@ -1916,5 +1916,5 @@
     "topicARN":{"type":"string"},
     "topicName":{"type":"string"}
   },
-  "documentation":"<fullname>Amazon Simple Notification Service</fullname> <p>Amazon Simple Notification Service (Amazon SNS) is a web service that enables you to build distributed web-enabled applications. Applications can use Amazon SNS to easily push real-time notification messages to interested subscribers over multiple delivery protocols. For more information about this product see <a href=\"http://aws.amazon.com/sns/\">https://aws.amazon.com/sns</a>. For detailed information about Amazon SNS features and their associated API calls, see the <a href=\"https://docs.aws.amazon.com/sns/latest/dg/\">Amazon SNS Developer Guide</a>. </p> <p>For information on the permissions you need to use this API, see <a href=\"https://docs.aws.amazon.com/sns/latest/dg/sns-authentication-and-access-control.html\">Identity and access management in Amazon SNS</a> in the <i>Amazon SNS Developer Guide.</i> </p> <p>We also provide SDKs that enable you to access Amazon SNS from your preferred programming language. The SDKs contain functionality that automatically takes care of tasks such as: cryptographically signing your service requests, retrying requests, and handling error responses. For a list of available SDKs, go to <a href=\"http://aws.amazon.com/tools/\">Tools for Amazon Web Services</a>. </p>"
+  "documentation":"<fullname>Amazon Simple Notification Service</fullname> <p>Amazon Simple Notification Service (Amazon SNS) is a web service that enables you to build distributed web-enabled applications. Applications can use Amazon SNS to easily push real-time notification messages to interested subscribers over multiple delivery protocols. For more information about this product see <a href=\"http://aws.amazon.com/sns/\">https://aws.amazon.com/sns</a>. For detailed information about Amazon SNS features and their associated API calls, see the <a href=\"https://docs.aws.amazon.com/sns/latest/dg/\">Amazon SNS Developer Guide</a>. </p> <p>We also provide SDKs that enable you to access Amazon SNS from your preferred programming language. The SDKs contain functionality that automatically takes care of tasks such as: cryptographically signing your service requests, retrying requests, and handling error responses. For a list of available SDKs, go to <a href=\"http://aws.amazon.com/tools/\">Tools for Amazon Web Services</a>. </p>"
 }
diff --git a/botocore/data/synthetics/2017-10-11/service-2.json b/botocore/data/synthetics/2017-10-11/service-2.json
index 255bc9bba..985c52799 100644
--- a/botocore/data/synthetics/2017-10-11/service-2.json
+++ b/botocore/data/synthetics/2017-10-11/service-2.json
@@ -269,7 +269,7 @@
         },
         "RuntimeVersion":{
           "shape":"String",
-          "documentation":"<p>Specifies the runtime version to use for the canary. For more information about runtime versions, see <a href=\"https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library.html\"> Canary Runtime Versions</a>.</p>"
+          "documentation":"<p>Specifies the runtime version to use for the canary. Currently, the only valid values are <code>syn-nodejs-2.0</code>, <code>syn-nodejs-2.0-beta</code>, and <code>syn-1.0</code>. For more information about runtime versions, see <a href=\"https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library.html\"> Canary Runtime Versions</a>.</p>"
         },
         "VpcConfig":{"shape":"VpcConfigOutput"},
         "Tags":{
@@ -386,10 +386,6 @@
         "ActiveTracing":{
           "shape":"NullableBoolean",
           "documentation":"<p>Specifies whether this canary is to use active AWS X-Ray tracing when it runs. Active tracing enables this canary run to be displayed in the ServiceLens and X-Ray service maps even if the canary does not hit an endpoint that has X-ray tracing enabled. Using X-Ray tracing incurs charges. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_tracing.html\"> Canaries and X-Ray tracing</a>.</p> <p>You can enable active tracing only for canaries that use version <code>syn-nodejs-2.0</code> or later for their canary runtime.</p>"
-        },
-        "EnvironmentVariables":{
-          "shape":"EnvironmentVariablesMap",
-          "documentation":"<p>Specifies the keys and values to use for any environment variables used in the canary script. Use the following format:</p> <p>{ \"key1\" : \"value1\", \"key2\" : \"value2\", ...}</p> <p>Keys must start with a letter and be at least two characters. The total size of your environment variables cannot exceed 4 KB. You can't specify any Lambda reserved environment variables as the keys for your environment variables. For more information about reserved keys, see <a href=\"https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime\"> Runtime environment variables</a>.</p>"
         }
       },
       "documentation":"<p>A structure that contains input information for a canary run.</p>"
@@ -604,7 +600,7 @@
         },
         "RuntimeVersion":{
           "shape":"String",
-          "documentation":"<p>Specifies the runtime version to use for the canary. For a list of valid runtime versions and more information about runtime versions, see <a href=\"https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library.html\"> Canary Runtime Versions</a>.</p>"
+          "documentation":"<p>Specifies the runtime version to use for the canary. Currently, the only valid values are <code>syn-nodejs-2.0</code>, <code>syn-nodejs-2.0-beta</code>, and <code>syn-1.0</code>. For more information about runtime versions, see <a href=\"https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library.html\"> Canary Runtime Versions</a>.</p>"
         },
         "VpcConfig":{
           "shape":"VpcConfigInput",
@@ -720,16 +716,6 @@
         }
       }
     },
-    "EnvironmentVariableName":{
-      "type":"string",
-      "pattern":"[a-zA-Z]([a-zA-Z0-9_])+"
-    },
-    "EnvironmentVariableValue":{"type":"string"},
-    "EnvironmentVariablesMap":{
-      "type":"map",
-      "key":{"shape":"EnvironmentVariableName"},
-      "value":{"shape":"EnvironmentVariableValue"}
-    },
     "ErrorMessage":{"type":"string"},
     "FunctionArn":{
       "type":"string",
@@ -872,7 +858,7 @@
       "members":{
         "VersionName":{
           "shape":"String",
-          "documentation":"<p>The name of the runtime version. For a list of valid runtime versions, see <a href=\"https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library.html\"> Canary Runtime Versions</a>.</p>"
+          "documentation":"<p>The name of the runtime version. Currently, the only valid values are <code>syn-nodejs-2.0</code>, <code>syn-nodejs-2.0-beta</code>, and <code>syn-1.0</code>.</p>"
         },
         "Description":{
           "shape":"String",
@@ -1049,7 +1035,7 @@
         },
         "RuntimeVersion":{
           "shape":"String",
-          "documentation":"<p>Specifies the runtime version to use for the canary. For a list of valid runtime versions and for more information about runtime versions, see <a href=\"https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library.html\"> Canary Runtime Versions</a>.</p>"
+          "documentation":"<p>Specifies the runtime version to use for the canary. Currently, the only valid values are <code>syn-nodejs-2.0</code>, <code>syn-nodejs-2.0-beta</code>, and <code>syn-1.0</code>. For more information about runtime versions, see <a href=\"https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library.html\"> Canary Runtime Versions</a>.</p>"
         },
         "Schedule":{
           "shape":"CanaryScheduleInput",
diff --git a/botocore/utils.py b/botocore/utils.py
index a643d888d..8eda6148b 100644
--- a/botocore/utils.py
+++ b/botocore/utils.py
@@ -2215,7 +2215,7 @@ def conditionally_calculate_md5(params, **kwargs):
     """Only add a Content-MD5 if the system supports it."""
     headers = params['headers']
     body = params['body']
-    if MD5_AVAILABLE and body and 'Content-MD5' not in headers:
+    if MD5_AVAILABLE and body is not None and 'Content-MD5' not in headers:
         md5_digest = calculate_md5(body, **kwargs)
         params['headers']['Content-MD5'] = md5_digest
 
diff --git a/docs/source/conf.py b/docs/source/conf.py
index b8982a1d3..27c34d973 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -54,7 +54,7 @@ copyright = u'2013, Mitch Garnaat'
 # The short X.Y version.
 version = '1.19.'
 # The full version, including alpha/beta/rc tags.
-release = '1.19.19'
+release = '1.19.18'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.


Test patch:
diff --git a/tests/functional/test_s3.py b/tests/functional/test_s3.py
index 00917d93f..b7645125d 100644
--- a/tests/functional/test_s3.py
+++ b/tests/functional/test_s3.py
@@ -919,6 +919,18 @@ class TestS3SigV4(BaseS3OperationTest):
             self.client.put_object(Bucket='foo', Key='bar', Body='baz')
         self.assertIn('content-md5', self.get_sent_headers())
 
+    def test_content_md5_set_empty_body(self):
+        with self.http_stubber:
+            self.client.put_object(Bucket='foo', Key='bar', Body='')
+        self.assertIn('content-md5', self.get_sent_headers())
+
+    def test_content_md5_set_empty_file(self):
+        with self.http_stubber:
+            with temporary_file('rb') as f:
+                assert f.read() == b''
+                self.client.put_object(Bucket='foo', Key='bar', Body=f)
+        self.assertIn('content-md5', self.get_sent_headers())
+
     def test_content_sha256_set_if_config_value_is_true(self):
         config = Config(signature_version='s3v4', s3={
             'payload_signing_enabled': True
diff --git a/tests/unit/test_handlers.py b/tests/unit/test_handlers.py
index 7857ef67a..fde22e34e 100644
--- a/tests/unit/test_handlers.py
+++ b/tests/unit/test_handlers.py
@@ -1217,6 +1217,17 @@ class TestAddMD5(BaseMD5Test):
             request_dict['headers']['Content-MD5'],
             'OFj2IjCsPJFfMAxmQxLGPw==')
 
+    def test_add_md5_with_empty_body(self):
+        request_dict = {
+            'body': b'',
+            'headers': {}
+        }
+        self.md5_digest.return_value = b'8X\xf6"0\xac<\x91_0\x0cfC\x12\xc6?'
+        conditionally_calculate_md5(request_dict)
+        self.assertEqual(
+            request_dict['headers']['Content-MD5'],
+            'OFj2IjCsPJFfMAxmQxLGPw==')
+
     def test_add_md5_with_bytearray_object(self):
         request_dict = {
             'body': bytearray(b'foobar'),