public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
        {
            var eventStoreSettings = new EventStoreSettings();

            configuration.GetSection(nameof(EventStoreSettings)).Bind(eventStoreSettings);
            services.Configure <EventStoreSettings>(configuration.GetSection(nameof(EventStoreSettings)));

            var eventStoreConnection = EventStoreConnection.Create(
                connectionString: eventStoreSettings.ConnectionString,
                builder: ConnectionSettings.Create().KeepReconnecting(),
                connectionName: eventStoreSettings.ConnectionName);

            eventStoreConnection.ConnectAsync().GetAwaiter().GetResult();

            services.AddSingleton(eventStoreConnection);

            var couchbaseSettings = new CouchbaseSettings();

            configuration.GetSection(nameof(CouchbaseSettings)).Bind(couchbaseSettings);
            services.Configure <CouchbaseSettings>(configuration.GetSection(nameof(CouchbaseSettings)));

            services.AddCouchbase((opt) =>
            {
                opt.ConnectionString = couchbaseSettings.ConnectionStrings;
                opt.Username         = couchbaseSettings.UserName;
                opt.Password         = couchbaseSettings.Password;
            });
            services.AddTransient(typeof(IGenericRepository <>), typeof(GenericRepository <>));

            return(services);
        }
Example #2
0
        /// <summary>
        /// Implements the service as a <see cref="Task"/>.
        /// </summary>
        /// <returns>The <see cref="Task"/>.</returns>
        private static async Task RunAsync()
        {
            try
            {
                var settings =
                    new CouchbaseSettings()
                {
                    Servers = new List <Uri>()
                    {
                        new Uri("couchbase://10.0.0.90"),
                        new Uri("couchbase://10.0.0.91"),
                        new Uri("couchbase://10.0.0.92")
                    },
                    Bucket = "stoke"
                };

                var credentials =
                    new Credentials()
                {
                    Username = Environment.GetEnvironmentVariable("TS_COUCHBASE_USERNAME"),
                    Password = Environment.GetEnvironmentVariable("TS_COUCHBASE_PASSWORD")
                };

                using (var bucket = settings.OpenBucket(credentials))
                {
                    var retry = new ExponentialRetryPolicy(CouchbaseTransientDetector.IsTransient);

                    for (int i = 0; i < 500000; i++)
                    {
                        var key = bucket.GenKey();

                        await retry.InvokeAsync(async() => await bucket.InsertSafeAsync(key, new Document <Item>()
                        {
                            Id = key, Content = new Item()
                            {
                                Name = "Jeff", Age = 56
                            }
                        }));

                        var exists = await bucket.ExistsAsync(key);

                        var result2 = await bucket.GetAsync <Document <Item> >(key);

                        result2.EnsureSuccess();
                    }
                }
            }
            catch (OperationCanceledException)
            {
                return;
            }
            catch (Exception e)
            {
                log.LogError(e);
            }
            finally
            {
                terminator.ReadyToExit();
            }
        }
Example #3
0
        /// <summary>
        /// Returns a Couchbase bucket connection using specified settings and a Docker secret.
        /// </summary>
        /// <param name="settings">The Couchbase settings.</param>
        /// <param name="secretName">The Docker secret name.</param>
        /// <returns>The connected <see cref="IBucket"/>.</returns>
        public static IBucket ConnectBucket(this CouchbaseSettings settings, string secretName)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(secretName));

            var credentials = NeonHelper.JsonDeserialize <Credentials>(HiveHelper.GetSecret(secretName));

            return(global::Couchbase.CouchbaseExtensions.OpenBucket(settings, credentials));
        }
Example #4
0
        /// <summary>
        /// Returns a Couchbase bucket connection using specified settings and credentials.
        /// </summary>
        /// <param name="settings">The Couchbase settings.</param>
        /// <param name="credentials">The credentials.</param>
        /// <param name="timeout">The optional timeout (defaults to 30 seconds).</param>
        /// <param name="ignoreDurability">Optionally configure the bucket to ignore durability parameters.</param>
        /// <returns>The connected <see cref="NeonBucket"/>.</returns>
        /// <remarks>
        /// <para>
        /// You may explicitly pass <paramref name="ignoreDurability"/><c>=true</c> for
        /// development and test environments where there may not be enough cluster nodes to
        /// satisfy durability constraints.  If this is <c>null</c> (the default) then the bucket
        /// will look for the presence of the <b>DEV_WORKSTATION</b> environment variable
        /// and ignore durability constraints if this variable exists, otherwise durability
        /// constraints will be honored.
        /// </para>
        /// </remarks>
        public static NeonBucket OpenBucket(this CouchbaseSettings settings,
                                            Credentials credentials,
                                            TimeSpan timeout      = default,
                                            bool?ignoreDurability = null)
        {
            Covenant.Requires <ArgumentNullException>(credentials != null);

            return(settings.OpenBucket(credentials.Username, credentials.Password, timeout: timeout, ignoreDurability: ignoreDurability));
        }
