From a0ad131e4f48ba9d4249bfeefa333a8497d824db Mon Sep 17 00:00:00 2001 From: dedene Date: Mon, 26 Nov 2018 10:23:56 +0100 Subject: [PATCH 1/3] providers: add support for hetzner cloud --- README.md | 7 +++ src/metadata.rs | 1 + src/providers/hcloud/mod.rs | 109 ++++++++++++++++++++++++++++++++++++ src/providers/mod.rs | 1 + 4 files changed, 118 insertions(+) create mode 100644 src/providers/hcloud/mod.rs diff --git a/README.md b/README.md index 25a22735..5fcc4d79 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,13 @@ The supported cloud providers and their respective metadata are as follows: - COREOS_GCE_HOSTNAME - COREOS_GCE_IP_EXTERNAL_0 - COREOS_GCE_IP_LOCAL_0 + - hcloud + - SSH Keys + - Attributes + - COREOS_HCLOUD_HOSTNAME + - COREOS_HCLOUD_IPV4_LOCAL + - COREOS_HCLOUD_IPV4_PUBLIC + - COREOS_HCLOUD_INSTANCE_ID - openstack-metadata - SSH Keys - Attributes diff --git a/src/metadata.rs b/src/metadata.rs index c0337b9c..0aebfc7c 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -32,6 +32,7 @@ pub fn fetch_metadata(provider: &str) -> errors::Result> { "digitalocean" => box_result!(digitalocean::DigitalOceanProvider::new()), "ec2" => box_result!(ec2::Ec2Provider::new()), "gce" => box_result!(gce::GceProvider::new()), + "hcloud" => box_result!(hcloud::HetznerCloudProvider::new()), "openstack-metadata" => box_result!(openstack::network::OpenstackProvider::new()), "packet" => box_result!(packet::PacketProvider::new()), "vagrant-virtualbox" => box_result!(vagrant_virtualbox::VagrantVirtualboxProvider::new()), diff --git a/src/providers/hcloud/mod.rs b/src/providers/hcloud/mod.rs new file mode 100644 index 00000000..fffc4f2c --- /dev/null +++ b/src/providers/hcloud/mod.rs @@ -0,0 +1,109 @@ +// Copyright 2017 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! aws ec2 metadata fetcher +//! + +use std::collections::HashMap; + +use openssh_keys::PublicKey; +use update_ssh_keys::AuthorizedKeyEntry; + +use errors::*; +use network; +use providers::MetadataProvider; +use retry; +use serde_json; + +#[cfg(not(test))] +const URL: &str = "http://169.254.169.254/2009-04-04"; + +#[allow(non_snake_case)] +#[derive(Debug, Deserialize)] +struct InstanceIdDoc { + region: String, +} + +#[derive(Clone, Debug)] +pub struct HetznerCloudProvider { + client: retry::Client, +} + +impl HetznerCloudProvider { + pub fn new() -> Result { + let client = retry::Client::new()? + .return_on_404(true); + + Ok(HetznerCloudProvider { client }) + } + + fn endpoint_for(key: &str) -> String { + format!("{}/{}", URL, key) + } +} + +impl MetadataProvider for HetznerCloudProvider { + fn attributes(&self) -> Result> { + let mut out = HashMap::with_capacity(4); + + let add_value = |map: &mut HashMap<_, _>, key: &str, name| -> Result<()> { + let value = self.client.get(retry::Raw, HetznerCloudProvider::endpoint_for(name)).send()?; + + if let Some(value) = value { + map.insert(key.to_string(), value); + } + + Ok(()) + }; + + add_value(&mut out, "HCLOUD_INSTANCE_ID", "meta-data/instance-id")?; + add_value(&mut out, "HCLOUD_IPV4_LOCAL", "meta-data/local-ipv4")?; + add_value(&mut out, "HCLOUD_IPV4_PUBLIC", "meta-data/public-ipv4")?; + add_value(&mut out, "HCLOUD_HOSTNAME", "meta-data/hostname")?; + + Ok(out) + } + + fn hostname(&self) -> Result> { + self.client.get(retry::Raw, HetznerCloudProvider::endpoint_for("meta-data/hostname")).send() + } + + fn ssh_keys(&self) -> Result> { + let raw_keys: Option = self.client + .get(retry::Raw, HetznerCloudProvider::endpoint_for("meta-data/public-keys")) + .send()?; + + if let Some(raw_keys) = raw_keys { + let keys: Vec = serde_json::from_str(&raw_keys).unwrap(); + let mut out = Vec::new(); + + for key in keys { + let key = PublicKey::parse(&key)?; + out.push(AuthorizedKeyEntry::Valid{key}); + } + + Ok(out) + } else { + Ok(vec![]) + } + } + + fn networks(&self) -> Result> { + Ok(vec![]) + } + + fn network_devices(&self) -> Result> { + Ok(vec![]) + } +} diff --git a/src/providers/mod.rs b/src/providers/mod.rs index ff50e14f..f6217ab0 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -28,6 +28,7 @@ pub mod digitalocean; pub mod cloudstack; pub mod ec2; pub mod gce; +pub mod hcloud; pub mod openstack; pub mod packet; pub mod vagrant_virtualbox; From de1887eac5daedea89a074aa63e09f268cd1ad0b Mon Sep 17 00:00:00 2001 From: dedene Date: Tue, 27 Nov 2018 12:10:34 +0100 Subject: [PATCH 2/3] providers: change description for hcloud metadata fetcher --- src/providers/hcloud/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/providers/hcloud/mod.rs b/src/providers/hcloud/mod.rs index fffc4f2c..5feae41e 100644 --- a/src/providers/hcloud/mod.rs +++ b/src/providers/hcloud/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017 CoreOS, Inc. +// Copyright 2018 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! aws ec2 metadata fetcher +//! Hetzner Cloud metadata fetcher //! use std::collections::HashMap; From 93e98b0e0d2aefa2c3f8cb7e41f4ab065e902bba Mon Sep 17 00:00:00 2001 From: dedene Date: Tue, 27 Nov 2018 12:43:38 +0100 Subject: [PATCH 3/3] providers/hcloud: fix tests --- src/providers/hcloud/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/providers/hcloud/mod.rs b/src/providers/hcloud/mod.rs index 5feae41e..aa9548ff 100644 --- a/src/providers/hcloud/mod.rs +++ b/src/providers/hcloud/mod.rs @@ -26,7 +26,6 @@ use providers::MetadataProvider; use retry; use serde_json; -#[cfg(not(test))] const URL: &str = "http://169.254.169.254/2009-04-04"; #[allow(non_snake_case)]