Merge pull request #978 from influxdata/runrun

feat: Rename server run command to just run
pull/24376/head
kodiakhq[bot] 2021-03-12 18:49:29 +00:00 committed by GitHub
commit 83e90a70ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 381 additions and 361 deletions

View File

@ -37,4 +37,4 @@ EXPOSE 8080 8082
ENTRYPOINT ["/usr/bin/influxdb_iox"]
CMD ["server", "run"]
CMD ["run"]

View File

@ -133,7 +133,7 @@ takes its configuration as environment variables.
You can see a list of the current configuration values by running `influxdb_iox
--help`, as well as the specific subcommand config options such as `influxdb_iox
server --help`.
run --help`.
Should you desire specifying config via a file, you can do so using a
`.env` formatted file in the working directory. You can use the
@ -175,7 +175,7 @@ cargo build --release
which will create the corresponding binary in `target/release`:
```shell
./target/release/influxdb_iox server
./target/release/influxdb_iox run
```
Similarly, you can do this in one step with:

View File

@ -21,4 +21,4 @@ EXPOSE 8080 8082
ENTRYPOINT ["influxdb_iox"]
CMD ["server", "run"]
CMD ["run"]

View File

@ -7,7 +7,7 @@
# The full list of available configuration values can be found by in
# the command line help (e.g. `env: INFLUXDB_IOX_DB_DIR=`):
#
# ./influxdb_iox server --help
# ./influxdb_iox run --help
#
#
# The identifier for the server. Used for writing to object storage and as

View File

@ -21,14 +21,14 @@ of the object stores, the relevant tests will run.
### Configuration differences when running the tests
When running `influxdb_iox server`, you can pick one object store to use. When running the tests,
When running `influxdb_iox run`, you can pick one object store to use. When running the tests,
you can run them against all the possible object stores. There's still only one
`INFLUXDB_IOX_BUCKET` variable, though, so that will set the bucket name for all configured object
stores. Use the same bucket name when setting up the different services.
Other than possibly configuring multiple object stores, configuring the tests to use the object
store services is the same as configuring the server to use an object store service. See the output
of `influxdb_iox server --help` for instructions.
of `influxdb_iox run --help` for instructions.
## InfluxDB IOx Client

View File

@ -2,7 +2,7 @@
use tracing_subscriber::{prelude::*, EnvFilter};
use super::server::{LogFormat, RunConfig};
use super::run::{Config, LogFormat};
/// Handles setting up logging levels
#[derive(Debug)]
@ -81,7 +81,7 @@ impl LoggingLevel {
/// Configures logging and tracing, based on the configuration
/// values, for the IOx server (the whole enchalada)
pub fn setup_logging(&self, config: &RunConfig) -> Option<opentelemetry_jaeger::Uninstall> {
pub fn setup_logging(&self, config: &Config) -> Option<opentelemetry_jaeger::Uninstall> {
// Copy anything from the config to the rust log environment
self.set_rust_log_if_needed(config.rust_log.clone());

341
src/commands/run.rs Normal file
View File

@ -0,0 +1,341 @@
//! Implementation of command line option for running server
use crate::commands::logging::LoggingLevel;
use crate::influxdb_ioxd;
use clap::arg_enum;
use std::{net::SocketAddr, net::ToSocketAddrs, path::PathBuf};
use structopt::StructOpt;
use thiserror::Error;
/// The default bind address for the HTTP API.
pub const DEFAULT_API_BIND_ADDR: &str = "127.0.0.1:8080";
/// The default bind address for the gRPC.
pub const DEFAULT_GRPC_BIND_ADDR: &str = "127.0.0.1:8082";
/// The AWS region to use for Amazon S3 based object storage if none is
/// specified.
pub const FALLBACK_AWS_REGION: &str = "us-east-1";
#[derive(Debug, Error)]
pub enum Error {
#[error("Run: {0}")]
ServerError(#[from] influxdb_ioxd::Error),
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, StructOpt)]
#[structopt(
name = "run",
about = "Runs in server mode",
long_about = "Run the IOx server.\n\nThe configuration options below can be \
set either with the command line flags or with the specified environment \
variable. If there is a file named '.env' in the current working directory, \
it is sourced before loading the configuration.
Configuration is loaded from the following sources (highest precedence first):
- command line arguments
- user set environment variables
- .env file contents
- pre-configured default values"
)]
pub struct Config {
/// This controls the IOx server logging level, as described in
/// https://crates.io/crates/env_logger.
///
/// Levels for different modules can be specified as well. For example
/// `debug,hyper::proto::h1=info` specifies debug logging for all modules
/// except for the `hyper::proto::h1' module which will only display info
/// level logging.
#[structopt(long = "--log", env = "RUST_LOG")]
pub rust_log: Option<String>,
/// Log message format. Can be one of:
///
/// "rust" (default)
/// "logfmt" (logfmt/Heroku style - https://brandur.org/logfmt)
#[structopt(long = "--log_format", env = "INFLUXDB_IOX_LOG_FORMAT")]
pub log_format: Option<LogFormat>,
/// This sets logging up with a pre-configured set of convenient log levels.
///
/// -v means 'info' log levels
/// -vv means 'verbose' log level (with the exception of some particularly
/// low level libraries)
///
/// This option is ignored if --log / RUST_LOG are set
#[structopt(
short = "-v",
long = "--verbose",
multiple = true,
takes_value = false,
parse(from_occurrences)
)]
pub verbose_count: u64,
/// The identifier for the server.
///
/// Used for writing to object storage and as an identifier that is added to
/// replicated writes, WAL segments and Chunks. Must be unique in a group of
/// connected or semi-connected IOx servers. Must be a number that can be
/// represented by a 32-bit unsigned integer.
#[structopt(long = "--writer-id", env = "INFLUXDB_IOX_ID")]
pub writer_id: Option<u32>,
/// The address on which IOx will serve HTTP API requests.
#[structopt(
long = "--api-bind",
env = "INFLUXDB_IOX_BIND_ADDR",
default_value = DEFAULT_API_BIND_ADDR,
parse(try_from_str = parse_socket_addr),
)]
pub http_bind_address: SocketAddr,
/// The address on which IOx will serve Storage gRPC API requests.
#[structopt(
long = "--grpc-bind",
env = "INFLUXDB_IOX_GRPC_BIND_ADDR",
default_value = DEFAULT_GRPC_BIND_ADDR,
parse(try_from_str = parse_socket_addr),
)]
pub grpc_bind_address: SocketAddr,
/// The location InfluxDB IOx will use to store files locally.
#[structopt(long = "--data-dir", env = "INFLUXDB_IOX_DB_DIR")]
pub database_directory: Option<PathBuf>,
#[structopt(
long = "--object-store",
env = "INFLUXDB_IOX_OBJECT_STORE",
possible_values = &ObjectStore::variants(),
case_insensitive = true,
long_help = r#"Which object storage to use. If not specified, defaults to memory.
Possible values (case insensitive):
* memory (default): Effectively no object persistence.
* file: Stores objects in the local filesystem. Must also set `--data-dir`.
* s3: Amazon S3. Must also set `--bucket`, `--aws-access-key-id`, `--aws-secret-access-key`, and
possibly `--aws-default-region`.
* google: Google Cloud Storage. Must also set `--bucket` and `--google-service-account`.
* azure: Microsoft Azure blob storage. Must also set `--bucket`, `--azure-storage-account`,
and `--azure-storage-access-key`.
"#,
)]
pub object_store: Option<ObjectStore>,
/// Name of the bucket to use for the object store. Must also set
/// `--object-store` to a cloud object storage to have any effect.
///
/// If using Google Cloud Storage for the object store, this item as well
/// as `--google-service-account` must be set.
///
/// If using S3 for the object store, must set this item as well
/// as `--aws-access-key-id` and `--aws-secret-access-key`. Can also set
/// `--aws-default-region` if not using the fallback region.
///
/// If using Azure for the object store, set this item to the name of a
/// container you've created in the associated storage account, under
/// Blob Service > Containers. Must also set `--azure-storage-account` and
/// `--azure-storage-access-key`.
#[structopt(long = "--bucket", env = "INFLUXDB_IOX_BUCKET")]
pub bucket: Option<String>,
/// When using Amazon S3 as the object store, set this to an access key that
/// has permission to read from and write to the specified S3 bucket.
///
/// Must also set `--object-store=s3`, `--bucket`, and
/// `--aws-secret-access-key`. Can also set `--aws-default-region` if not
/// using the fallback region.
///
/// Prefer the environment variable over the command line flag in shared
/// environments.
#[structopt(long = "--aws-access-key-id", env = "AWS_ACCESS_KEY_ID")]
pub aws_access_key_id: Option<String>,
/// When using Amazon S3 as the object store, set this to the secret access
/// key that goes with the specified access key ID.
///
/// Must also set `--object-store=s3`, `--bucket`, `--aws-access-key-id`.
/// Can also set `--aws-default-region` if not using the fallback region.
///
/// Prefer the environment variable over the command line flag in shared
/// environments.
#[structopt(long = "--aws-secret-access-key", env = "AWS_SECRET_ACCESS_KEY")]
pub aws_secret_access_key: Option<String>,
/// When using Amazon S3 as the object store, set this to the region
/// that goes with the specified bucket if different from the fallback
/// value.
///
/// Must also set `--object-store=s3`, `--bucket`, `--aws-access-key-id`,
/// and `--aws-secret-access-key`.
#[structopt(
long = "--aws-default-region",
env = "AWS_DEFAULT_REGION",
default_value = FALLBACK_AWS_REGION,
)]
pub aws_default_region: String,
/// When using Google Cloud Storage as the object store, set this to the
/// path to the JSON file that contains the Google credentials.
///
/// Must also set `--object-store=google` and `--bucket`.
#[structopt(long = "--google-service-account", env = "GOOGLE_SERVICE_ACCOUNT")]
pub google_service_account: Option<String>,
/// When using Microsoft Azure as the object store, set this to the
/// name you see when going to All Services > Storage accounts > [name].
///
/// Must also set `--object-store=azure`, `--bucket`, and
/// `--azure-storage-access-key`.
#[structopt(long = "--azure-storage-account", env = "AZURE_STORAGE_ACCOUNT")]
pub azure_storage_account: Option<String>,
/// When using Microsoft Azure as the object store, set this to one of the
/// Key values in the Storage account's Settings > Access keys.
///
/// Must also set `--object-store=azure`, `--bucket`, and
/// `--azure-storage-account`.
///
/// Prefer the environment variable over the command line flag in shared
/// environments.
#[structopt(long = "--azure-storage-access-key", env = "AZURE_STORAGE_ACCESS_KEY")]
pub azure_storage_access_key: Option<String>,
/// If set, Jaeger traces are emitted to this host
/// using the OpenTelemetry tracer.
///
/// NOTE: The OpenTelemetry agent CAN ONLY be
/// configured using environment variables. It CAN NOT be configured
/// using the command line at this time. Some useful variables:
///
/// * OTEL_SERVICE_NAME: emitter service name (iox by default)
/// * OTEL_EXPORTER_JAEGER_AGENT_HOST: hostname/address of the collector
/// * OTEL_EXPORTER_JAEGER_AGENT_PORT: listening port of the collector.
///
/// The entire list of variables can be found in
/// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/sdk-environment-variables.md#jaeger-exporter
#[structopt(
long = "--oetl_exporter_jaeger_agent",
env = "OTEL_EXPORTER_JAEGER_AGENT_HOST"
)]
pub jaeger_host: Option<String>,
}
pub async fn command(logging_level: LoggingLevel, config: Config) -> Result<()> {
Ok(influxdb_ioxd::main(logging_level, config).await?)
}
fn parse_socket_addr(s: &str) -> std::io::Result<SocketAddr> {
let mut addrs = s.to_socket_addrs()?;
// when name resolution fails, to_socket_address returns a validation error
// so generally there is at least one result address, unless the resolver is
// drunk.
Ok(addrs
.next()
.expect("name resolution should return at least one address"))
}
arg_enum! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ObjectStore {
Memory,
File,
S3,
Google,
Azure,
}
}
/// How to format output logging messages
#[derive(Debug, Clone, Copy)]
pub enum LogFormat {
/// Default formatted logging
///
/// Example:
/// ```
/// level=warn msg="NO PERSISTENCE: using memory for object storage" target="influxdb_iox::influxdb_ioxd"
/// ```
Rust,
/// Use the (somwhat pretentiously named) Heroku / logfmt formatted output
/// format
///
/// Example:
/// ```
/// Jan 31 13:19:39.059 WARN influxdb_iox::influxdb_ioxd: NO PERSISTENCE: using memory for object storage
/// ```
LogFmt,
}
impl Default for LogFormat {
fn default() -> Self {
Self::Rust
}
}
impl std::str::FromStr for LogFormat {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"rust" => Ok(Self::Rust),
"logfmt" => Ok(Self::LogFmt),
_ => Err(format!(
"Invalid log format '{}'. Valid options: rust, logfmt",
s
)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
fn to_vec(v: &[&str]) -> Vec<String> {
v.iter().map(|s| s.to_string()).collect()
}
#[test]
fn test_socketaddr() -> Result<(), clap::Error> {
let c = Config::from_iter_safe(
to_vec(&["server", "--api-bind", "127.0.0.1:1234"]).into_iter(),
)?;
assert_eq!(
c.http_bind_address,
SocketAddr::from(([127, 0, 0, 1], 1234))
);
let c = Config::from_iter_safe(
to_vec(&["server", "--api-bind", "localhost:1234"]).into_iter(),
)?;
// depending on where the test runs, localhost will either resolve to a ipv4 or
// an ipv6 addr.
match c.http_bind_address {
SocketAddr::V4(so) => {
assert_eq!(so, SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1234))
}
SocketAddr::V6(so) => assert_eq!(
so,
SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 1234, 0, 0)
),
};
assert_eq!(
Config::from_iter_safe(
to_vec(&["server", "--api-bind", "!@INv_a1d(ad0/resp_!"]).into_iter(),
)
.map_err(|e| e.kind)
.expect_err("must fail"),
clap::ErrorKind::ValueValidation
);
Ok(())
}
}