Example #5
0
        /// <summary>
        /// Actually starts Couchbase within the initialization <see cref="Action"/>.  You'll
        /// generally want to use <see cref="Start(CouchbaseSettings, string, string, string[], string, string, bool)"/>
        /// but this method is used internally or for special situations.
        /// </summary>
        /// <param name="settings">Optional Couchbase settings.</param>
        /// <param name="image">Optionally specifies the Couchbase container image (defaults to <b>nhive/couchbase-test:latest</b>).</param>
        /// <param name="name">Optionally specifies the Couchbase container name (defaults to <c>cb-test</c>).</param>
        /// <param name="env">Optional environment variables to be passed to the Couchbase container, formatted as <b>NAME=VALUE</b> or just <b>NAME</b>.</param>
        /// <param name="username">Optional Couchbase username (defaults to <b>Administrator</b>).</param>
        /// <param name="password">Optional Couchbase password (defaults to <b>password</b>).</param>
        /// <param name="noPrimary">Optionally disable creation of thea primary bucket index.</param>
        /// <returns>
        /// <c>true</c> if the fixture wasn't previously initialized and
        /// this method call initialized it or <c>false</c> if the fixture
        /// was already initialized.
        /// </returns>
        public void StartInAction(
            CouchbaseSettings settings = null,
            string image            = "nhive/couchbase-test:latest",
            string name             = "cb-test",
            string[]            env = null,
            string username         = "******",
            string password         = "******",
            bool noPrimary          = false)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(image));

            base.CheckWithinAction();

            if (IsInitialized)
            {
                return;
            }

            RunContainer(name, image,
                         new string[]
            {
                "--detach",
                "--mount", "type=volume,target=/opt/couchbase/var",
                "-p", "4369:4369",
                "-p", "8091-8096:8091-8096",
                "-p", "9100-9105:9100-9105",
                "-p", "9110-9118:9110-9118",
                "-p", "9120-9122:9120-9122",
                "-p", "9999:9999",
                "-p", "11207:11207",
                "-p", "11209-11211:11209-11211",
                "-p", "18091-18096:18091-18096",
                "-p", "21100-21299:21100-21299"
            },
                         env: env);

            Thread.Sleep(warmupDelay);

            settings = settings ?? new CouchbaseSettings();

            settings.Servers.Clear();
            settings.Servers.Add(new Uri("http://localhost:8091"));

            if (settings.Bucket == null)
            {
                settings.Bucket = "test";
            }

            Bucket   = null;
            Settings = settings;
            Username = username;
            Password = password;

            ConnectBucket();
        }
Example #6
0
        /// <summary>
        /// Returns a Couchbase cluster connection using specified settings and <see cref="Credentials"/>.
        /// </summary>
        /// <param name="settings">The Couchbase settings.</param>
        /// <param name="credentials">Cluster credentials.</param>
        /// <returns>The connected <see cref="Cluster"/>.</returns>
        public static Cluster OpenCluster(this CouchbaseSettings settings, Credentials credentials)
        {
            Covenant.Requires <ArgumentNullException>(settings.Servers != null && settings.Servers.Count > 0);
            Covenant.Requires <ArgumentNullException>(credentials != null);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(credentials.Username));
            Covenant.Requires <ArgumentNullException>(credentials.Password != null);

            var config  = settings.ToClientConfig();
            var cluster = new Cluster(config);

            cluster.Authenticate(credentials.Username, credentials.Password);

            return(cluster);
        }
        public CouchbaseRepositoryBase()
        {
            _couchbaseSettings = ServiceTool.ServiceProvider.GetService <IConfiguration>().GetSection("CouchbaseSettings").Get <CouchbaseSettings>();
            _cluster           = new Cluster(new ClientConfiguration
            {
                Servers = new List <Uri> {
                    new Uri(_couchbaseSettings.Host)
                }
            });
            _cluster.Authenticate(_couchbaseSettings.Username, _couchbaseSettings.Password);

            _bucket  = _cluster.OpenBucket("todo");
            _context = new BucketContext(_bucket);
        }
