Giter Club home page Giter Club logo

rust-openstack's Introduction

OpenStack SDK for Rust

CI License Latest Version Documentation

The goal of this project is to provide a simple API for working with OpenStack clouds. It is still work-in-progress, some bits are not implemented.

Usage

Use standard cargo tool to build and test. Add a dependency on openstack crate to your software to use this library.

Examples

There is an example that lists all running servers (their ID and name). Source your Keystone V3 credentials and run:

cargo run --example list-servers

Enable verbose logging by using standard RUST_LOG variable:

RUST_LOG=openstack cargo run --example list-servers

rust-openstack's People

Contributors

dtantsur avatar gierens avatar hirevo avatar ilourt avatar jistr avatar julienfastre avatar mchlumsky avatar milliams avatar mrhillsman avatar rkday avatar sd109 avatar stefan-k avatar uberjay avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rust-openstack's Issues

rustc-serialize used by eui48 dependency is deprecated

rustc-serialize is deprecated, from https://github.com/rust-lang-deprecated/rustc-serialize:
NOTE: This crate is deprecated in favor of [serde](https://serde.rs/).

It results in anything using openstack crate producing:
warning: the following packages contain code that will be rejected by a future version of Rust: rustc-serialize v0.3.24
As also it could have security impact too https://rustsec.org/advisories/RUSTSEC-2022-0004

rustc-serialize comes into rust-openstack as dependency of eui48

├── openstack v0.5.0
│   ├── eui48 v1.1.0
│   │   ├── regex v1.9.0 (*)
│   │   ├── rustc-serialize v0.3.24
│   │   └── serde v1.0.168 (*)

eui48 = { version = "^1.0", features = ["disp_hexstring", "serde"] }

eui48 itself does not seems responsive about this issue for a while already

One possible alternative seems to be to switch from eui48 to macaddr e.g.: ewilken/hap-rs#80

Error enum clean up

Should be designed around what consumers will need, not what underlying libraries provide. Hide rare errors inside something more generic, move things like NotFound and AccessDenied to the front.

Error handling in DetailedServerQuery

When running a detailed server query, the batching behaviour of fetch_chunk makes error handling difficult. I'm trying to run the following code

let results = cloud
    .find_servers()
    .detailed()
    .into_stream()
    .collect::<Vec<openstack::Result<Server>>>()
    .await;

and expect to have 81 Server objects returned to me based on the cloud I'm testing against. The problem is that my target cloud is a multi-user dev environment which has seen a lot of experimentation and as a result some of the server queries return errors. For example, running

let server_summaries = cloud.list_servers().await.unwrap();
for ss in server_summaries {
    let result = cloud.get_server(ss.id()).await;
    if result.is_err() {
            println!("{e}");
    }
}

gives me 3 errors of the form

Normal Flavor e081ba5c-90a8-4f8f-abc4-d262cecf55dc could not be found.
Requested resource was not found: Flavor with given name or ID not found

From an openstack perspective (I think) what's happening here is that a flavour has been deleted while still having servers using that flavour, but that's not really important. (I also can't work out exactly where the query for flavours by ID is happening in this library, maybe it's done by the OpenStack API as part of the server details request, but I don't think that's relevant to the wider issue either.)

The problem is that the results variable in the first code snippet returns a vector of 51 elements where the first 50 are Ok and the final element is Err. However, if I add a .with_limit(77) to the query I get a vec of 77 Ok values but .with_limit(78) gives me a vec of length 1 with a single Err (because the 78th server in the list is the first that has a broken flavour reference, so with no limit the first chunk of 50 servers are fetched successfully then the second chunk returns the error).

Am I missing some simple way to return each item from the stream and handle each error separately? Or maybe there needs to be some more explicit error handling in the list_servers_detailed function to accommodate this?

Cloud: new high-level API

We need to clearly split between high-level and low-level API. Low-level should exist as extension traits for Session per service (e.g. openstack::compute::v2::ComputeApi) providing low-level functions operating on protocol objects and UUIDs. Then the Cloud object will wrap it for a high-level API.

Feature list for the MVP (0.1):

  • getting and listing images (glance only)
  • getting and listing flavors
  • getting and listing networks (neutron only)
  • getting and listing keypairs
  • creating keypairs from string and file
  • getting and listing servers
  • creating a server with image, network and keypair
  • powering on and off, rebooting servers
  • deleting servers
  • deleting keypairs

The following example should work (modulo minor issues):

use openstack;

fn demo() -> openstack::Result<openstack::compute::Server> {
    let auth = openstack::auth::Password::new(
        "https://127.0.0.1:5000",
        "admin", "password", "Default",
        openstack::auth::Scope::Project("project name", "Default"))?;
    let os = openstack::Cloud::new(auth);

    let all_servers = os.list_servers()?;
    let servers_with_flavors = os.find_servers()
        .with_flavor("small").limit(10).all()?;

    let my_server = os.get_server("web")?;
    let image = my_server.get_image()?;
    let flavor = os.get_flavor("large")?;
    let net = os.get_network("public")?;

    let mut file = File::open("~/.id_rsa.pub")?;
    let keypair = os.new_keypair("default").from_reader(file)
        .create()?.wait()?;
    os.new_server("new-server", flavor).with_image(image)
        .with_network(net).with_keypair(keypair).with_auto_ip()
        .create()?.wait()
}

All asynchronous calls (like power actions) return immediately after receiving 204 from the API. They return a struct implementing Waiter trait:

pub trait Waiter<T> {
    // The main method to implement.
    fn poll(&mut self) -> Result<Option<T>>;
    // Provided implementation for waiting.
    fn wait(mut self) -> Result<T> { ... }
    fn wait_for(mut self, duration: Duration) -> Result<T> { ... }
}

To avoid using the underlying object (e.g. a Server), the Waiter either consumes it (in case of deletion) or borrows it mutably.

For example, ServerRequest.create returns PendingServer implementing Waiter<Server>.

Getting messages saying "Normal Flavor m1.small could not be found."

If I run the code:

let flavor = os.get_flavor("m1.small").await?;

then it outputs the following to the screen:

Normal Flavor m1.small could not be found.

This is not an error being raised as the code continues to run, nor does it actually cause any problems as flavor gets populated correctly with all the details of the m1.small flavor.

If I pass in the string of the ID of the flavor (instead of the name) to os.get_flavor then the message is not printed.

I'm trying to track down where the message is coming from, but can't find it anywhere. I haven't turned on any logging and the message seems to appear on stdout.

I get the same thing if I create a server and specify the network by name .with_network("external"):

Normal Network external could not be found.

I'll note that fetching key pairs or images by name does not seem to trigger the message being printed.

I'm not sure why it has the prefix "Normal " or how to turn it off. Any pointers?

Issue with OS_AUTH_URL with a trailing slash

Hello Dmitry!
I can't access containers in a named region.

Here's what I source before running my code:

#!/bin/bash
export OS_AUTH_URL=https://auth.cloud.ovh.net/v3/
export OS_IDENTITY_API_VERSION=3
export OS_USER_DOMAIN_NAME='Default'
export OS_PROJECT_DOMAIN_NAME='Default'
export OS_PROJECT_ID='<redacted>'
export OS_USERNAME='<redacted>'
export OS_PASSWORD='<redacted>'
export OS_REGION_NAME='DE'

My code:

# src/main.rs
extern crate openstack;

fn cloud_from_env() -> openstack::Result<openstack::Cloud> {
    let mut cloud = openstack::Cloud::from_env()?;
    {
        let filters = cloud.endpoint_filters_mut();
        filters.set_region("DE");
    }
    Ok(cloud)
}

fn main() {
    let os = cloud_from_env().expect("Failed to create an identity provider from the environment");

    let containers = os.list_containers();

    println!("Name: {:?}", containers);
}

Gives:

Name: Err(Error { kind: ResourceNotFound, message: "The resource could not be found.", status: Some(404) })

In the same shell (with the same env) openstack container list gives one result.

What am I doing wrong?

List compute examples fail

list-keypairs.rs and list-servers.rs from examples directory don't seem to work.
All the other list-*.rs examples work fine.

I get this error when running list-servers.rs (and the same error when running list-keypairs.rs):

$ RUST_BACKTRACE=full cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.09s
     Running `target/debug/openstack`
thread 'main' panicked at 'Cannot list servers: Error { kind: EndpointNotFound, message: "Endpoint for service compute was not found", status: None }', src/libcore/result.rs:999:5
stack backtrace:
   0:     0x55caf003e1fb - std::panicking::default_hook::{{closure}}::ha6347d45d6ce78e6
   1:     0x55caf003ded7 - std::panicking::default_hook::h710ef7fef9effc11
   2:     0x55caf003e970 - std::panicking::rust_panic_with_hook::h76ef5746177cf2f1
   3:     0x55caf003e4f2 - std::panicking::continue_panic_fmt::h1bc636947a39411e
   4:     0x55caf003e3d6 - rust_begin_unwind
   5:     0x55caf0056a3d - core::panicking::panic_fmt::h1858cc192bbf4d30
   6:     0x55caef5a4ea3 - core::result::unwrap_failed::hfff6da115b3fa5b4
                               at /builddir/build/BUILD/rustc-1.37.0-src/src/libcore/macros.rs:18
   7:     0x55caef5a51fa - core::result::Result<T,E>::expect::he640bb0f24fc5474
                               at /builddir/build/BUILD/rustc-1.37.0-src/src/libcore/result.rs:827
   8:     0x55caef5a4690 - openstack::main::h0508d5cdcc1d742d
                               at src/main.rs:29
   9:     0x55caef5a5c40 - std::rt::lang_start::{{closure}}::hda5be38dd52a3df8
                               at /builddir/build/BUILD/rustc-1.37.0-src/src/libstd/rt.rs:64
  10:     0x55caf003e373 - std::panicking::try::do_call::h0ad313ed04aaa877
  11:     0x55caf0041fba - __rust_maybe_catch_panic
  12:     0x55caf003ef3d - std::rt::lang_start_internal::h1765bcf229d6c7c6
  13:     0x55caef5a5c19 - std::rt::lang_start::he071acc26c4d85b0
                               at /builddir/build/BUILD/rustc-1.37.0-src/src/libstd/rt.rs:64
  14:     0x55caef5a4cfa - main
  15:     0x7fcb2be3ff33 - __libc_start_main
  16:     0x55caef5a223e - _start
  17:                0x0 - <unknown>

My service catalog seems fine. It works with the openstack CLI.

$ openstack endpoint list --service compute
+----------------------------------+-------------------+--------------+--------------+---------+-----------+-------------------------------------------------------------------------+
| ID                               | Region            | Service Name | Service Type | Enabled | Interface | URL                                                                     |
+----------------------------------+-------------------+--------------+--------------+---------+-----------+-------------------------------------------------------------------------+
| a6c52b6a89d346d585f4aa2e761a02d2 | <redacted> | nova         | compute      | True    | internal  | http://<redacted>:8774/v2.1/%(tenant_id)s                           |
| b23551a517c949a18f90eb9ec08caaac | <redacted> | nova         | compute      | True    | admin     | https://<redacted>:8774/v2.1/%(tenant_id)s                          |
| df71538ee05542df9dbcbaf6cc5e512d | <redacted> | nova         | compute      | True    | public    | https://<redacted>:8774/v2.1/%(tenant_id)s |
+----------------------------------+-------------------+--------------+--------------+---------+-----------+-------------------------------------------------------------------------+

My cargo.toml:

[package]
name = "openstack"
version = "0.1.0"
authors = ["Martin Chlumsky <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = ["compute", "image", "network"]
compute = []
image = []
network = []


[dependencies]
openstack = "0.3.0"
waiter = "0.1.1"
fallible-iterator = "0.2.0"
env_logger = "0.6.0"

Thank you!

Implement floating IP API

  • Getting/listing floating IPs
  • Creating floating IPs
  • Attaching/detaching floating IPs
  • Deleting floating IPs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.