View File

@ -1,27 +1,12 @@
//! Implementation of command line option for manipulating and showing server
//! config
use crate::commands::{logging::LoggingLevel, server_remote};
use crate::influxdb_ioxd;
use clap::arg_enum;
use std::{net::SocketAddr, net::ToSocketAddrs, path::PathBuf};
use crate::commands::server_remote;
use structopt::StructOpt;
use thiserror::Error;
/// The default bind address for the HTTP API.
pub const DEFAULT_API_BIND_ADDR: &str = "127.0.0.1:8080";
/// The default bind address for the gRPC.
pub const DEFAULT_GRPC_BIND_ADDR: &str = "127.0.0.1:8082";
/// The AWS region to use for Amazon S3 based object storage if none is
/// specified.
pub const FALLBACK_AWS_REGION: &str = "us-east-1";
#[derive(Debug, Error)]
pub enum Error {
#[error("Run: {0}")]
ServerError(#[from] influxdb_ioxd::Error),
#[error("Remote: {0}")]
RemoteError(#[from] server_remote::Error),
}
@ -31,324 +16,11 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, StructOpt)]
#[structopt(name = "server", about = "IOx server commands")]
pub enum Config {
Run(RunConfig),
Remote(crate::commands::server_remote::Config),
}
#[derive(Debug, StructOpt)]
#[structopt(
name = "run",
about = "Runs in server mode",
long_about = "Run the IOx server.\n\nThe configuration options below can be \
set either with the command line flags or with the specified environment \
variable. If there is a file named '.env' in the current working directory, \
it is sourced before loading the configuration.
Configuration is loaded from the following sources (highest precedence first):
- command line arguments
- user set environment variables
- .env file contents
- pre-configured default values"
)]
pub struct RunConfig {
/// This controls the IOx server logging level, as described in
/// https://crates.io/crates/env_logger.
///
/// Levels for different modules can be specified as well. For example
/// `debug,hyper::proto::h1=info` specifies debug logging for all modules
/// except for the `hyper::proto::h1' module which will only display info
/// level logging.
#[structopt(long = "--log", env = "RUST_LOG")]
pub rust_log: Option<String>,
/// Log message format. Can be one of:
///
/// "rust" (default)
/// "logfmt" (logfmt/Heroku style - https://brandur.org/logfmt)
#[structopt(long = "--log_format", env = "INFLUXDB_IOX_LOG_FORMAT")]
pub log_format: Option<LogFormat>,
/// This sets logging up with a pre-configured set of convenient log levels.
///
/// -v means 'info' log levels
/// -vv means 'verbose' log level (with the exception of some particularly
/// low level libraries)
///
/// This option is ignored if --log / RUST_LOG are set
#[structopt(
short = "-v",
long = "--verbose",
multiple = true,
takes_value = false,
parse(from_occurrences)
)]
pub verbose_count: u64,
/// The identifier for the server.
///
/// Used for writing to object storage and as an identifier that is added to
/// replicated writes, WAL segments and Chunks. Must be unique in a group of
/// connected or semi-connected IOx servers. Must be a number that can be
/// represented by a 32-bit unsigned integer.
#[structopt(long = "--writer-id", env = "INFLUXDB_IOX_ID")]
pub writer_id: Option<u32>,
/// The address on which IOx will serve HTTP API requests.
#[structopt(
long = "--api-bind",
env = "INFLUXDB_IOX_BIND_ADDR",
default_value = DEFAULT_API_BIND_ADDR,
parse(try_from_str = parse_socket_addr),
)]
pub http_bind_address: SocketAddr,
/// The address on which IOx will serve Storage gRPC API requests.
#[structopt(
long = "--grpc-bind",
env = "INFLUXDB_IOX_GRPC_BIND_ADDR",
default_value = DEFAULT_GRPC_BIND_ADDR,
parse(try_from_str = parse_socket_addr),
)]
pub grpc_bind_address: SocketAddr,
/// The location InfluxDB IOx will use to store files locally.
#[structopt(long = "--data-dir", env = "INFLUXDB_IOX_DB_DIR")]
pub database_directory: Option<PathBuf>,
#[structopt(
long = "--object-store",
env = "INFLUXDB_IOX_OBJECT_STORE",
possible_values = &ObjectStore::variants(),
case_insensitive = true,
long_help = r#"Which object storage to use. If not specified, defaults to memory.
Possible values (case insensitive):
* memory (default): Effectively no object persistence.
* file: Stores objects in the local filesystem. Must also set `--data-dir`.
* s3: Amazon S3. Must also set `--bucket`, `--aws-access-key-id`, `--aws-secret-access-key`, and
possibly `--aws-default-region`.
* google: Google Cloud Storage. Must also set `--bucket` and `--google-service-account`.
* azure: Microsoft Azure blob storage. Must also set `--bucket`, `--azure-storage-account`,
and `--azure-storage-access-key`.
"#,
)]
pub object_store: Option<ObjectStore>,
/// Name of the bucket to use for the object store. Must also set
/// `--object-store` to a cloud object storage to have any effect.
///
/// If using Google Cloud Storage for the object store, this item as well
/// as `--google-service-account` must be set.
///
/// If using S3 for the object store, must set this item as well
/// as `--aws-access-key-id` and `--aws-secret-access-key`. Can also set
/// `--aws-default-region` if not using the fallback region.
///
/// If using Azure for the object store, set this item to the name of a
/// container you've created in the associated storage account, under
/// Blob Service > Containers. Must also set `--azure-storage-account` and
/// `--azure-storage-access-key`.
#[structopt(long = "--bucket", env = "INFLUXDB_IOX_BUCKET")]
pub bucket: Option<String>,
/// When using Amazon S3 as the object store, set this to an access key that
/// has permission to read from and write to the specified S3 bucket.
///
/// Must also set `--object-store=s3`, `--bucket`, and
/// `--aws-secret-access-key`. Can also set `--aws-default-region` if not
/// using the fallback region.
///
/// Prefer the environment variable over the command line flag in shared
/// environments.
#[structopt(long = "--aws-access-key-id", env = "AWS_ACCESS_KEY_ID")]
pub aws_access_key_id: Option<String>,
/// When using Amazon S3 as the object store, set this to the secret access
/// key that goes with the specified access key ID.
///
/// Must also set `--object-store=s3`, `--bucket`, `--aws-access-key-id`.
/// Can also set `--aws-default-region` if not using the fallback region.
///
/// Prefer the environment variable over the command line flag in shared
/// environments.
#[structopt(long = "--aws-secret-access-key", env = "AWS_SECRET_ACCESS_KEY")]
pub aws_secret_access_key: Option<String>,
/// When using Amazon S3 as the object store, set this to the region
/// that goes with the specified bucket if different from the fallback
/// value.
///
/// Must also set `--object-store=s3`, `--bucket`, `--aws-access-key-id`,
/// and `--aws-secret-access-key`.
#[structopt(
long = "--aws-default-region",
env = "AWS_DEFAULT_REGION",
default_value = FALLBACK_AWS_REGION,
)]
pub aws_default_region: String,
/// When using Google Cloud Storage as the object store, set this to the
/// path to the JSON file that contains the Google credentials.
///
/// Must also set `--object-store=google` and `--bucket`.
#[structopt(long = "--google-service-account", env = "GOOGLE_SERVICE_ACCOUNT")]
pub google_service_account: Option<String>,
/// When using Microsoft Azure as the object store, set this to the
/// name you see when going to All Services > Storage accounts > [name].
///
/// Must also set `--object-store=azure`, `--bucket`, and
/// `--azure-storage-access-key`.
#[structopt(long = "--azure-storage-account", env = "AZURE_STORAGE_ACCOUNT")]
pub azure_storage_account: Option<String>,
/// When using Microsoft Azure as the object store, set this to one of the
/// Key values in the Storage account's Settings > Access keys.
///
/// Must also set `--object-store=azure`, `--bucket`, and
/// `--azure-storage-account`.
///
/// Prefer the environment variable over the command line flag in shared
/// environments.
#[structopt(long = "--azure-storage-access-key", env = "AZURE_STORAGE_ACCESS_KEY")]
pub azure_storage_access_key: Option<String>,
/// If set, Jaeger traces are emitted to this host
/// using the OpenTelemetry tracer.
///
/// NOTE: The OpenTelemetry agent CAN ONLY be
/// configured using environment variables. It CAN NOT be configured
/// using the command line at this time. Some useful variables:
///
/// * OTEL_SERVICE_NAME: emitter service name (iox by default)
/// * OTEL_EXPORTER_JAEGER_AGENT_HOST: hostname/address of the collector
/// * OTEL_EXPORTER_JAEGER_AGENT_PORT: listening port of the collector.
///
/// The entire list of variables can be found in
/// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/sdk-environment-variables.md#jaeger-exporter
#[structopt(
long = "--oetl_exporter_jaeger_agent",
env = "OTEL_EXPORTER_JAEGER_AGENT_HOST"
)]
pub jaeger_host: Option<String>,
}
pub async fn command(logging_level: LoggingLevel, url: String, config: Config) -> Result<()> {
pub async fn command(url: String, config: Config) -> Result<()> {
match config {
Config::Run(config) => Ok(influxdb_ioxd::main(logging_level, config).await?),
Config::Remote(config) => Ok(server_remote::command(url, config).await?),
}
}
fn parse_socket_addr(s: &str) -> std::io::Result<SocketAddr> {
let mut addrs = s.to_socket_addrs()?;
// when name resolution fails, to_socket_address returns a validation error
// so generally there is at least one result address, unless the resolver is
// drunk.
Ok(addrs
.next()
.expect("name resolution should return at least one address"))
}
arg_enum! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ObjectStore {
Memory,
File,
S3,
Google,
Azure,
}
}
/// How to format output logging messages
#[derive(Debug, Clone, Copy)]
pub enum LogFormat {
/// Default formatted logging
///
/// Example:
/// ```
/// level=warn msg="NO PERSISTENCE: using memory for object storage" target="influxdb_iox::influxdb_ioxd"
/// ```
Rust,
/// Use the (somwhat pretentiously named) Heroku / logfmt formatted output
/// format
///
/// Example:
/// ```
/// Jan 31 13:19:39.059 WARN influxdb_iox::influxdb_ioxd: NO PERSISTENCE: using memory for object storage
/// ```
LogFmt,
}
impl Default for LogFormat {
fn default() -> Self {
Self::Rust
}
}
impl std::str::FromStr for LogFormat {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"rust" => Ok(Self::Rust),
"logfmt" => Ok(Self::LogFmt),
_ => Err(format!(
"Invalid log format '{}'. Valid options: rust, logfmt",
s
)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
fn to_vec(v: &[&str]) -> Vec<String> {
v.iter().map(|s| s.to_string()).collect()
}
#[test]
fn test_socketaddr() -> Result<(), clap::Error> {
let c = RunConfig::from_iter_safe(
to_vec(&["server", "--api-bind", "127.0.0.1:1234"]).into_iter(),
)?;
assert_eq!(
c.http_bind_address,
SocketAddr::from(([127, 0, 0, 1], 1234))
);
let c = RunConfig::from_iter_safe(
to_vec(&["server", "--api-bind", "localhost:1234"]).into_iter(),
)?;
// depending on where the test runs, localhost will either resolve to a ipv4 or
// an ipv6 addr.
match c.http_bind_address {
SocketAddr::V4(so) => {
assert_eq!(so, SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1234))
}
SocketAddr::V6(so) => assert_eq!(
so,
SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 1234, 0, 0)
),
};
assert_eq!(
RunConfig::from_iter_safe(
to_vec(&["server", "--api-bind", "!@INv_a1d(ad0/resp_!"]).into_iter(),
)
.map_err(|e| e.kind)
.expect_err("must fail"),
clap::ErrorKind::ValueValidation
);
Ok(())
}
}

