rusoto / rusoto

AWS SDK for Rust
MIT License
2.73k stars 447 forks source link

ServiceDiscovery GetServiceResponse erroneously requiring an optional field #1672

Open ChronosWS opened 4 years ago

ChronosWS commented 4 years ago

Version: rusoto_core 0.42.0, rusoto_servicediscovery 0.42.0

Failing code snippet:

let client = ServiceDiscoveryClient::new(Region::default());
let request = GetServiceRequest {
    id: service_id.to_string()
};
let response = client.get_service(request).sync().unwrap();

Result:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseError("missing field `DnsRecords` at line 1 column 236")', src\libcore\result.rs:1165:5

Looking at the generated Service (part of the GetServiceResponse):

#[derive(Default, Debug, Clone, PartialEq, Deserialize)]
#[cfg_attr(any(test, feature = "serialize_structs"), derive(Serialize))]
pub struct Service {
...
    /// <p>A complex type that contains information about the Route 53 DNS records that you want AWS Cloud Map to create when you register an instance.</p>
    #[serde(rename = "DnsConfig")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub dns_config: Option<DnsConfig>
...

and DnsConfig:

/// <p>A complex type that contains information about the Amazon Route 53 DNS records that you want AWS Cloud Map to create when you register an instance.</p>
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DnsConfig {
    /// <p>An array that contains one <code>DnsRecord</code> object for each Route 53 DNS record that you want AWS Cloud Map to create when you register an instance.</p>
    #[serde(rename = "DnsRecords")]
    pub dns_records: Vec<DnsRecord>,
...

But the actual response from AWS looks as follows:

aws servicediscovery get-service --id srv-6rsvjngovanXXXX
{
    "Service": {
        "Id": "srv-6rsvjngovanXXXX",
        "Arn": "arn:aws:servicediscovery:us-west-2:XXXXXXXXXXXX:service/srv-6rsvjngovanXXXX",
        "Name": "XXXX",
        "NamespaceId": "XXXX",
        "Description": "XXXX",
        "DnsConfig": {},   <-- EMPTY STRUCT
        "CreateDate": 1580835395.788,
        "CreatorRequestId": "BB099F98-64E1-47B0-94AD-3ECE136002E8"
    }
}

It looks like perhaps that empty struct is not being seen as "absent" but as "present with no fields", and as such the required dns_records field on DnsConfig is barfing. This will be the normal response from a service in an HttpNamespace, which does not do any DNS registration.

Seems like dns_records should be Optional? I am not sure if you could determine this during generation from boto or not...

ChronosWS commented 4 years ago

Verified that changing DnsConfig.dns_records to pub dns_records: Option<Vec<DnsRecord>> allows the request to succeed as expected. However, I see in botocore that servicediscovery has the following definition for DnsConfig:

"DnsConfig":{
      "type":"structure",
      "required":["DnsRecords"],
...

If this is being used to determine whether a field is Optional on types used in responses, then I don't think there is enough information provided by boto to do response generation like this statically. I am not comfortable submitting a PR for this because it seems like a potentially larger issue than just one field on one response...