Example #8
0
 /// <summary>
 /// <para>
 /// Starts a Couchbase container if it's not already running.  You'll generally want
 /// to call this in your test class constructor instead of <see cref="ITestFixture.Start(Action)"/>.
 /// </para>
 /// <note>
 /// You'll need to call <see cref="StartAsComposed(CouchbaseSettings, string, string, string[], string, string, bool)"/>
 /// instead when this fixture is being added to a <see cref="ComposedFixture"/>.
 /// </note>
 /// </summary>
 /// <param name="settings">Optional Couchbase settings.</param>
 /// <param name="image">
 /// Optionally specifies the Couchbase container image.  This defaults to
 /// <b>nkubeio/couchbase-test:latest</b> or <b>nkubedev/couchbase-test:latest</b>
 /// depending on whether the assembly was built from a git release branch or not.
 /// </param>
 /// <param name="name">Optionally specifies the Couchbase container name (defaults to <c>cb-test</c>).</param>
 /// <param name="env">Optional environment variables to be passed to the Couchbase container, formatted as <b>NAME=VALUE</b> or just <b>NAME</b>.</param>
 /// <param name="username">Optional Couchbase username (defaults to <b>Administrator</b>).</param>
 /// <param name="password">Optional Couchbase password (defaults to <b>password</b>).</param>
 /// <param name="noPrimary">Optionally disable creation of the primary bucket index.</param>
 /// <returns>
 /// <see cref="TestFixtureStatus.Started"/> if the fixture wasn't previously started and
 /// this method call started it or <see cref="TestFixtureStatus.AlreadyRunning"/> if the
 /// fixture was already running.
 /// </returns>
 /// <remarks>
 /// <note>
 /// Some of the <paramref name="settings"/> properties will be ignored including
 /// <see cref="CouchbaseSettings.Servers"/>.  This will be replaced by the local
 /// endpoint for the Couchbase container.  Also, the fixture will connect to the
 /// <b>test</b> bucket by default (unless another is specified).
 /// </note>
 /// <para>
 /// This method creates a primary index by default because it's very common for
 /// unit tests to require a primary index. You can avoid creating a primary index
 /// by passing <paramref name="noPrimary"/><c>=true</c>.
 /// </para>
 /// <para>
 /// There are three basic patterns for using this fixture.
 /// </para>
 /// <list type="table">
 /// <item>
 /// <term><b>initialize once</b></term>
 /// <description>
 /// <para>
 /// The basic idea here is to have your test class initialize Couchbase
 /// once within the test class constructor inside of the initialize action
 /// with common state that all of the tests can access.
 /// </para>
 /// <para>
 /// This will be quite a bit faster than reconfiguring Couchbase at the
 /// beginning of every test and can work well for many situations.
 /// </para>
 /// </description>
 /// </item>
 /// <item>
 /// <term><b>initialize every test</b></term>
 /// <description>
 /// For scenarios where Couchbase must be cleared before every test,
 /// you can use the <see cref="Clear()"/> method to reset its
 /// state within each test method, populate the database as necessary,
 /// and then perform your tests.
 /// </description>
 /// </item>
 /// <item>
 /// <term><b>docker integrated</b></term>
 /// <description>
 /// The <see cref="CouchbaseFixture"/> can also be added to the <see cref="DockerFixture"/>
 /// and used within a swarm.  This is useful for testing multiple services and
 /// also has the advantage of ensure that swarm/node state is fully reset
 /// before the database container is started.
 /// </description>
 /// </item>
 /// </list>
 /// </remarks>
 public TestFixtureStatus Start(
     CouchbaseSettings settings = null,
     string image            = null,
     string name             = "cb-test",
     string[]            env = null,
     string username         = "******",
     string password         = "******",
     bool noPrimary          = false)
 {
     return(base.Start(
                () =>
     {
         StartAsComposed(settings, image, name, env, username, password, noPrimary);
     }));
 }
Example #9
0
        /// <summary>
        /// Returns a Couchbase cluster connection using specified settings and the username and password.
        /// </summary>
        /// <param name="settings">The Couchbase settings.</param>
        /// <param name="username">The cluster username.</param>
        /// <param name="password">The cluster password.</param>
        /// <returns>The connected <see cref="Cluster"/>.</returns>
        public static Cluster OpenCluster(this CouchbaseSettings settings, string username, string password)
        {
            Covenant.Requires <ArgumentNullException>(settings.Servers != null && settings.Servers.Count > 0);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(username));
            Covenant.Requires <ArgumentNullException>(password != null);

            var config  = settings.ToClientConfig();
            var cluster = new Cluster(config);

            if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
            {
                cluster.Authenticate(new Authentication.PasswordAuthenticator(username, password));
            }

            return(cluster);
        }