View File

@ -1,6 +1,6 @@
use crate::commands::{
logging::LoggingLevel,
server::{ObjectStore as ObjStoreOpt, RunConfig},
run::{Config, ObjectStore as ObjStoreOpt},
};
use hyper::Server;
use object_store::{
@ -73,7 +73,7 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
///
/// The logging_level passed in is the global setting (e.g. if -v or
/// -vv was passed in before 'server')
pub async fn main(logging_level: LoggingLevel, config: RunConfig) -> Result<()> {
pub async fn main(logging_level: LoggingLevel, config: Config) -> Result<()> {
// Handle the case if -v/-vv is specified both before and after the server
// command
let logging_level = logging_level.combine(LoggingLevel::new(config.verbose_count));
@ -155,10 +155,10 @@ pub async fn main(logging_level: LoggingLevel, config: RunConfig) -> Result<()>
Ok(())
}
impl TryFrom<&RunConfig> for ObjectStore {
impl TryFrom<&Config> for ObjectStore {
type Error = Error;
fn try_from(config: &RunConfig) -> Result<Self, Self::Error> {
fn try_from(config: &Config) -> Result<Self, Self::Error> {
match config.object_store {
Some(ObjStoreOpt::Memory) | None => {
Ok(Self::new_in_memory(object_store::memory::InMemory::new()))
@ -285,7 +285,7 @@ mod tests {
#[test]
fn default_object_store_is_memory() {
let config = RunConfig::from_iter_safe(&["server"]).unwrap();
let config = Config::from_iter_safe(&["server"]).unwrap();
let object_store = ObjectStore::try_from(&config).unwrap();
@ -297,7 +297,7 @@ mod tests {
#[test]
fn explicitly_set_object_store_to_memory() {
let config = RunConfig::from_iter_safe(&["server", "--object-store", "memory"]).unwrap();
let config = Config::from_iter_safe(&["server", "--object-store", "memory"]).unwrap();
let object_store = ObjectStore::try_from(&config).unwrap();
@ -309,7 +309,7 @@ mod tests {
#[test]
fn valid_s3_config() {
let config = RunConfig::from_iter_safe(&[
let config = Config::from_iter_safe(&[
"server",
"--object-store",
"s3",
@ -332,7 +332,7 @@ mod tests {
#[test]
fn s3_config_missing_params() {
let config = RunConfig::from_iter_safe(&["server", "--object-store", "s3"]).unwrap();
let config = Config::from_iter_safe(&["server", "--object-store", "s3"]).unwrap();
let err = ObjectStore::try_from(&config).unwrap_err().to_string();
@ -345,7 +345,7 @@ mod tests {
#[test]
fn valid_google_config() {
let config = RunConfig::from_iter_safe(&[
let config = Config::from_iter_safe(&[
"server",
"--object-store",
"google",
@ -366,7 +366,7 @@ mod tests {
#[test]
fn google_config_missing_params() {
let config = RunConfig::from_iter_safe(&["server", "--object-store", "google"]).unwrap();
let config = Config::from_iter_safe(&["server", "--object-store", "google"]).unwrap();
let err = ObjectStore::try_from(&config).unwrap_err().to_string();
@ -379,7 +379,7 @@ mod tests {
#[test]
fn valid_azure_config() {
let config = RunConfig::from_iter_safe(&[
let config = Config::from_iter_safe(&[
"server",
"--object-store",
"azure",
@ -402,7 +402,7 @@ mod tests {
#[test]
fn azure_config_missing_params() {
let config = RunConfig::from_iter_safe(&["server", "--object-store", "azure"]).unwrap();
let config = Config::from_iter_safe(&["server", "--object-store", "azure"]).unwrap();
let err = ObjectStore::try_from(&config).unwrap_err().to_string();
@ -417,7 +417,7 @@ mod tests {
fn valid_file_config() {
let root = TempDir::new().unwrap();
let config = RunConfig::from_iter_safe(&[
let config = Config::from_iter_safe(&[
"server",
"--object-store",
"file",
@ -436,7 +436,7 @@ mod tests {
#[test]
fn file_config_missing_params() {
let config = RunConfig::from_iter_safe(&["server", "--object-store", "file"]).unwrap();
let config = Config::from_iter_safe(&["server", "--object-store", "file"]).unwrap();
let err = ObjectStore::try_from(&config).unwrap_err().to_string();

View File

@ -23,6 +23,7 @@ mod commands {
mod input;
pub mod logging;
pub mod meta;
pub mod run;
pub mod server;
pub mod server_remote;
pub mod stats;
@ -46,13 +47,13 @@ Examples:
influxdb_iox
# Display all server settings
influxdb_iox server --help
influxdb_iox run --help
# Run the InfluxDB IOx server with extra verbose logging
influxdb_iox -v
influxdb_iox run -v
# Run InfluxDB IOx with full debug logging specified with RUST_LOG
RUST_LOG=debug influxdb_iox
RUST_LOG=debug influxdb_iox run
# converts line protocol formatted data in temperature.lp to out.parquet
influxdb_iox convert temperature.lp out.parquet
@ -110,9 +111,10 @@ enum Command {
input: String,
},
Database(commands::database::Config),
Stats(commands::stats::Config),
// Clippy recommended boxing this variant because it's much larger than the others
Server(Box<commands::server::Config>),
Run(Box<commands::run::Config>),
Stats(commands::stats::Config),
Server(commands::server::Config),
Writer(commands::writer::Config),
}
@ -184,9 +186,16 @@ fn main() -> Result<(), std::io::Error> {
}
}
Command::Server(config) => {
logging_level.setup_basic_logging();
if let Err(e) = commands::server::command(host, config).await {
eprintln!("Server command failed: {}", e);
std::process::exit(ReturnCode::Failure as _)
}
}
Command::Run(config) => {
// Note don't set up basic logging here, different logging rules apply in server
// mode
if let Err(e) = commands::server::command(logging_level, host, *config).await {
if let Err(e) = commands::run::command(logging_level, *config).await {
eprintln!("Server command failed: {}", e);
std::process::exit(ReturnCode::Failure as _)
}

View File

@ -225,7 +225,6 @@ impl TestServer {
let server_process = Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("server")
.arg("run")
// Can enable for debugging
//.arg("-vv")
@ -251,7 +250,6 @@ impl TestServer {
self.server_process.wait().unwrap();
self.server_process = Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("server")
.arg("run")
// Can enable for debugging
//.arg("-vv")