Skip to content

Commit

Permalink
Merge pull request #1517 from dmcgillen/add-ec2-instance-connect
Browse files Browse the repository at this point in the history
Add EC2 Instance Connect
  • Loading branch information
matthewkmayer committed Oct 4, 2019
2 parents 301ce9a + bca58a7 commit 8ebae02
Show file tree
Hide file tree
Showing 10 changed files with 355 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Fix service_crategen to parse operations with multiple static params
- Refactor S3 integration tests - about a `#[test]` per behavior
- Add support for non signing clients
- Add EC2 Instance Connect service

## [0.40.0] - 2019-06-28

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ members = [
"rusoto/services/dynamodb",
"rusoto/services/dynamodbstreams",
"rusoto/services/ec2",
"rusoto/services/ec2-instance-connect",
"rusoto/services/ecr",
"rusoto/services/ecs",
"rusoto/services/elasticache",
Expand Down
6 changes: 6 additions & 0 deletions integration_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ path = "../rusoto/services/dynamodbstreams"
optional = true
path = "../rusoto/services/ec2"

[dependencies.rusoto_ec2_instance_connect]
optional = true
path = "../rusoto/services/ec2-instance-connect"

[dependencies.rusoto_ecr]
optional = true
path = "../rusoto/services/ecr"
Expand Down Expand Up @@ -689,6 +693,7 @@ all = [
"dynamodb",
"dynamodbstreams",
"ec2",
"ec2-instance-connect",
"ecr",
"ecs",
"elasticache",
Expand Down Expand Up @@ -841,6 +846,7 @@ ds = ["rusoto_ds"]
dynamodb = ["rusoto_dynamodb"]
dynamodbstreams = ["rusoto_dynamodbstreams"]
ec2 = ["rusoto_ec2"]
ec2-instance-connect = ["rusoto_ec2_instance_connect"]
ecr = ["rusoto_ecr"]
ecs = ["rusoto_ecs"]
elasticache = ["rusoto_elasticache"]
Expand Down
38 changes: 38 additions & 0 deletions integration_tests/tests/ec2-instance-connect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#![cfg(feature = "ec2-instance-connect")]

extern crate rusoto_core;
extern crate rusoto_ec2_instance_connect;

use rusoto_core::{Region, RusotoError};
use rusoto_ec2_instance_connect::{
Ec2InstanceConnect, Ec2InstanceConnectClient, SendSSHPublicKeyError, SendSSHPublicKeyRequest,
};

#[test]
fn send_ssh_public_key_correctly_errors_for_unknown_instance() {
let client = Ec2InstanceConnectClient::new(Region::UsEast1);
let request = SendSSHPublicKeyRequest {
availability_zone: "us-east-1a".into(),
instance_id: "i-00000000".into(),
instance_os_user: "ec2-user".into(),
ssh_public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+P68X1LG5rJXQL1ktjhMv84lP8gKgJoPk99GwWoM6lbJAv80WUgauB961I5i/3/Y0XWnYZfzFCP3+fTu/9+vEsfTd38hUW3QBGTPrx/jXyvTBRQc7bTirpeicfwL9SwM4ztYvuM45sGSeZkQIg+TMKVFGnR0ijCitG613fRP/NUw/jQjzUPj2ymCw43MIAD1BPQrznsyoaPWP/bKv91Y9ZtB1fOn3UzgWlwBGxzPNXx8boquLfHWi+ut+v1zfZpUBUjQtI4EIctjqzmxnyB1SPpxk0r5v2GR0qLChKzZ0IqdJmImlz2vqCuwUThJN9d/iF//kCeb76uJVsDOOtDWb user@host".into(),
};

match client.send_ssh_public_key(request).sync() {
Ok(_) => {
panic!("send_ssh_public_key should fail");
}
Err(error) => match error {
RusotoError::Service(e) => match e {
SendSSHPublicKeyError::InvalidArgs(error) => assert!(
error.contains("Instance not found"),
"Missing error message"
),
_ => panic!("Unexpected error"),
},
_ => {
panic!("Should have a typed error from EC2 Instance Connect");
}
},
};
}
35 changes: 35 additions & 0 deletions rusoto/services/ec2-instance-connect/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[package]
authors = ["Anthony DiMarco <ocramida@gmail.com>", "Jimmy Cuadra <jimmy@jimmycuadra.com>", "Matthew Mayer <matthewkmayer@gmail.com>", "Nikita Pekin <contact@nikitapek.in>"]
description = "AWS SDK for Rust - AWS EC2 Instance Connect @ 2018-04-02"
documentation = "https://docs.rs/rusoto_ec2_instance_connect"
keywords = ["AWS", "Amazon", "ec2-instance-connect"]
license = "MIT"
name = "rusoto_ec2_instance_connect"
readme = "README.md"
repository = "https://github.com/rusoto/rusoto"
version = "0.40.0"
homepage = "https://www.rusoto.org/"
edition = "2018"
exclude = ["test_resources/*"]

[build-dependencies]

[dependencies]
bytes = "0.4.12"
futures = "0.1.16"
serde = "1.0.2"
serde_derive = "1.0.2"
serde_json = "1.0.1"

[dependencies.rusoto_core]
version = "0.40.0"
path = "../../core"
default-features = false
[dev-dependencies.rusoto_mock]
version = "0.40.0"
path = "../../../mock"

[features]
default = ["native-tls"]
native-tls = ["rusoto_core/native-tls"]
rustls = ["rusoto_core/rustls"]
45 changes: 45 additions & 0 deletions rusoto/services/ec2-instance-connect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

# Rusoto Ec2InstanceConnect
Rust SDK for AWS EC2 Instance Connect

You may be looking for:

* [An overview of Rusoto][rusoto-overview]
* [AWS services supported by Rusoto][supported-aws-services]
* [API documentation][api-documentation]
* [Getting help with Rusoto][rusoto-help]

## Requirements

Rust stable or beta are required to use Rusoto. Nightly is tested, but not guaranteed to be supported. Older
versions _may_ be supported. The currently supported Rust versions can be found in the Rusoto project
[`travis.yml`](https://github.com/rusoto/rusoto/blob/master/.travis.yml).

On Linux, OpenSSL is required.

## Installation

To use `rusoto_ec2_instance_connect` in your application, add it as a dependency in your `Cargo.toml`:

```toml
[dependencies]
rusoto_ec2_instance_connect = "0.40.0"
```

## Contributing

See [CONTRIBUTING][contributing].

## License

Rusoto is distributed under the terms of the MIT license.

See [LICENSE][license] for details.

[api-documentation]: https://docs.rs/rusoto_ec2_instance_connect "API documentation"
[license]: https://github.com/rusoto/rusoto/blob/master/LICENSE "MIT License"
[contributing]: https://github.com/rusoto/rusoto/blob/master/CONTRIBUTING.md "Contributing Guide"
[rusoto-help]: https://www.rusoto.org/help.html "Getting help with Rusoto"
[rusoto-overview]: https://www.rusoto.org/ "Rusoto overview"
[supported-aws-services]: https://www.rusoto.org/supported-aws-services.html "List of AWS services supported by Rusoto"
Empty file.
191 changes: 191 additions & 0 deletions rusoto/services/ec2-instance-connect/src/generated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// =================================================================
//
// * WARNING *
//
// This file is generated!
//
// Changes made to this file will be overwritten. If changes are
// required to the generated code, the service_crategen project
// must be updated to generate the changes.
//
// =================================================================
#![allow(warnings)]

use futures::future;
use futures::Future;
use rusoto_core::credential::ProvideAwsCredentials;
use rusoto_core::region;
use rusoto_core::request::{BufferedHttpResponse, DispatchSignedRequest};
use rusoto_core::{Client, RusotoError, RusotoFuture};
use std::error::Error;
use std::fmt;

use rusoto_core::proto;
use rusoto_core::signature::SignedRequest;
use serde_json;
#[derive(Default, Debug, Clone, PartialEq, Serialize)]
pub struct SendSSHPublicKeyRequest {
/// <p>The availability zone the EC2 instance was launched in.</p>
#[serde(rename = "AvailabilityZone")]
pub availability_zone: String,
/// <p>The EC2 instance you wish to publish the SSH key to.</p>
#[serde(rename = "InstanceId")]
pub instance_id: String,
/// <p>The OS user on the EC2 instance whom the key may be used to authenticate as.</p>
#[serde(rename = "InstanceOSUser")]
pub instance_os_user: String,
/// <p>The public key to be published to the instance. To use it after publication you must have the matching private key.</p>
#[serde(rename = "SSHPublicKey")]
pub ssh_public_key: String,
}

#[derive(Default, Debug, Clone, PartialEq, Deserialize)]
#[cfg_attr(test, derive(Serialize))]
pub struct SendSSHPublicKeyResponse {
/// <p>The request ID as logged by EC2 Connect. Please provide this when contacting AWS Support.</p>
#[serde(rename = "RequestId")]
#[serde(skip_serializing_if = "Option::is_none")]
pub request_id: Option<String>,
/// <p>Indicates request success.</p>
#[serde(rename = "Success")]
#[serde(skip_serializing_if = "Option::is_none")]
pub success: Option<bool>,
}

/// Errors returned by SendSSHPublicKey
#[derive(Debug, PartialEq)]
pub enum SendSSHPublicKeyError {
/// <p>Indicates that either your AWS credentials are invalid or you do not have access to the EC2 instance.</p>
Auth(String),
/// <p>Indicates that the instance requested was not found in the given zone. Check that you have provided a valid instance ID and the correct zone.</p>
EC2InstanceNotFound(String),
/// <p>Indicates that you provided bad input. Ensure you have a valid instance ID, the correct zone, and a valid SSH public key.</p>
InvalidArgs(String),
/// <p>Indicates that the service encountered an error. Follow the message's instructions and try again.</p>
Service(String),
/// <p>Indicates you have been making requests too frequently and have been throttled. Wait for a while and try again. If higher call volume is warranted contact AWS Support.</p>
Throttling(String),
}

impl SendSSHPublicKeyError {
pub fn from_response(res: BufferedHttpResponse) -> RusotoError<SendSSHPublicKeyError> {
if let Some(err) = proto::json::Error::parse(&res) {
match err.typ.as_str() {
"AuthException" => {
return RusotoError::Service(SendSSHPublicKeyError::Auth(err.msg))
}
"EC2InstanceNotFoundException" => {
return RusotoError::Service(SendSSHPublicKeyError::EC2InstanceNotFound(
err.msg,
))
}
"InvalidArgsException" => {
return RusotoError::Service(SendSSHPublicKeyError::InvalidArgs(err.msg))
}
"ServiceException" => {
return RusotoError::Service(SendSSHPublicKeyError::Service(err.msg))
}
"ThrottlingException" => {
return RusotoError::Service(SendSSHPublicKeyError::Throttling(err.msg))
}
"ValidationException" => return RusotoError::Validation(err.msg),
_ => {}
}
}
return RusotoError::Unknown(res);
}
}
impl fmt::Display for SendSSHPublicKeyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
impl Error for SendSSHPublicKeyError {
fn description(&self) -> &str {
match *self {
SendSSHPublicKeyError::Auth(ref cause) => cause,
SendSSHPublicKeyError::EC2InstanceNotFound(ref cause) => cause,
SendSSHPublicKeyError::InvalidArgs(ref cause) => cause,
SendSSHPublicKeyError::Service(ref cause) => cause,
SendSSHPublicKeyError::Throttling(ref cause) => cause,
}
}
}
/// Trait representing the capabilities of the EC2 Instance Connect API. EC2 Instance Connect clients implement this trait.
pub trait Ec2InstanceConnect {
/// <p>Pushes an SSH public key to a particular OS user on a given EC2 instance for 60 seconds.</p>
fn send_ssh_public_key(
&self,
input: SendSSHPublicKeyRequest,
) -> RusotoFuture<SendSSHPublicKeyResponse, SendSSHPublicKeyError>;
}
/// A client for the EC2 Instance Connect API.
#[derive(Clone)]
pub struct Ec2InstanceConnectClient {
client: Client,
region: region::Region,
}

impl Ec2InstanceConnectClient {
/// Creates a client backed by the default tokio event loop.
///
/// The client will use the default credentials provider and tls client.
pub fn new(region: region::Region) -> Ec2InstanceConnectClient {
Self::new_with_client(Client::shared(), region)
}

pub fn new_with<P, D>(
request_dispatcher: D,
credentials_provider: P,
region: region::Region,
) -> Ec2InstanceConnectClient
where
P: ProvideAwsCredentials + Send + Sync + 'static,
P::Future: Send,
D: DispatchSignedRequest + Send + Sync + 'static,
D::Future: Send,
{
Self::new_with_client(
Client::new_with(credentials_provider, request_dispatcher),
region,
)
}

pub fn new_with_client(client: Client, region: region::Region) -> Ec2InstanceConnectClient {
Ec2InstanceConnectClient { client, region }
}
}

impl Ec2InstanceConnect for Ec2InstanceConnectClient {
/// <p>Pushes an SSH public key to a particular OS user on a given EC2 instance for 60 seconds.</p>
fn send_ssh_public_key(
&self,
input: SendSSHPublicKeyRequest,
) -> RusotoFuture<SendSSHPublicKeyResponse, SendSSHPublicKeyError> {
let mut request = SignedRequest::new("POST", "ec2-instance-connect", &self.region, "/");

request.set_content_type("application/x-amz-json-1.1".to_owned());
request.add_header(
"x-amz-target",
"AWSEC2InstanceConnectService.SendSSHPublicKey",
);
let encoded = serde_json::to_string(&input).unwrap();
request.set_payload(Some(encoded));

self.client.sign_and_dispatch(request, |response| {
if response.status.is_success() {
Box::new(response.buffer().from_err().and_then(|response| {
proto::json::ResponsePayload::new(&response)
.deserialize::<SendSSHPublicKeyResponse, _>()
}))
} else {
Box::new(
response
.buffer()
.from_err()
.and_then(|response| Err(SendSSHPublicKeyError::from_response(response))),
)
}
})
}
}
32 changes: 32 additions & 0 deletions rusoto/services/ec2-instance-connect/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

// =================================================================
//
// * WARNING *
//
// This file is generated!
//
// Changes made to this file will be overwritten. If changes are
// required to the generated code, the service_crategen project
// must be updated to generate the changes.
//
// =================================================================

#![doc(html_logo_url = "https://raw.githubusercontent.com/rusoto/rusoto/master/assets/logo-square.png")]
//! <p>AWS EC2 Connect Service is a service that enables system administrators to publish temporary SSH keys to their EC2 instances in order to establish connections to their instances without leaving a permanent authentication option.</p>
//!
//! If you're using the service, you're probably looking for [Ec2InstanceConnectClient](struct.Ec2InstanceConnectClient.html) and [Ec2InstanceConnect](trait.Ec2InstanceConnect.html).

extern crate bytes;
extern crate futures;
extern crate rusoto_core;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod generated;
mod custom;

pub use crate::generated::*;
pub use crate::custom::*;

0 comments on commit 8ebae02

Please sign in to comment.