Example #10
0
 /// <summary>
 /// <para>
 /// Starts a Couchbase container if it's not already running.  You'll generally want
 /// to call this in your test class constructor instead of <see cref="ITestFixture.Start(Action)"/>.
 /// </para>
 /// <note>
 /// You'll need to call <see cref="StartAsComposed(CouchbaseSettings, string, string, string[], string, string, bool, string, ContainerLimits)"/>
 /// instead when this fixture is being added to a <see cref="ComposedFixture"/>.
 /// </note>
 /// </summary>
 /// <param name="settings">Optional Couchbase settings.</param>
 /// <param name="image">
 /// Optionally specifies the Couchbase container image.  This defaults to
 /// <b>ghcr.io/neonrelease/couchbase-dev:latest</b> or <b>ghcr.io/neonrelease-dev/couchbase-dev:latest</b>
 /// depending on whether the assembly was built from a git release branch or not.
 /// </param>
 /// <param name="name">Optionally specifies the Couchbase container name (defaults to <c>cb-test</c>).</param>
 /// <param name="env">Optional environment variables to be passed to the Couchbase container, formatted as <b>NAME=VALUE</b> or just <b>NAME</b>.</param>
 /// <param name="username">Optional Couchbase username (defaults to <b>Administrator</b>).</param>
 /// <param name="password">Optional Couchbase password (defaults to <b>password</b>).</param>
 /// <param name="noPrimary">Optionally disable creation of the primary bucket index.</param>
 /// <param name="hostInterface">
 /// Optionally specifies the host interface where the container public ports will be
 /// published.  This defaults to <see cref="ContainerFixture.DefaultHostInterface"/>
 /// but may be customized.  This needs to be an IPv4 address.
 /// </param>
 /// <param name="limits">
 /// Optionally specifies the Docker container limits to use for hosting Couchbase.  Note that
 /// this method will use reasonable default limits when this is <c>null</c>.
 /// </param>
 /// <returns>
 /// <see cref="TestFixtureStatus.Started"/> if the fixture wasn't previously started and
 /// this method call started it or <see cref="TestFixtureStatus.AlreadyRunning"/> if the
 /// fixture was already running.
 /// </returns>
 /// <remarks>
 /// <note>
 /// Some of the <paramref name="settings"/> properties will be ignored including
 /// <see cref="CouchbaseSettings.Servers"/>.  This will be replaced by the local
 /// endpoint for the Couchbase container.  Also, the fixture will connect to the
 /// <b>test</b> bucket by default (unless another is specified).
 /// </note>
 /// <para>
 /// This method creates a primary index by default because it's very common for
 /// unit tests to require a primary index. You can avoid creating a primary index
 /// by passing <paramref name="noPrimary"/><c>=true</c>.
 /// </para>
 /// <para>
 /// There are three basic patterns for using this fixture.
 /// </para>
 /// <list type="table">
 /// <item>
 /// <term><b>initialize once</b></term>
 /// <description>
 /// <para>
 /// The basic idea here is to have your test class initialize Couchbase
 /// once within the test class constructor inside of the initialize action
 /// with common state that all of the tests can access.
 /// </para>
 /// <para>
 /// This will be quite a bit faster than reconfiguring Couchbase at the
 /// beginning of every test and can work well for many situations.
 /// </para>
 /// </description>
 /// </item>
 /// <item>
 /// <term><b>initialize every test</b></term>
 /// <description>
 /// For scenarios where Couchbase must be cleared before every test,
 /// you can use the <see cref="Clear()"/> method to reset its
 /// state within each test method, populate the database as necessary,
 /// and then perform your tests.
 /// </description>
 /// </item>
 /// <item>
 /// <term><b>docker integrated</b></term>
 /// <description>
 /// The <see cref="CouchbaseFixture"/> can also be added to the <see cref="DockerFixture"/>
 /// and used within a swarm.  This is useful for testing multiple services and
 /// also has the advantage of ensure that swarm/node state is fully reset
 /// before the database container is started.
 /// </description>
 /// </item>
 /// </list>
 /// </remarks>
 public TestFixtureStatus Start(
     CouchbaseSettings settings = null,
     string image            = null,
     string name             = "cb-test",
     string[]            env = null,
     string username         = "******",
     string password         = "******",
     bool noPrimary          = false,
     string hostInterface    = null,
     ContainerLimits limits  = null)
 {
     return(base.Start(
                () =>
     {
         StartAsComposed(settings, image, name, env, username, password, noPrimary, hostInterface, limits);
     }));
 }
Example #11
0
        /// <summary>
        /// Converts a <see cref="CouchbaseSettings"/> into a <see cref="ClientConfiguration"/>.
        /// </summary>
        /// <param name="settings">The simplified Couchbase settings instance.</param>
        /// <returns>A Couchbase <see cref="ClientConfiguration"/>.</returns>
        public static ClientConfiguration ToClientConfig(this CouchbaseSettings settings)
        {
            var config = new ClientConfiguration();

            config.Servers.Clear();

            foreach (var uri in settings.Servers)
            {
                config.Servers.Add(uri);
            }

            config.UseSsl     = false;
            config.Serializer = () => new DefaultSerializer(NeonHelper.JsonRelaxedSerializerSettings.Value, NeonHelper.JsonRelaxedSerializerSettings.Value);
            config.DefaultOperationLifespan = (uint)settings.OperationTimeout;
            config.DefaultConnectionLimit   = settings.MaxPoolConnections;

            return(config);
        }
