Getting a Keystone Token in Rust

Python is a great language, but sometimes I miss type safety. While I was always comfortable with C++, I know that the lanugague has it’s warts. Lately, I’ve been taking an interest in Rust, which seems to be set to address many of the shortcomiings of C++. What better way to learn it than to try and use on problems I already know well; OpenStack and Keystone? So, I wrote my first non-trivial program, which gets a Keystone token.

Here is my src/main.rs

 
 
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. See http://www.gnu.org/licenses/ 
*/
 
 
extern crate curl;
extern crate rustc_serialize;
 
 
use curl::http;
use rustc_serialize::json;
 
 
#[derive(RustcDecodable, RustcEncodable)]
struct Domain {
    name: String
}
#[derive(RustcDecodable, RustcEncodable)]
struct User {
    name: String,
    password: String,
    domain: Domain
}
 
#[derive(RustcDecodable, RustcEncodable)]
struct PasswordAuth {
    user: User
}
 
#[derive(RustcDecodable, RustcEncodable)]
struct Project{
    domain: Domain,
    name:  String
}
#[derive(RustcDecodable, RustcEncodable)]
struct Scope{
    project : Project
}
#[derive(RustcDecodable, RustcEncodable)]
struct Identity{
    methods: Vec<String>,
    password: PasswordAuth
}
 
#[derive(RustcDecodable, RustcEncodable)]
struct Auth{
    identity: Identity,
    scope: Scope
 
}
 
#[derive(RustcDecodable, RustcEncodable)]
struct TokenRequest{
    auth: Auth,
}
 
fn main() {
 
 
    let os_auth_url = env!("OS_AUTH_URL").to_string();
    let os_username = env!("OS_USERNAME").to_string();
    let os_password = env!("OS_PASSWORD").to_string();
    let os_project_name =
        env!("OS_PROJECT_NAME").to_string();  
    let os_project_domain_name =
        env!("OS_PROJECT_DOMAIN_NAME").to_string();  
    let os_user_domain_name =
        env!("OS_USER_DOMAIN_NAME").to_string();  
 
 
    let request = TokenRequest {
        auth: Auth{
            identity: Identity {
                methods: vec!["password".to_string()],
                password: PasswordAuth{
                    user: User{
                        name: os_username,
                        password: os_password,        
                        domain: Domain {
                            name: os_user_domain_name}
                    }
                }
            },
            scope: Scope {
                project:
                Project{
                    name: os_project_name,
                    domain: Domain{
                        name: os_project_domain_name
                    }
                }
            }
        }
    };
    let s = json::encode(&request).unwrap();
    let data: &str = &s;
 
    let token_request_url = os_auth_url.to_string()
        + "/auth/tokens";
    let resp = http::handle()
        .post(token_request_url, data)
        .header("Content-Type", "application/json")
        .exec().unwrap();
 
 
    let body = String::from_utf8_lossy(resp.get_body());
 
    println!("code={}; headers={:?}; body={}",
    resp.get_code(), resp.get_headers(), body);    
}

Here is the Cargo.toml file

[package]
 
name = "osrust"
version = "0.0.1"
authors = [ "Adam Young <adam@younglogic.com>" ]
 
 
[dependencies.curl]
git = "https://github.com/carllerche/curl-rust"
 
[dependencies]
rustc-serialize = "0.3.15"

My Directory structure looks like this:

./src
./src/main.rs
./Cargo.toml

Build it with:

cargo build

It reads the values necessary to connect to Keystone from environment variables, which I have in a file like this.

export OS_AUTH_URL=http://hostname:5000/v3
export OS_USERNAME=ayoung
export OS_PASSWORD=changeme
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_PROJECT_NAME=ChangeMe

To Run it

 . ~/keystonev3.rc
 ./target/debug/osrust

I decided to use Curl instead of rust-http, mainly due to the expectation that rust-http hasn’t dealt with Negotiate (GSSAPI, Kerberos) yet but Curl has. I want to use this approach to talk to IPA as well as to Keystone, using Kerberos for authentication. The rust-http would not be radically different.

5 thoughts on “Getting a Keystone Token in Rust

  1. rust is good ,esp. of systems programming.

    but, you should also try “Haxe” . (see http://www.haxe.org).
    1) It is also again a statically typed language
    2) haxe program compiles to java ,C++,python,C#, nodejs,PHP etc programs.
    So with one language you can run on any platform, any OS and any of the major VMs.
    3) haxe syntax is like Actionscript, C# or java. So one can easily learn its syntax, compared to rust etc, if he is coming from these backgrounds.
    also read:
    https://en.wikipedia.org/wiki/HaXe

  2. Thanks for the suggestion. I have limited bandwidth, I want native, not a VM language, and Rust has worked really hard at doing things right. One language at a time…

  3. I was surprised to not find an existing library to access openstack in rust! I think you should put this snippet on github as a basis for the future library 😉

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.