comparison env/lib/python3.9/site-packages/boto/support/layer1.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # Copyright (c) 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the
5 # "Software"), to deal in the Software without restriction, including
6 # without limitation the rights to use, copy, modify, merge, publish, dis-
7 # tribute, sublicense, and/or sell copies of the Software, and to permit
8 # persons to whom the Software is furnished to do so, subject to the fol-
9 # lowing conditions:
10 #
11 # The above copyright notice and this permission notice shall be included
12 # in all copies or substantial portions of the Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
21 #
22
23 import boto
24 from boto.compat import json
25 from boto.connection import AWSQueryConnection
26 from boto.regioninfo import RegionInfo
27 from boto.exception import JSONResponseError
28 from boto.support import exceptions
29
30
31 class SupportConnection(AWSQueryConnection):
32 """
33 AWS Support
34 The AWS Support API reference is intended for programmers who need
35 detailed information about the AWS Support operations and data
36 types. This service enables you to manage your AWS Support cases
37 programmatically. It uses HTTP methods that return results in JSON
38 format.
39
40 The AWS Support service also exposes a set of `Trusted Advisor`_
41 features. You can retrieve a list of checks and their
42 descriptions, get check results, specify checks to refresh, and
43 get the refresh status of checks.
44
45 The following list describes the AWS Support case management
46 operations:
47
48
49 + **Service names, issue categories, and available severity
50 levels. **The DescribeServices and DescribeSeverityLevels
51 operations return AWS service names, service codes, service
52 categories, and problem severity levels. You use these values when
53 you call the CreateCase operation.
54 + **Case creation, case details, and case resolution.** The
55 CreateCase, DescribeCases, DescribeAttachment, and ResolveCase
56 operations create AWS Support cases, retrieve information about
57 cases, and resolve cases.
58 + **Case communication.** The DescribeCommunications,
59 AddCommunicationToCase, and AddAttachmentsToSet operations
60 retrieve and add communications and attachments to AWS Support
61 cases.
62
63
64 The following list describes the operations available from the AWS
65 Support service for Trusted Advisor:
66
67
68 + DescribeTrustedAdvisorChecks returns the list of checks that run
69 against your AWS resources.
70 + Using the `CheckId` for a specific check returned by
71 DescribeTrustedAdvisorChecks, you can call
72 DescribeTrustedAdvisorCheckResult to obtain the results for the
73 check you specified.
74 + DescribeTrustedAdvisorCheckSummaries returns summarized results
75 for one or more Trusted Advisor checks.
76 + RefreshTrustedAdvisorCheck requests that Trusted Advisor rerun a
77 specified check.
78 + DescribeTrustedAdvisorCheckRefreshStatuses reports the refresh
79 status of one or more checks.
80
81
82 For authentication of requests, AWS Support uses `Signature
83 Version 4 Signing Process`_.
84
85 See `About the AWS Support API`_ in the AWS Support User Guide for
86 information about how to use this service to create and manage
87 your support cases, and how to call Trusted Advisor for results of
88 checks on your resources.
89 """
90 APIVersion = "2013-04-15"
91 DefaultRegionName = "us-east-1"
92 DefaultRegionEndpoint = "support.us-east-1.amazonaws.com"
93 ServiceName = "Support"
94 TargetPrefix = "AWSSupport_20130415"
95 ResponseError = JSONResponseError
96
97 _faults = {
98 "CaseCreationLimitExceeded": exceptions.CaseCreationLimitExceeded,
99 "AttachmentLimitExceeded": exceptions.AttachmentLimitExceeded,
100 "CaseIdNotFound": exceptions.CaseIdNotFound,
101 "DescribeAttachmentLimitExceeded": exceptions.DescribeAttachmentLimitExceeded,
102 "AttachmentSetIdNotFound": exceptions.AttachmentSetIdNotFound,
103 "InternalServerError": exceptions.InternalServerError,
104 "AttachmentSetExpired": exceptions.AttachmentSetExpired,
105 "AttachmentIdNotFound": exceptions.AttachmentIdNotFound,
106 "AttachmentSetSizeLimitExceeded": exceptions.AttachmentSetSizeLimitExceeded,
107 }
108
109
110 def __init__(self, **kwargs):
111 region = kwargs.pop('region', None)
112 if not region:
113 region = RegionInfo(self, self.DefaultRegionName,
114 self.DefaultRegionEndpoint)
115
116 if 'host' not in kwargs or kwargs['host'] is None:
117 kwargs['host'] = region.endpoint
118
119 super(SupportConnection, self).__init__(**kwargs)
120 self.region = region
121
122 def _required_auth_capability(self):
123 return ['hmac-v4']
124
125 def add_attachments_to_set(self, attachments, attachment_set_id=None):
126 """
127 Adds one or more attachments to an attachment set. If an
128 `AttachmentSetId` is not specified, a new attachment set is
129 created, and the ID of the set is returned in the response. If
130 an `AttachmentSetId` is specified, the attachments are added
131 to the specified set, if it exists.
132
133 An attachment set is a temporary container for attachments
134 that are to be added to a case or case communication. The set
135 is available for one hour after it is created; the
136 `ExpiryTime` returned in the response indicates when the set
137 expires. The maximum number of attachments in a set is 3, and
138 the maximum size of any attachment in the set is 5 MB.
139
140 :type attachment_set_id: string
141 :param attachment_set_id: The ID of the attachment set. If an
142 `AttachmentSetId` is not specified, a new attachment set is
143 created, and the ID of the set is returned in the response. If an
144 `AttachmentSetId` is specified, the attachments are added to the
145 specified set, if it exists.
146
147 :type attachments: list
148 :param attachments: One or more attachments to add to the set. The
149 limit is 3 attachments per set, and the size limit is 5 MB per
150 attachment.
151
152 """
153 params = {'attachments': attachments, }
154 if attachment_set_id is not None:
155 params['attachmentSetId'] = attachment_set_id
156 return self.make_request(action='AddAttachmentsToSet',
157 body=json.dumps(params))
158
159 def add_communication_to_case(self, communication_body, case_id=None,
160 cc_email_addresses=None,
161 attachment_set_id=None):
162 """
163 Adds additional customer communication to an AWS Support case.
164 You use the `CaseId` value to identify the case to add
165 communication to. You can list a set of email addresses to
166 copy on the communication using the `CcEmailAddresses` value.
167 The `CommunicationBody` value contains the text of the
168 communication.
169
170 The response indicates the success or failure of the request.
171
172 This operation implements a subset of the behavior on the AWS
173 Support `Your Support Cases`_ web form.
174
175 :type case_id: string
176 :param case_id: The AWS Support case ID requested or returned in the
177 call. The case ID is an alphanumeric string formatted as shown in
178 this example: case- 12345678910-2013-c4c1d2bf33c5cf47
179
180 :type communication_body: string
181 :param communication_body: The body of an email communication to add to
182 the support case.
183
184 :type cc_email_addresses: list
185 :param cc_email_addresses: The email addresses in the CC line of an
186 email to be added to the support case.
187
188 :type attachment_set_id: string
189 :param attachment_set_id: The ID of a set of one or more attachments
190 for the communication to add to the case. Create the set by calling
191 AddAttachmentsToSet
192
193 """
194 params = {'communicationBody': communication_body, }
195 if case_id is not None:
196 params['caseId'] = case_id
197 if cc_email_addresses is not None:
198 params['ccEmailAddresses'] = cc_email_addresses
199 if attachment_set_id is not None:
200 params['attachmentSetId'] = attachment_set_id
201 return self.make_request(action='AddCommunicationToCase',
202 body=json.dumps(params))
203
204 def create_case(self, subject, communication_body, service_code=None,
205 severity_code=None, category_code=None,
206 cc_email_addresses=None, language=None, issue_type=None,
207 attachment_set_id=None):
208 """
209 Creates a new case in the AWS Support Center. This operation
210 is modeled on the behavior of the AWS Support Center `Open a
211 new case`_ page. Its parameters require you to specify the
212 following information:
213
214
215 #. **IssueType.** The type of issue for the case. You can
216 specify either "customer-service" or "technical." If you do
217 not indicate a value, the default is "technical."
218 #. **ServiceCode.** The code for an AWS service. You obtain
219 the `ServiceCode` by calling DescribeServices.
220 #. **CategoryCode.** The category for the service defined for
221 the `ServiceCode` value. You also obtain the category code for
222 a service by calling DescribeServices. Each AWS service
223 defines its own set of category codes.
224 #. **SeverityCode.** A value that indicates the urgency of the
225 case, which in turn determines the response time according to
226 your service level agreement with AWS Support. You obtain the
227 SeverityCode by calling DescribeSeverityLevels.
228 #. **Subject.** The **Subject** field on the AWS Support
229 Center `Open a new case`_ page.
230 #. **CommunicationBody.** The **Description** field on the AWS
231 Support Center `Open a new case`_ page.
232 #. **AttachmentSetId.** The ID of a set of attachments that
233 has been created by using AddAttachmentsToSet.
234 #. **Language.** The human language in which AWS Support
235 handles the case. English and Japanese are currently
236 supported.
237 #. **CcEmailAddresses.** The AWS Support Center **CC** field
238 on the `Open a new case`_ page. You can list email addresses
239 to be copied on any correspondence about the case. The account
240 that opens the case is already identified by passing the AWS
241 Credentials in the HTTP POST method or in a method or function
242 call from one of the programming languages supported by an
243 `AWS SDK`_.
244
245
246 A successful CreateCase request returns an AWS Support case
247 number. Case numbers are used by the DescribeCases operation
248 to retrieve existing AWS Support cases.
249
250 :type subject: string
251 :param subject: The title of the AWS Support case.
252
253 :type service_code: string
254 :param service_code: The code for the AWS service returned by the call
255 to DescribeServices.
256
257 :type severity_code: string
258 :param severity_code: The code for the severity level returned by the
259 call to DescribeSeverityLevels.
260
261 :type category_code: string
262 :param category_code: The category of problem for the AWS Support case.
263
264 :type communication_body: string
265 :param communication_body: The communication body text when you create
266 an AWS Support case by calling CreateCase.
267
268 :type cc_email_addresses: list
269 :param cc_email_addresses: A list of email addresses that AWS Support
270 copies on case correspondence.
271
272 :type language: string
273 :param language: The ISO 639-1 code for the language in which AWS
274 provides support. AWS Support currently supports English ("en") and
275 Japanese ("ja"). Language parameters must be passed explicitly for
276 operations that take them.
277
278 :type issue_type: string
279 :param issue_type: The type of issue for the case. You can specify
280 either "customer-service" or "technical." If you do not indicate a
281 value, the default is "technical."
282
283 :type attachment_set_id: string
284 :param attachment_set_id: The ID of a set of one or more attachments
285 for the case. Create the set by using AddAttachmentsToSet.
286
287 """
288 params = {
289 'subject': subject,
290 'communicationBody': communication_body,
291 }
292 if service_code is not None:
293 params['serviceCode'] = service_code
294 if severity_code is not None:
295 params['severityCode'] = severity_code
296 if category_code is not None:
297 params['categoryCode'] = category_code
298 if cc_email_addresses is not None:
299 params['ccEmailAddresses'] = cc_email_addresses
300 if language is not None:
301 params['language'] = language
302 if issue_type is not None:
303 params['issueType'] = issue_type
304 if attachment_set_id is not None:
305 params['attachmentSetId'] = attachment_set_id
306 return self.make_request(action='CreateCase',
307 body=json.dumps(params))
308
309 def describe_attachment(self, attachment_id):
310 """
311 Returns the attachment that has the specified ID. Attachment
312 IDs are generated by the case management system when you add
313 an attachment to a case or case communication. Attachment IDs
314 are returned in the AttachmentDetails objects that are
315 returned by the DescribeCommunications operation.
316
317 :type attachment_id: string
318 :param attachment_id: The ID of the attachment to return. Attachment
319 IDs are returned by the DescribeCommunications operation.
320
321 """
322 params = {'attachmentId': attachment_id, }
323 return self.make_request(action='DescribeAttachment',
324 body=json.dumps(params))
325
326 def describe_cases(self, case_id_list=None, display_id=None,
327 after_time=None, before_time=None,
328 include_resolved_cases=None, next_token=None,
329 max_results=None, language=None,
330 include_communications=None):
331 """
332 Returns a list of cases that you specify by passing one or
333 more case IDs. In addition, you can filter the cases by date
334 by setting values for the `AfterTime` and `BeforeTime` request
335 parameters.
336
337 Case data is available for 12 months after creation. If a case
338 was created more than 12 months ago, a request for data might
339 cause an error.
340
341 The response returns the following in JSON format:
342
343
344 #. One or more CaseDetails data types.
345 #. One or more `NextToken` values, which specify where to
346 paginate the returned records represented by the `CaseDetails`
347 objects.
348
349 :type case_id_list: list
350 :param case_id_list: A list of ID numbers of the support cases you want
351 returned. The maximum number of cases is 100.
352
353 :type display_id: string
354 :param display_id: The ID displayed for a case in the AWS Support
355 Center user interface.
356
357 :type after_time: string
358 :param after_time: The start date for a filtered date search on support
359 case communications. Case communications are available for 12
360 months after creation.
361
362 :type before_time: string
363 :param before_time: The end date for a filtered date search on support
364 case communications. Case communications are available for 12
365 months after creation.
366
367 :type include_resolved_cases: boolean
368 :param include_resolved_cases: Specifies whether resolved support cases
369 should be included in the DescribeCases results. The default is
370 false .
371
372 :type next_token: string
373 :param next_token: A resumption point for pagination.
374
375 :type max_results: integer
376 :param max_results: The maximum number of results to return before
377 paginating.
378
379 :type language: string
380 :param language: The ISO 639-1 code for the language in which AWS
381 provides support. AWS Support currently supports English ("en") and
382 Japanese ("ja"). Language parameters must be passed explicitly for
383 operations that take them.
384
385 :type include_communications: boolean
386 :param include_communications: Specifies whether communications should
387 be included in the DescribeCases results. The default is true .
388
389 """
390 params = {}
391 if case_id_list is not None:
392 params['caseIdList'] = case_id_list
393 if display_id is not None:
394 params['displayId'] = display_id
395 if after_time is not None:
396 params['afterTime'] = after_time
397 if before_time is not None:
398 params['beforeTime'] = before_time
399 if include_resolved_cases is not None:
400 params['includeResolvedCases'] = include_resolved_cases
401 if next_token is not None:
402 params['nextToken'] = next_token
403 if max_results is not None:
404 params['maxResults'] = max_results
405 if language is not None:
406 params['language'] = language
407 if include_communications is not None:
408 params['includeCommunications'] = include_communications
409 return self.make_request(action='DescribeCases',
410 body=json.dumps(params))
411
412 def describe_communications(self, case_id, before_time=None,
413 after_time=None, next_token=None,
414 max_results=None):
415 """
416 Returns communications (and attachments) for one or more
417 support cases. You can use the `AfterTime` and `BeforeTime`
418 parameters to filter by date. You can use the `CaseId`
419 parameter to restrict the results to a particular case.
420
421 Case data is available for 12 months after creation. If a case
422 was created more than 12 months ago, a request for data might
423 cause an error.
424
425 You can use the `MaxResults` and `NextToken` parameters to
426 control the pagination of the result set. Set `MaxResults` to
427 the number of cases you want displayed on each page, and use
428 `NextToken` to specify the resumption of pagination.
429
430 :type case_id: string
431 :param case_id: The AWS Support case ID requested or returned in the
432 call. The case ID is an alphanumeric string formatted as shown in
433 this example: case- 12345678910-2013-c4c1d2bf33c5cf47
434
435 :type before_time: string
436 :param before_time: The end date for a filtered date search on support
437 case communications. Case communications are available for 12
438 months after creation.
439
440 :type after_time: string
441 :param after_time: The start date for a filtered date search on support
442 case communications. Case communications are available for 12
443 months after creation.
444
445 :type next_token: string
446 :param next_token: A resumption point for pagination.
447
448 :type max_results: integer
449 :param max_results: The maximum number of results to return before
450 paginating.
451
452 """
453 params = {'caseId': case_id, }
454 if before_time is not None:
455 params['beforeTime'] = before_time
456 if after_time is not None:
457 params['afterTime'] = after_time
458 if next_token is not None:
459 params['nextToken'] = next_token
460 if max_results is not None:
461 params['maxResults'] = max_results
462 return self.make_request(action='DescribeCommunications',
463 body=json.dumps(params))
464
465 def describe_services(self, service_code_list=None, language=None):
466 """
467 Returns the current list of AWS services and a list of service
468 categories that applies to each one. You then use service
469 names and categories in your CreateCase requests. Each AWS
470 service has its own set of categories.
471
472 The service codes and category codes correspond to the values
473 that are displayed in the **Service** and **Category** drop-
474 down lists on the AWS Support Center `Open a new case`_ page.
475 The values in those fields, however, do not necessarily match
476 the service codes and categories returned by the
477 `DescribeServices` request. Always use the service codes and
478 categories obtained programmatically. This practice ensures
479 that you always have the most recent set of service and
480 category codes.
481
482 :type service_code_list: list
483 :param service_code_list: A JSON-formatted list of service codes
484 available for AWS services.
485
486 :type language: string
487 :param language: The ISO 639-1 code for the language in which AWS
488 provides support. AWS Support currently supports English ("en") and
489 Japanese ("ja"). Language parameters must be passed explicitly for
490 operations that take them.
491
492 """
493 params = {}
494 if service_code_list is not None:
495 params['serviceCodeList'] = service_code_list
496 if language is not None:
497 params['language'] = language
498 return self.make_request(action='DescribeServices',
499 body=json.dumps(params))
500
501 def describe_severity_levels(self, language=None):
502 """
503 Returns the list of severity levels that you can assign to an
504 AWS Support case. The severity level for a case is also a
505 field in the CaseDetails data type included in any CreateCase
506 request.
507
508 :type language: string
509 :param language: The ISO 639-1 code for the language in which AWS
510 provides support. AWS Support currently supports English ("en") and
511 Japanese ("ja"). Language parameters must be passed explicitly for
512 operations that take them.
513
514 """
515 params = {}
516 if language is not None:
517 params['language'] = language
518 return self.make_request(action='DescribeSeverityLevels',
519 body=json.dumps(params))
520
521 def describe_trusted_advisor_check_refresh_statuses(self, check_ids):
522 """
523 Returns the refresh status of the Trusted Advisor checks that
524 have the specified check IDs. Check IDs can be obtained by
525 calling DescribeTrustedAdvisorChecks.
526
527 :type check_ids: list
528 :param check_ids: The IDs of the Trusted Advisor checks.
529
530 """
531 params = {'checkIds': check_ids, }
532 return self.make_request(action='DescribeTrustedAdvisorCheckRefreshStatuses',
533 body=json.dumps(params))
534
535 def describe_trusted_advisor_check_result(self, check_id, language=None):
536 """
537 Returns the results of the Trusted Advisor check that has the
538 specified check ID. Check IDs can be obtained by calling
539 DescribeTrustedAdvisorChecks.
540
541 The response contains a TrustedAdvisorCheckResult object,
542 which contains these three objects:
543
544
545 + TrustedAdvisorCategorySpecificSummary
546 + TrustedAdvisorResourceDetail
547 + TrustedAdvisorResourcesSummary
548
549
550 In addition, the response contains these fields:
551
552
553 + **Status.** The alert status of the check: "ok" (green),
554 "warning" (yellow), "error" (red), or "not_available".
555 + **Timestamp.** The time of the last refresh of the check.
556 + **CheckId.** The unique identifier for the check.
557
558 :type check_id: string
559 :param check_id: The unique identifier for the Trusted Advisor check.
560
561 :type language: string
562 :param language: The ISO 639-1 code for the language in which AWS
563 provides support. AWS Support currently supports English ("en") and
564 Japanese ("ja"). Language parameters must be passed explicitly for
565 operations that take them.
566
567 """
568 params = {'checkId': check_id, }
569 if language is not None:
570 params['language'] = language
571 return self.make_request(action='DescribeTrustedAdvisorCheckResult',
572 body=json.dumps(params))
573
574 def describe_trusted_advisor_check_summaries(self, check_ids):
575 """
576 Returns the summaries of the results of the Trusted Advisor
577 checks that have the specified check IDs. Check IDs can be
578 obtained by calling DescribeTrustedAdvisorChecks.
579
580 The response contains an array of TrustedAdvisorCheckSummary
581 objects.
582
583 :type check_ids: list
584 :param check_ids: The IDs of the Trusted Advisor checks.
585
586 """
587 params = {'checkIds': check_ids, }
588 return self.make_request(action='DescribeTrustedAdvisorCheckSummaries',
589 body=json.dumps(params))
590
591 def describe_trusted_advisor_checks(self, language):
592 """
593 Returns information about all available Trusted Advisor
594 checks, including name, ID, category, description, and
595 metadata. You must specify a language code; English ("en") and
596 Japanese ("ja") are currently supported. The response contains
597 a TrustedAdvisorCheckDescription for each check.
598
599 :type language: string
600 :param language: The ISO 639-1 code for the language in which AWS
601 provides support. AWS Support currently supports English ("en") and
602 Japanese ("ja"). Language parameters must be passed explicitly for
603 operations that take them.
604
605 """
606 params = {'language': language, }
607 return self.make_request(action='DescribeTrustedAdvisorChecks',
608 body=json.dumps(params))
609
610 def refresh_trusted_advisor_check(self, check_id):
611 """
612 Requests a refresh of the Trusted Advisor check that has the
613 specified check ID. Check IDs can be obtained by calling
614 DescribeTrustedAdvisorChecks.
615
616 The response contains a RefreshTrustedAdvisorCheckResult
617 object, which contains these fields:
618
619
620 + **Status.** The refresh status of the check: "none",
621 "enqueued", "processing", "success", or "abandoned".
622 + **MillisUntilNextRefreshable.** The amount of time, in
623 milliseconds, until the check is eligible for refresh.
624 + **CheckId.** The unique identifier for the check.
625
626 :type check_id: string
627 :param check_id: The unique identifier for the Trusted Advisor check.
628
629 """
630 params = {'checkId': check_id, }
631 return self.make_request(action='RefreshTrustedAdvisorCheck',
632 body=json.dumps(params))
633
634 def resolve_case(self, case_id=None):
635 """
636 Takes a `CaseId` and returns the initial state of the case
637 along with the state of the case after the call to ResolveCase
638 completed.
639
640 :type case_id: string
641 :param case_id: The AWS Support case ID requested or returned in the
642 call. The case ID is an alphanumeric string formatted as shown in
643 this example: case- 12345678910-2013-c4c1d2bf33c5cf47
644
645 """
646 params = {}
647 if case_id is not None:
648 params['caseId'] = case_id
649 return self.make_request(action='ResolveCase',
650 body=json.dumps(params))
651
652 def make_request(self, action, body):
653 headers = {
654 'X-Amz-Target': '%s.%s' % (self.TargetPrefix, action),
655 'Host': self.region.endpoint,
656 'Content-Type': 'application/x-amz-json-1.1',
657 'Content-Length': str(len(body)),
658 }
659 http_request = self.build_base_http_request(
660 method='POST', path='/', auth_path='/', params={},
661 headers=headers, data=body)
662 response = self._mexe(http_request, sender=None,
663 override_num_retries=10)
664 response_body = response.read().decode('utf-8')
665 boto.log.debug(response_body)
666 if response.status == 200:
667 if response_body:
668 return json.loads(response_body)
669 else:
670 json_body = json.loads(response_body)
671 fault_name = json_body.get('__type', None)
672 exception_class = self._faults.get(fault_name, self.ResponseError)
673 raise exception_class(response.status, response.reason,
674 body=json_body)