Example #12
0
        /// <summary>
        /// Starts a Couchbase container if it's not already running.  You'll generally want
        /// to call this in your test class constructor instead of <see cref="ITestFixture.Initialize(Action)"/>.
        /// </summary>
        /// <param name="settings">Optional Couchbase settings.</param>
        /// <param name="image">Optionally specifies the Couchbase container image (defaults to <b>nhive/couchbase-test:latest</b>).</param>
        /// <param name="name">Optionally specifies the Couchbase container name (defaults to <c>cb-test</c>).</param>
        /// <param name="env">Optional environment variables to be passed to the Couchbase container, formatted as <b>NAME=VALUE</b> or just <b>NAME</b>.</param>
        /// <param name="username">Optional Couchbase username (defaults to <b>Administrator</b>).</param>
        /// <param name="password">Optional Couchbase password (defaults to <b>password</b>).</param>
        /// <param name="noPrimary">Optionally disable creation of the primary bucket index.</param>
        /// <returns>
        /// <c>true</c> if the fixture wasn't previously initialized and
        /// this method call initialized it or <c>false</c> if the fixture
        /// was already initialized.
        /// </returns>
        /// <remarks>
        /// <note>
        /// Some of the <paramref name="settings"/> properties will be ignored including
        /// <see cref="CouchbaseSettings.Servers"/>.  This will be replaced by the local
        /// endpoint for the Couchbase container.  Also, the fixture will connect to the
        /// <b>test</b> bucket by default (unless another is specified).
        /// </note>
        /// <para>
        /// This method creates a primary index by default because it's very common for
        /// unit tests to require a primary index. You can avoid creating a primary index
        /// by passing <paramref name="noPrimary"/><c>=true</c>.
        /// </para>
        /// <para>
        /// There are three basic patterns for using this fixture.
        /// </para>
        /// <list type="table">
        /// <item>
        /// <term><b>initialize once</b></term>
        /// <description>
        /// <para>
        /// The basic idea here is to have your test class initialize Couchbase
        /// once within the test class constructor inside of the initialize action
        /// with common state that all of the tests can access.
        /// </para>
        /// <para>
        /// This will be quite a bit faster than reconfiguring Couchbase at the
        /// beginning of every test and can work well for many situations.
        /// </para>
        /// </description>
        /// </item>
        /// <item>
        /// <term><b>initialize every test</b></term>
        /// <description>
        /// For scenarios where Couchbase must be cleared before every test,
        /// you can use the <see cref="Clear()"/> method to reset its
        /// state within each test method, populate the database as necessary,
        /// and then perform your tests.
        /// </description>
        /// </item>
        /// <item>
        /// <term><b>docker integrated</b></term>
        /// <description>
        /// The <see cref="CouchbaseFixture"/> can also be added to the <see cref="DockerFixture"/>
        /// and used within a swarm.  This is useful for testing multiple services and
        /// also has the advantage of ensure that swarm/node state is fully reset
        /// before the database container is started.
        /// </description>
        /// </item>
        /// </list>
        /// </remarks>
        public bool Start(
            CouchbaseSettings settings = null,
            string image            = "nhive/couchbase-test:latest",
            string name             = "cb-test",
            string[]            env = null,
            string username         = "******",
            string password         = "******",
            bool noPrimary          = false)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(image));

            createPrimaryIndex = !noPrimary;

            return(base.Initialize(
                       () =>
            {
                StartInAction(settings, image, name, env, username, password, noPrimary);
            }));
        }
Example #13
0
        //---------------------------------------------------------------------
        // Instance members

        /// <summary>
        /// Constructor.
        /// </summary>
        public CouchbaseArgs()
        {
            Settings    = new CouchbaseSettings();
            Credentials = new Credentials();
        }
Example #14
0
        /// <inheritdoc/>
        public override void Run(CommandLine commandLine)
        {
            if (commandLine.HasHelpOption || commandLine.Arguments.Length == 0)
            {
                Console.WriteLine(usage);
                Program.Exit(0);
            }

            if (commandLine.Arguments.Length == 0)
            {
                Console.Error.WriteLine("*** ERROR: Expected a TARGET argument like: [couchbase://HOST@USER:PASSWORD:BUCKET] or [http(s)://HOST:PORT@USER:PASSWORD:BUCKET]");
                Program.Exit(1);
            }

            // Open a Couchbase bucket for the TARGET.
            //
            //      http(s)://HOST:PORT@USER:PASSWORD:BUCKET
            //      couchbase://HOST@USER:PASSWORD:BUCKET

            var target = commandLine.Arguments[0];
            var error  = $"*** ERROR: [{target}] is not a valid Couchbase target.  Expected: [couchbase://HOST@USER:PASSWORD:BUCKET] or [http(s)://HOST:PORT@USER:PASSWORD:BUCKET]";
            var fields = target.Split(new char[] { '@' }, 2);

            if (fields.Length != 2)
            {
                Console.WriteLine(error);
                Program.Exit(1);
            }

            var uri = fields[0];

            fields = fields[1].Split(':');

            if (fields.Length != 3)
            {
                Console.WriteLine(error);
                Program.Exit(1);
            }

            var username   = fields[0];
            var password   = fields[1];
            var bucketName = fields[2];
            var config     = new CouchbaseSettings();

            config.Servers.Clear();
            config.Servers.Add(new Uri(uri));
            config.Bucket = bucketName;

            using (var bucket = config.OpenBucket(username, password))
            {
                commandLine = commandLine.Shift(1);

                // Get the N1QL query.

                if (commandLine.Arguments.Length != 1)
                {
                    Console.Error.WriteLine("*** ERROR: QUERY argument expected.");
                    Program.Exit(1);
                }

                var query = commandLine.Arguments[0];

                if (query == "-")
                {
                    // Read the query from STDIN.

                    query = NeonHelper.ReadStandardInputText();
                }
                else if (query.StartsWith("@"))
                {
                    // Read the query from the file.

                    query = File.ReadAllText(query.Substring(1));
                }

                var queryResults = bucket.Query <JToken>(query);

                Console.WriteLine(JsonConvert.SerializeObject(queryResults, Formatting.Indented));
            }

            Program.Exit(0);
        }
