Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Commit

Permalink
Merge pull request #392 from cloudflare/alewis/feat-create-namespace
Browse files Browse the repository at this point in the history
feat create namespace
  • Loading branch information
ashleymichal authored Aug 6, 2019
2 parents f3d492a + be5bd24 commit 374860d
Show file tree
Hide file tree
Showing 10 changed files with 380 additions and 2 deletions.
221 changes: 221 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ build = "build.rs"
atty = "0.2.11"
binary-install = "0.0.3-alpha"
clap = "2.32.0"
cloudflare = { git = "https://github.com/cloudflare/cloudflare-rs.git" }
config = "0.9.2"
console = "0.7.5"
dirs = "1.0.5"
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ cargo install wrangler
wrangler preview get // this is the default
```

- ### πŸ—‚οΈ `kv`
Interact with your Cloudflare Workers KV store. [Check out the docs.](./docs/content/kv)


## πŸ”© Configuration

Expand Down
27 changes: 27 additions & 0 deletions docs/content/kv_commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# πŸ—‚οΈ `kv`

## Overview

The `kv` subcommand allows you to store application data in the Cloudflare network to be accessed from Workers. KV operations are scoped to your account, so in order to use any of these commands, you need to:

* have a Wrangler project set up with your `account_id` configured in the `wrangler.toml`
* call commands from within a Wrangler project directory.

<!-- TODO: add gif of `wrangler generate` through `wrangler kv create` -->

## Commands

### ✨ `create <namespace-title>`

Creates a new namespace.

#### Usage

``` sh
$ wrangler kv create "new kv namespace"
πŸŒ€ Creating namespace with title "new kv namespace" πŸŒ€
✨ Success: WorkersKVNamespace {
id: "f7b02e7fc70443149ac906dd81ec1791",
title: "new kv namespace",
}
```
25 changes: 25 additions & 0 deletions src/commands/kv/create_namespace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use cloudflare::apiclient::APIClient;

use cloudflare::workerskv::create_namespace::CreateNamespace;
use cloudflare::workerskv::create_namespace::CreateNamespaceParams;

use crate::terminal::message;

pub fn create_namespace(title: &str) -> Result<(), failure::Error> {
let client = super::api_client()?;
let account_id = super::account_id()?;

let msg = format!("Creating namespace with title \"{}\"", title);
message::working(&msg);

let response = client.request(&CreateNamespace {
account_identifier: &account_id,
params: CreateNamespaceParams {
title: title.to_string(),
},
});

super::print_response(response);

Ok(())
}
66 changes: 66 additions & 0 deletions src/commands/kv/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use cloudflare::auth::Credentials;
use cloudflare::response::APIFailure;
use cloudflare::response::APIResponse;
use cloudflare::response::APIResult;
use cloudflare::HTTPAPIClient;

use crate::settings;
use crate::terminal::message;

mod create_namespace;

pub use create_namespace::create_namespace;

fn api_client() -> Result<HTTPAPIClient, failure::Error> {
let user = settings::global_user::GlobalUser::new()?;

Ok(HTTPAPIClient::new(Credentials::from(user)))
}

fn account_id() -> Result<String, failure::Error> {
let project = settings::project::Project::new()?;
// we need to be certain that account id is present to make kv calls
if project.account_id.is_empty() {
panic!("Your wrangler.toml is missing the account_id field which is required to create KV namespaces!");
}
Ok(project.account_id)
}

fn print_response<T: APIResult>(response: APIResponse<T>) {
match response {
Ok(success) => message::success(&format!("Success: {:#?}", success.result)),
Err(e) => match e {
APIFailure::Error(_status, errors) => {
for error in errors {
message::warn(&format!("Error {}: {}", error.code, error.message,));

let suggestion = help(error.code);
if !suggestion.is_empty() {
message::help(suggestion);
}
}
}
APIFailure::Invalid(reqwest_err) => message::warn(&format!("Error: {}", reqwest_err)),
},
}
}

fn help(error_code: u16) -> &'static str {
// https://api.cloudflare.com/#workers-kv-namespace-errors
match error_code {
// namespace errors
10010 | 10011 | 10012 | 10013 | 10014 | 10018 => {
"Run `wrangler kv list` to see your existing namespaces with IDs"
}
10009 => "Run `wrangler kv list <namespaceID>` to see your existing keys", // key errors
// TODO: link to more info
// limit errors
10022 | 10024 | 10030 => "See documentation",
// TODO: link to tool for this?
// legacy namespace errors
10021 | 10035 | 10038 => "Consider moving this namespace",
// cloudflare account errors
10017 | 10026 => "Check your account settings in the Cloudflare dashboard",
_ => "",
}
}
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod build;
pub mod config;
pub mod generate;
pub mod init;
pub mod kv;
pub mod publish;
pub mod subdomain;
pub mod whoami;
Expand Down
23 changes: 23 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod terminal;
use crate::settings::project::ProjectType;
use exitfailure::ExitFailure;
use terminal::emoji;
use terminal::message;

fn main() -> Result<(), ExitFailure> {
env_logger::init();
Expand All @@ -45,6 +46,19 @@ fn run() -> Result<(), failure::Error> {
.author("ashley g williams <[email protected]>")
.setting(AppSettings::ArgRequiredElseHelp)
.setting(AppSettings::DeriveDisplayOrder)
.subcommand(
SubCommand::with_name("kv")
.about(&*format!(
"{} Interact with your Workers KV Store",
emoji::KV
))
.subcommand(
SubCommand::with_name("create")
.arg(
Arg::with_name("title")
)
)
)
.subcommand(
SubCommand::with_name("generate")
.about(&*format!(
Expand Down Expand Up @@ -233,6 +247,15 @@ fn run() -> Result<(), failure::Error> {
.expect("The subdomain name you are requesting must be provided.");

commands::subdomain(name, &user, &project)?;
} else if let Some(kv_matches) = matches.subcommand_matches("kv") {
match kv_matches.subcommand() {
("create", Some(create_matches)) => {
let title = create_matches.value_of("title").unwrap();
commands::kv::create_namespace(title)?;
}
("", None) => message::warn("kv expects a subcommand"),
_ => unreachable!(),
}
}
Ok(())
}
10 changes: 10 additions & 0 deletions src/settings/global_user.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::env;
use std::path::{Path, PathBuf};

use cloudflare::auth::Credentials;
use log::info;
use serde::{Deserialize, Serialize};

Expand All @@ -19,6 +20,15 @@ impl GlobalUser {
}
}

impl From<GlobalUser> for Credentials {
fn from(user: GlobalUser) -> Credentials {
Credentials::User {
key: user.api_key,
email: user.email,
}
}
}

fn get_global_config() -> Result<GlobalUser, failure::Error> {
let mut s = Config::new();

Expand Down
5 changes: 3 additions & 2 deletions src/terminal/emoji.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ pub static DANCERS: Emoji = Emoji("πŸ‘― ", "");
pub static EYES: Emoji = Emoji("πŸ‘€ ", "");
pub static INBOX: Emoji = Emoji("πŸ“₯ ", "");
pub static INFO: Emoji = Emoji("πŸ’β€ ", "");
pub static KV: Emoji = Emoji("πŸ—‚οΈ ", "");
pub static MICROSCOPE: Emoji = Emoji("πŸ”¬ ", "");
pub static SHEEP: Emoji = Emoji("πŸ‘ ", "");
pub static SLEUTH: Emoji = Emoji("πŸ•΅οΈβ€β™‚οΈ", "");
pub static SPARKLES: Emoji = Emoji("✨ ", "");
pub static SLEUTH: Emoji = Emoji("πŸ•΅οΈβ€β™‚οΈ ", "");
pub static SPARKLES: Emoji = Emoji("✨ ", "");
pub static SWIRL: Emoji = Emoji("πŸŒ€ ", "");
pub static UP: Emoji = Emoji("πŸ†™ ", "");
pub static WARN: Emoji = Emoji("⚠️ ", "");
Expand Down

0 comments on commit 374860d

Please sign in to comment.