Example #15
0
        /// <summary>
        /// Returns a Couchbase bucket connection using specified settings and the cluster credentials.
        /// </summary>
        /// <param name="settings">The Couchbase settings.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="timeout">The optional timeout (defaults to 60 seconds).</param>
        /// <param name="ignoreDurability">Optionally configure the bucket to ignore durability parameters.</param>
        /// <returns>The connected <see cref="NeonBucket"/>.</returns>
        /// <exception cref="TimeoutException">Thrown if the bucket is not ready after waiting <paramref name="timeout"/>.</exception>
        /// <remarks>
        /// <para>
        /// You may explicitly pass <paramref name="ignoreDurability"/><c>=true</c> for
        /// development and test environments where there may not be enough cluster nodes to
        /// satisfy durability constraints.  If this is <c>null</c> (the default) then the bucket
        /// will look for the presence of the <b>DEV_WORKSTATION</b> environment variable
        /// and ignore durability constraints if this variable exists, otherwise durability
        /// constraints will be honored.
        /// </para>
        /// </remarks>
        public static NeonBucket OpenBucket(this CouchbaseSettings settings,
                                            string username,
                                            string password,
                                            TimeSpan timeout      = default(TimeSpan),
                                            bool?ignoreDurability = null)
        {
            var bucketConfig =
                new BucketConfiguration()
            {
                BucketName            = settings.Bucket,
                UseEnhancedDurability = settings.UseEnhancedDurability,

                PoolConfiguration = new PoolConfiguration()
                {
                    ConnectTimeout = settings.ConnectTimeout,
                    SendTimeout    = settings.SendTimeout,
                    MaxSize        = settings.MaxPoolConnections,
                    MinSize        = settings.MinPoolConnections
                }
            };

            bucketConfig.PoolConfiguration.ClientConfiguration =
                new ClientConfiguration()
            {
                QueryRequestTimeout = (uint)settings.QueryRequestTimeout,
                ViewRequestTimeout  = settings.ViewRequestTimeout,
                Serializer          = () => new EntitySerializer()
            };

            var config = settings.ToClientConfig();

            config.BucketConfigs.Clear();
            config.BucketConfigs.Add(settings.Bucket, bucketConfig);

            var cluster = new Cluster(config);

            // We have to wait for three Couchbase operations to complete
            // successfully:
            //
            //      1. Authenticate
            //      2. Open Bucket
            //      3. List Indexes
            //
            // Each of these can fail if Couchbase isn't ready.  The Open Bucket
            // can fail after the Authenticate succeeded because the bucket is
            // still warming up in the cluster.

            if (timeout <= TimeSpan.Zero)
            {
                timeout = NeonBucket.ReadyTimeout;
            }

            //-----------------------------------------------------------------
            // Authenticate against the Couchbase cluster.

            var stopwatch = new Stopwatch();

            stopwatch.Start();

            NeonHelper.WaitFor(
                () =>
            {
                try
                {
                    cluster.Authenticate(username, password);
                    return(true);
                }
                catch
                {
                    return(false);
                }
            },
                timeout: timeout,
                pollTime: TimeSpan.FromSeconds(0.5));

            //-----------------------------------------------------------------
            // Open the bucket.  Note that we're going to recreate the bucket after
            // each failed attempt because it doesn't seem to recover from connection
            // failures.
            //
            // I believe this may be due to the index and or query services not being
            // ready yet after Couchbase has just been spun up and the bucket isn't
            // notified when these become ready, even after some time passes.

            timeout = timeout - stopwatch.Elapsed;  // Adjust the timeout downward by the time taken to authenticate.
            stopwatch.Restart();

            var bucket = (NeonBucket)null;

            NeonHelper.WaitFor(
                () =>
            {
                try
                {
                    bucket = new NeonBucket(cluster.OpenBucket(settings.Bucket), settings, ignoreDurability);
                    return(true);
                }
                catch
                {
                    return(false);
                }
            },
                timeout: timeout,
                pollTime: TimeSpan.FromSeconds(0.5));

            //-----------------------------------------------------------------
            // Wait until the bucket can perform a simple read operation without
            // failing.  It appears that we can see early failures for Couchbase
            // clusters that have just been created (e.g. during unit tests).

            timeout = timeout - stopwatch.Elapsed;  // Adjust the timeout downward by the time taken to connect.
            stopwatch.Restart();

            bucket.WaitUntilReadyAsync(timeout).Wait();

            return(bucket);
        }
Example #16
0
        /// <summary>
        /// Used to start the fixture within a <see cref="ComposedFixture"/>.
        /// </summary>
        /// <param name="settings">Optional Couchbase settings.</param>
        /// <param name="image">
        /// Optionally specifies the Couchbase container image.  This defaults to
        /// <b>nkubeio/couchbase-dev:latest</b> or <b>nkubedev/couchbase-dev:latest</b>
        /// depending on whether the assembly was built from a git release branch or not.
        /// </param>
        /// <param name="name">Optionally specifies the Couchbase container name (defaults to <c>cb-test</c>).</param>
        /// <param name="env">Optional environment variables to be passed to the Couchbase container, formatted as <b>NAME=VALUE</b> or just <b>NAME</b>.</param>
        /// <param name="username">Optional Couchbase username (defaults to <b>Administrator</b>).</param>
        /// <param name="password">Optional Couchbase password (defaults to <b>password</b>).</param>
        /// <param name="noPrimary">Optionally disable creation of thea primary bucket index.</param>
        /// <param name="hostInterface">
        /// Optionally specifies the host interface where the container public ports will be
        /// published.  This defaults to <see cref="ContainerFixture.DefaultHostInterface"/>
        /// but may be customized.  This needs to be an IPv4 address.
        /// </param>
        public void StartAsComposed(
            CouchbaseSettings settings = null,
            string image            = null,
            string name             = "cb-test",
            string[]            env = null,
            string username         = "******",
            string password         = "******",
            bool noPrimary          = false,
            string hostInterface    = null)
        {
            image = image ?? $"{KubeConst.NeonBranchRegistry}/couchbase-dev:latest";

            base.CheckWithinAction();

            createPrimaryIndex = !noPrimary;

            if (!IsRunning)
            {
                StartAsComposed(name, image,
                                new string[]
                {
                    "--detach",
                    "-p", $"{GetHostInterface(hostInterface)}:4369:4369",
                    "-p", $"{GetHostInterface(hostInterface)}:8091-8096:8091-8096",
                    "-p", $"{GetHostInterface(hostInterface)}:9100-9105:9100-9105",
                    "-p", $"{GetHostInterface(hostInterface)}:9110-9118:9110-9118",
                    "-p", $"{GetHostInterface(hostInterface)}:9120-9122:9120-9122",
                    "-p", $"{GetHostInterface(hostInterface)}:9999:9999",
                    "-p", $"{GetHostInterface(hostInterface)}:11207:11207",
                    "-p", $"{GetHostInterface(hostInterface)}:11209-11211:11209-11211",
                    "-p", $"{GetHostInterface(hostInterface)}:18091-18096:18091-18096",
                    "-p", $"{GetHostInterface(hostInterface)}:21100-21299:21100-21299"
                },
                                env: env);

                Thread.Sleep(warmupDelay);

                settings = settings ?? new CouchbaseSettings();

                settings.Servers.Clear();
                settings.Servers.Add(new Uri($"http://{GetHostInterface(hostInterface, forConnection: true)}:8091"));

                if (settings.Bucket == null)
                {
                    settings.Bucket = "test";
                }

                Bucket   = null;
                Settings = settings;
                Username = username;
                Password = password;

                jsonClient             = new JsonClient();
                jsonClient.BaseAddress = new Uri($"http://{GetHostInterface(hostInterface, forConnection: true)}:8094");
                jsonClient.DefaultRequestHeaders.Authorization =
                    new AuthenticationHeaderValue(
                        "Basic",
                        Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{username}:{password}")));
            }

            ConnectBucket();
        }
Example #17
0
        /// <inheritdoc/>
        public override void Run(CommandLine commandLine)
        {
            if (commandLine.HasHelpOption || commandLine.Arguments.Length == 0)
            {
                Console.WriteLine(usage);
                Program.Exit(0);
            }

            Program.ConnectHive();

            // Process the command arguments.

            var command = commandLine.Arguments[0];

            commandLine = commandLine.Shift(1);

            if (commandLine.Arguments.Length == 0)
            {
                Console.Error.WriteLine("*** ERROR: Expected a TARGET argument like: [couchbase://HOST@USER:PASSWORD:BUCKET] or [http(s)://HOST:PORT@USER:PASSWORD:BUCKET]");
                Program.Exit(1);
            }

            // Open a Couchbase bucket for the TARGET.
            //
            //      http(s)://HOST:PORT@USER:PASSWORD:BUCKET
            //      couchbase://HOST@USER:PASSWORD:BUCKET

            var target = commandLine.Arguments[0];
            var error  = $"*** ERROR: [{target}] is not a valid Couchbase target.  Expected: [couchbase://HOST@USER:PASSWORD:BUCKET] or [http(s)://HOST:PORT@USER:PASSWORD:BUCKET]";
            var fields = target.Split(new char[] { '@' }, 2);

            if (fields.Length != 2)
            {
                Console.WriteLine(error);
                Program.Exit(1);
            }

            var uri = fields[0];

            fields = fields[1].Split(':');

            if (fields.Length != 3)
            {
                Console.WriteLine(error);
                Program.Exit(1);
            }

            var username   = fields[0];
            var password   = fields[1];
            var bucketName = fields[2];
            var config     = new CouchbaseSettings();

            config.Servers.Clear();
            config.Servers.Add(new Uri(uri));
            config.Bucket = bucketName;

            using (var bucket = config.OpenBucket(username, password))
            {
                commandLine = commandLine.Shift(1);

                switch (command)
                {
                case "query":

                    // Get the N1QL query.

                    if (commandLine.Arguments.Length != 1)
                    {
                        Console.Error.WriteLine("*** ERROR: QUERY argument expected.");
                        Program.Exit(1);
                    }

                    var query = commandLine.Arguments[0];

                    if (query == "-")
                    {
                        // Read the query from STDIN.

                        query = NeonHelper.ReadStandardInputText();
                    }
                    else if (query.StartsWith("@"))
                    {
                        // Read the query from the file.

                        query = File.ReadAllText(query.Substring(1));
                    }

                    var queryResults = bucket.Query <JToken>(query);

                    Console.WriteLine(JsonConvert.SerializeObject(queryResults, Formatting.Indented));
                    break;

                case "upsert":

                    if (commandLine.Arguments.Length != 1)
                    {
                        Console.Error.WriteLine("*** ERROR: JSON object argument expected.");
                        Program.Exit(1);
                    }

                    var fileArg = commandLine.Arguments[0];
                    var input   = (Stream)null;

                    if (fileArg == "-")
                    {
                        // Read the object from STDIN.

                        input = Console.OpenStandardInput();
                    }
                    else
                    {
                        input = new FileStream(fileArg, FileMode.Open, FileAccess.ReadWrite);
                    }

                    var keyPattern = commandLine.GetOption("--key");

                    var firstKeyValue = commandLine.GetOption("--first-key", "1");

                    if (!long.TryParse(firstKeyValue, out var firstKey))
                    {
                        Console.Error.WriteLine($"*** ERROR: [--firstkey={firstKeyValue}] is not a valid integer.");
                        Program.Exit(1);
                    }

                    var upsertError = false;

                    using (var reader = new StreamReader(input, Encoding.UTF8))
                    {
                        var importer = new CouchbaseImporter(
                            message =>
                        {
                            upsertError = true;
                            Console.Error.WriteLine($"*** ERROR: {message}");
                        },
                            bucket, keyPattern, firstKey);

                        foreach (var line in reader.Lines())
                        {
                            if (line.Trim() == string.Empty)
                            {
                                continue;       // Ignore blank lines
                            }

                            var item = JToken.Parse(line);

                            if (item.Type != JTokenType.Object)
                            {
                                upsertError = true;
                                Console.Error.WriteLine($"*** ERROR: [{fileArg}] includes one or more lines with non-document objects.");
                                break;
                            }

                            importer.WriteDocument((JObject)item);
                        }
                    }

                    if (upsertError)
                    {
                        Program.Exit(1);
                    }
                    break;

                default:

                    Console.Error.WriteLine($"*** ERROR: Unknown command: [{command}]");
                    Program.Exit(1);
                    break;
                }
            }
        }
Example #18
0
        /// <inheritdoc/>
        public override void Run(CommandLine commandLine)
        {
            if (commandLine.HasHelpOption || commandLine.Arguments.Length == 0)
            {
                Console.WriteLine(usage);
                Program.Exit(0);
            }

            if (commandLine.Arguments.Length == 0)
            {
                Console.Error.WriteLine("*** ERROR: Expected a TARGET argument like: [couchbase://HOST@USER:PASSWORD:BUCKET] or [http(s)://HOST:PORT@USER:PASSWORD:BUCKET]");
                Program.Exit(1);
            }

            // Open a Couchbase bucket for the TARGET.
            //
            //      http(s)://HOST:PORT@USER:PASSWORD:BUCKET
            //      couchbase://HOST@USER:PASSWORD:BUCKET

            var target = commandLine.Arguments[0];
            var error  = $"*** ERROR: [{target}] is not a valid Couchbase target.  Expected: [couchbase://HOST@USER:PASSWORD:BUCKET] or [http(s)://HOST:PORT@USER:PASSWORD:BUCKET]";
            var fields = target.Split(new char[] { '@' }, 2);

            if (fields.Length != 2)
            {
                Console.WriteLine(error);
                Program.Exit(1);
            }

            var uri = fields[0];

            fields = fields[1].Split(':');

            if (fields.Length != 3)
            {
                Console.WriteLine(error);
                Program.Exit(1);
            }

            var username   = fields[0];
            var password   = fields[1];
            var bucketName = fields[2];
            var config     = new CouchbaseSettings();

            config.Servers.Clear();
            config.Servers.Add(new Uri(uri));
            config.Bucket = bucketName;

            using (var bucket = config.OpenBucket(username, password))
            {
                commandLine = commandLine.Shift(1);

                if (commandLine.Arguments.Length != 1)
                {
                    Console.Error.WriteLine("*** ERROR: JSON-FILE argument is required.");
                    Program.Exit(1);
                }

                var fileArg = commandLine.Arguments[0];
                var input   = (Stream)null;

                if (fileArg == "-")
                {
                    // Read from STDIN.

                    input = NeonHelper.OpenStandardInput();
                }
                else
                {
                    input = new FileStream(fileArg, FileMode.Open, FileAccess.ReadWrite);
                }

                var keyPattern    = commandLine.GetOption("--key");
                var firstKeyValue = commandLine.GetOption("--first-key", "1");

                if (!long.TryParse(firstKeyValue, out var firstKey))
                {
                    Console.Error.WriteLine($"*** ERROR: [--firstkey={firstKeyValue}] is not a valid integer.");
                    Program.Exit(1);
                }

                var upsertError = false;

                using (var reader = new StreamReader(input, Encoding.UTF8))
                {
                    var importer = new CouchbaseImporter(
                        message =>
                    {
                        upsertError = true;
                        Console.Error.WriteLine($"*** ERROR: {message}");
                    },
                        bucket, keyPattern, firstKey);

                    foreach (var line in reader.Lines())
                    {
                        if (line.Trim() == string.Empty)
                        {
                            continue;   // Ignore blank lines
                        }

                        var item = JToken.Parse(line);

                        if (item.Type != JTokenType.Object)
                        {
                            upsertError = true;
                            Console.Error.WriteLine($"*** ERROR: [{fileArg}] includes one or more lines with non-JSON document objects.");
                            break;
                        }

                        importer.WriteDocument((JObject)item);
                    }
                }

                if (upsertError)
                {
                    Program.Exit(1);
                }
            }

            Program.Exit(0);
        }