Coder Social home page Coder Social logo

train's Introduction

Train - Transport Interface

  • Project State: Active
  • Issues Response SLA: 3 business days
  • Pull Request Response SLA: 3 business days

For more information on project states and SLAs, see this documentation.

Build status Gem Version

Umbrella Project: Chef Foundation

Project State: Active

Issues Response Time Maximum: 14 days

Pull Request Response Time Maximum: 14 days

Train lets you talk to your local or remote operating systems and APIs with a unified interface.

It allows you to:

  • execute commands via run_command
  • interact with files via file
  • identify the target operating system via os
  • authenticate to API-based services and treat them like a platform

Train supports:

  • Local execution
  • SSH
  • WinRM
  • Docker and Podman
  • Mock (for testing and debugging)
  • AWS as an API
  • Azure as an API
  • VMware via PowerCLI
  • Habitat

Examples

Setup

Local

require 'train'
train = Train.create('local')

SSH

require 'train'
train = Train.create('ssh',
  host: '1.2.3.4', port: 22, user: 'root', key_files: '/vagrant')

If you don't specify the key_files and password options, SSH agent authentication will be attempted. For example:

require 'train'
train = Train.create('ssh', host: '1.2.3.4', port: 22, user: 'root')

SSH transport has an ssh_config_file option to set the SSH config file path. This is set by default to true to read the values from the default SSH config file path. For example, ~/.ssh/config, /etc/ssh_config, /etc/ssh/ssh_config. Precedence is given to the options set through the arguments.

WinRM

require 'train'
train = Train.create('winrm',
  host: '1.2.3.4', user: 'Administrator', password: '...', ssl: true, self_signed: true)

Docker

require 'train'
train = Train.create('docker', host: 'container_id...')

You can use user option to connect with privileged user on non root user images.

require 'train'
train = Train.create('docker', host: 'container_id...', user: 'root')

For Docker Desktop for Windows, you must enable the "Expose daemon on tcp://localhost:2375 without TLS" setting. To change the URL that train uses to connect to Docker, use the docker_url option:

require 'train'
train = Train.create('docker', host: 'container_id...', docker_url: 'tcp://localhost:1234')

Windows Docker containers require PowerShell, which is assumed to be installed as powershell.exe. If it is installed as pwsh, use the --shell-command option to specify pwsh as the shell.

Podman

require 'train'
train = Train.create('podman', host: 'container_id...')
require 'train'
train = Train.create('podman', host: 'container_id...', podman_url: 'tcp://localhost:1234')

To connect to a Podman container, the Podman API endpoint URL needs to set. It can be set through the podman_url option or else Train will check for the CONTAINER_HOST environment variable. If neither is defined then Train will try to connect to the default URL, that is unix:///run/user/UID/podman/podman.sock for non-root users and unix:///run/podman/podman.sock for the root user. Precedence is given to options set through the arguments.

AWS

To use AWS API authentication, setup an AWS client profile to store the Access Key ID and Secret Access Key.

require 'train'
train = Train.create('aws', region: 'us-east-2', profile: 'my-profile')

You may also use the standard AWS CLI environment variables, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION.

require 'train'
train = Train.create('aws')

VMware

require 'train'
Train.create('vmware', viserver: '10.0.0.10', user: 'demouser', password: 'securepassword')

You may also use environment variables by setting VISERVER, VISERVER__USERNAME, and VISERVER_PASSWORD

require 'train'
Train.create('vmware')

Configuration

To get a list of available options for a plugin:

puts Train.options('ssh')

This will provide all configuration options:

{
  :host     => { :required => true},
  :port     => { :default  => 22, :required => true},
  :user     => { :default  => "root", :required => true},
  :keys     => { :default  => nil},
  :password => { :default  => nil},
  ...

Usage

# start or reuse a connection
conn = train.connection

# run a command on Linux/Unix/Mac
puts conn.run_command('whoami').stdout

# get OS info
puts conn.os[:family]
puts conn.os[:release]

# access files
puts conn.file('/proc/version').content

# access specific API client functionality
ec2_client = train.connection.aws_client(Aws::EC2::Client)
puts ec2_client.describe_instances

# close the connection
conn.close

Testing

We perform unit, integration and windows tests.

  • unit tests ensure the intended behaviour of the implementation
  • integration tests run against VMs and docker containers
  • windows tests that run on appveyor for windows integration tests

Mac/Linux

bundle exec ruby -W -Ilib:test/unit test/unit/extras/stat_test.rb

Windows

# run windows tests
bundle exec rake test:windows

# run single tests
bundle exec ruby -I .\test\windows\ .\test\windows\local_test.rb

Kudos and Contributors

Train is heavily based on the work of:

We also want to thank halo who did a great contribution by handing over the train gem name.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

License

| Author: | Dominik Richter ([email protected])

| Author: | Christoph Hartmann ([email protected])

| Copyright: | Copyright (c) 2015-2019 Chef Software Inc.

| Copyright: | Copyright (c) 2015 Vulcano Security GmbH.

| License: | Apache License, Version 2.0

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

train's People

Contributors

adamleff avatar ahasunos avatar alexpop avatar anirudh-gupta avatar arlimus avatar balasubramanian-s avatar briandoodyie avatar chef-ci avatar chef-delivery avatar chris-rock avatar clintoncwolfe avatar codeswhisperer avatar dependabot-preview[bot] avatar dependabot[bot] avatar dmccown avatar jerryaldrichiii avatar jonathanmorley avatar jquick avatar marcparadise avatar mattray avatar miah avatar sanga1794 avatar sathish-progress avatar srenatus avatar stevendanna avatar tas50 avatar tduffield avatar thheinen avatar vasu1105 avatar zenspider avatar

Stargazers

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

Watchers

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

train's Issues

sha256sum and md5sum to execute on the remote machine

A discussion in the Slack #inspec channel leads to the idea that md5sum and sha256sum should be done on the remote machine to minimize encoding issues as well as long executions (file is transferred on unknown connection speeds).

md5sum: https://github.com/chef/train/blob/master/lib/train/file.rb#L57
sha256sum: https://github.com/chef/train/blob/master/lib/train/file.rb#L65

Discussion:
Slack: https://chefcommunity.slack.com/archives/C1XB6U6MN/p1516743917000525
Github: inspec/inspec#1898 (comment)

Read port from ssh config file (e.g. /home/user/.ssh/config)

Description

Read port also from the ssh config under /home/user.ssh/config.

InSpec and Platform Version

inspec version is 0.20.1 and archlinux 4.5.2-1-ARCH

Replication Case

/home/user/.ssh/config look like this

Host jumphost
Hostname 1.1.1.1
Port 28646

inspec exec ./ -t ssh://root@jumphost --key-files /home/user/.ssh/id_rsa is not working because of the port. I have to add the Port also

inspec exec ./ -t ssh://root@jumphost --key-files /home/user/.ssh/id_rsa --port 28646

I think train read the config partly, because i can use the configured hostnames in /home/user/.ssh/config.

Add support for Docker + TCP Sockets

Currently, we only support Unix socket connections for targeting the Docker API. Unix sockets are not supported on Windows at this time so if we want to target containers on a Windows Docker host the user must reconfigure Docker to listen on a TCP socket.

Then we must make train make the correct call to the docker gem since it currently defaults to a Unix socket, https://github.com/swipely/docker-api/blob/master/lib/docker/connection.rb#L11

See issue inspec/inspec#2379 for more details

detect_arista_eos raises exception against unix host

Train version 0.21.0. Original stacktrace:

tball@delivery-server-acceptance:~$ sudo delivery-ctl install-runner -I /etc/delivery/chefdk-el7.rpm -f hostname --username ubuntu -i /etc/delivery/runners.pem -a tball -t 'token' -o -P none

Connecting to runner-acceptance-ubuntu1404-v2-1.builders-acceptance.shd.chef.co...
 (JSON::ParserError)ed/lib/ruby/gems/2.2.0/gems/json-2.0.2/lib/json/common.rb:156:in `parse': 743: unexpected token at 'bash: show: command not found
bash: json: command not found
'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/json-2.0.2/lib/json/common.rb:156:in `parse'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/extras/os_detect_arista_eos.rb:20:in `detect_arista_eos'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/extras/os_common.rb:127:in `detect_family_type'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/extras/os_common.rb:89:in `detect_family'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/extras/os_common.rb:31:in `initialize'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/transports/ssh_connection.rb:233:in `initialize'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/transports/ssh_connection.rb:58:in `new'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/transports/ssh_connection.rb:58:in `os'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/extras/command_wrapper.rb:165:in `load'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/transports/ssh_connection.rb:45:in `initialize'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/transports/ssh.rb:155:in `new'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/transports/ssh.rb:155:in `create_new_connection'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/train-0.21.0/lib/train/transports/ssh.rb:75:in `connection'
	from /opt/delivery/embedded/service/omnibus-ctl/runner/remote_connection.rb:19:in `connect!'
	from /opt/delivery/embedded/service/omnibus-ctl/runner/installer.rb:49:in `install'
	from (eval):10:in `block in load_file'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/omnibus-ctl-0.3.6/lib/omnibus-ctl.rb:171:in `call'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/omnibus-ctl-0.3.6/lib/omnibus-ctl.rb:171:in `block in add_command'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/omnibus-ctl-0.3.6/lib/omnibus-ctl.rb:575:in `run'
	from /opt/delivery/embedded/lib/ruby/gems/2.2.0/gems/omnibus-ctl-0.3.6/bin/omnibus-ctl:31:in `<top (required)>'
	from /opt/delivery/embedded/bin/omnibus-ctl:23:in `load'
	from /opt/delivery/embedded/bin/omnibus-ctl:23:in `<main>'

I have tried trying to access both an Ubuntu and Centos node using a Train connection.

connect_options => {:host=>"runner-acceptance-ubuntu1404-v2-1.builders-acceptance.shd.chef.co",
 :port=>22,
 :user=>"ubuntu",
 :key_files=>"/etc/delivery/runners.pem",
 :logger=>
  #<Logger:0x00000001b481c8
   @default_formatter=#<Logger::Formatter:0x00000001b481a0 @datetime_format=nil>,
   @formatter=nil,
   @level=0,
   @logdev=
    #<Logger::LogDevice:0x00000001b48150
     @dev=#<File:/var/log/delivery-ctl/runner-install_runner-acceptance-ubuntu1404-v2-1.builders-acceptance.shd.chef.co.log>,
     @filename="/var/log/delivery-ctl/runner-install_runner-acceptance-ubuntu1404-v2-1.builders-acceptance.shd.chef.co.log",
     @mutex=#<Logger::LogDevice::LogDeviceMutex:0x00000001b48128 @mon_count=0, @mon_mutex=#<Mutex:0x00000001b480d8>, @mon_owner=nil>,
     @shift_age=0,
     @shift_size=1048576>,
   @progname=nil>,
 :pty=>true,
 :sudo=>true,
 :sudo_password=>"none"}
@train = Train.create('ssh', connect_options)
@train.connection # fails

Add aws:// target

๐Ÿšง DO NOT MERGE until chef-boneyard/inspec-aws-old#149 is resolved ๐Ÿšง

The inspec-aws resource pack currently works "by accident"; all resources ignore the inspec runner (and anything it knows about the transport), and simply read credentials from the AWS_* environment variables. Inspec thinks it is running in local mode the whole time.

We've discussed internally having an explicit aws:// target, with possibilities of using various parts of the URI for various credentials.

This issue may need to be split, for an RFC to determine the URI format, then an implementation issue.

Refs inspec/inspec#2233

Create http/https/tcp/udp transports

Train-API

The Train-API subsystem supports non-OS platforms targets. It provides the tcp, udp, and unix transports for low-level socket access, as well as http and https for high-level transport implementations.

These are defined via the URI schema:

mandatory minimum:
[tcp|upd|unix|http|https]://host

all options:
[tcp|upd|unix|http|https]://[user[:password]@]host[:port]][/path][?query][#fragment]

Some of these fields may not apply to certain transports. There may be resources that are based on the tcp transport but don't process a path or query parameter (e.g. for low-level interface testing).

The tcp, udp, and unix transports will all provide a low-level socket object with a basic communication interface (using an abstraction on top of the underlying Socket object). It is exposed to all InSpec resources via inspec.backend including all configuration options.

The http and https transports offer a simpler interface for all RESTful endpoints, exposed as the inspec.backend object to InSpec resources. Apart from the simple request it is also possible to use HTTP verbs (get, post, put, options, delete, head, trace).

mount resource incorrect matching

As can be seen on this CentOS 7 box, /var is reported by inspec as mounted:

[1] pry(#<#<Class:0x007fe3a3ca6d48>>)> mount('/var').mounted?
=> true
[2] pry(#<#<Class:0x007fe3a3ca6d48>>)> mount('/var').options
=> ["rw", "relatime"]

This is because on this CentOS 7 box, /var matches another mount point that starts with /var:

[root@192 ~]# mount | grep -- ' on /var'
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)

The grep filter here needs to be restricted a bit more, something like:

[root@192 ~]# mount | grep -- ' on /var type '
[root@192 ~]# mount | grep -- ' on /sys/kernel/debug type '
debugfs on /sys/kernel/debug type debugfs (rw,relatime)

Need to test this on a few supported systems.

sporadic appveyor failure on `winrm delete ...`

https://ci.appveyor.com/project/chef/train/build/master-228/job/v06yd3r4g4txajgk

winrm delete winrm/config/Listener?Address=*+Transport=HTTPS
winrm : WSManFault
At line:1 char:1
+ winrm delete winrm/config/Listener?Address=*+Transport=HTTPS
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (WSManFault:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

    Message
        ProviderFault
            WSManFault
                Message = The WS-Management service cannot process the request. The service cannot find the resource identified by the resource URI and selectors. 



Error number:  -2144108544 0x80338000

The WS-Management service cannot process the request. The service cannot find the resource identified by the resource URI and selectors. 

Command executed with exception: 
The WS-Management service cannot process the request. The service cannot find the resource identified by the resource URI and selectors. 

prefix powershell commands with `$ProgressPreference = "SilentlyContinue"`

Recently we've seen errors in appveyor that highlight a general issue with data streams in powershell. Since train does not need the progress information (which is useful for a terminal), I propose we set $ProgressPreference = "SilentlyContinue" as a prefix for all commands under windows.

Our winrm implementation does not seem to be affected by that.

cc @arlimus @ksubrama @mwrock

A sample output from appveyor:

  1) Failure:
windows local command#test_0003_use powershell piping [test/windows/local_test.rb:39]:
--- expected
+++ actual
@@ -1,2 +1,3 @@
 # encoding: UTF-8
-""
+"#< CLIXML\r
+<Objs Version=\"1.1.0.1\" xmlns=\"http://schemas.microsoft.com/powershell/2004/04\"><Obj S=\"progress\" RefId=\"0\"><TN RefId=\"0\"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N=\"SourceId\">1</I64><PR N=\"Record\"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S=\"progress\" RefId=\"1\"><TNRef RefId=\"0\" /><MS><I64 N=\"SourceId\">2</I64><PR N=\"Record\"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>"
  2) Failure:
windows local command#test_0002_run echo test [test/windows/local_test.rb:33]:
--- expected
+++ actual
@@ -1,2 +1,3 @@
 # encoding: UTF-8
-""
+"#< CLIXML\r
+<Objs Version=\"1.1.0.1\" xmlns=\"http://schemas.microsoft.com/powershell/2004/04\"><Obj S=\"progress\" RefId=\"0\"><TN RefId=\"0\"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N=\"SourceId\">1</I64><PR N=\"Record\"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S=\"progress\" RefId=\"1\"><TNRef RefId=\"0\" /><MS><I64 N=\"SourceId\">2</I64><PR N=\"Record\"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>"

Local transport on Windows creates LinuxFile instead of WindowsFile

InSpec's file resource behaves strangely when running locally on Windows because LinuxFile is used instead of WindowsFile. This causes various methods to fail with error like so:

>inspec shell -c "file(\"C:\\log\").type"
C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/inspec/profile_context.rb:144:in `instance_eval': undefined method `name' for nil:NilClass (NoMethodError)
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/train-0.26.1/lib/train/transports/local_file.rb:75:in `stat'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/train-0.26.1/lib/train/extras/file_unix.rb:49:in `block (2 levels) in <class:UnixFile>'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/resources/file.rb:52:in `call'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/resources/file.rb:52:in `block (2 levels) in <class:FileResource>'
        from (eval):1:in `load_with_context'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/inspec/profile_context.rb:144:in `instance_eval'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/inspec/profile_context.rb:144:in `load_with_context'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/inspec/profile_context.rb:130:in `load_control_file'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/inspec/runner.rb:215:in `eval_with_virtual_profile'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/inspec/cli.rb:254:in `run_command'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/lib/inspec/cli.rb:204:in `shell_func'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
        from C:/opscode/inspec/embedded/lib/ruby/gems/2.3.0/gems/inspec-1.33.13/bin/inspec:12:in `<top (required)>'
        from C:/opscode/inspec/bin/inspec:62:in `load'
        from C:/opscode/inspec/bin/inspec:62:in `<main>'

See Train::Transports::Local::Connection.file
@files[path] ||= File.new(self, path)

Should there be conditional logic to create WindowsFile when running locally on Windows?

Connection re-use doesn't work due to modification of the options hash

During calls to #connection, the sub-classes of Transport will return an established connection if the option hash stored at time of creation matches the current options. However, the subclasses of BaseConnection mutate this hash by deleting items from it --- this prevents connection reuse from occurring.

Train doesn't create a login shell

require 'train'

train = Train.create('ssh', host: '127.0.0.1', port: 2200, user: 'vagrant', password: 'vagrant')
conn = train.connection
puts conn.run_command("shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'").stdout

Expected output Login shell
Actual output Not login shell

Since train 'logs in' to the remote host, and then runs commands against them, I would expect the resulting shells to be login shells.

I think a login parameter should be added to somehow force train to create a login shell (defaulted to false for backwards compatibility).

Train reports directories with the archive bit set as files on the windows platform

Description

On the windows platform programs like xcopy set the archive bit on folders
as well as files.

The Inspec directory and file resources use the train backend for file when making assertions,
Train can either use remote or local implimentation for the windows platform.

Using trains local file class for windows, a directory with the archive bit set is correctly identified as directory. (it uses rubys ::File.stat(path) to get attributes about the path)

When Inspec is used remotely and Trains remote file class for windows is used, directories with the archive bit set are identified as files. (it uses powershell's 'Get-ItemProperty -Path' to get attribute information)

Expected behaviour:
Train should report that directories with the archive bit set are directories and not files

relevant code in Train
https://github.com/chef/train/blob/master/lib/train/file/remote/windows.rb#L41-L50

        def type
          if attributes.include?('Archive')
            return :file
          elsif attributes.include?('ReparsePoint')
            return :symlink
          elsif attributes.include?('Directory')
            return :directory
          end
          :unknown
        end

windows remote file gets the attributes via

        def attributes
          return @attributes if defined?(@attributes)
          @attributes = @backend.run_command(
            "(Get-ItemProperty -Path \"#{@spath}\").attributes.ToString()").stdout.chomp.split(/\s*,\s*/)
        end

you can test this on the command line:

PS C:\> mkdir test_folder
    Directory: C:\
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         3/28/2018  11:41 AM            test_folder
PS C:\> attrib.exe .\test_folder
             C:\test_folder
PS C:\> attrib +A .\test_folder
PS C:\> attrib.exe .\test_folder
A            C:\test_folder
PS C:\> (Get-ItemProperty -Path C:\test_folder).attributes.ToString()
Directory, Archive
PS C:\>
PS C:\> attrib.exe -A .\test_folder
PS C:\> attrib.exe .\test_folder
             C:\test_folder
PS C:\> (Get-ItemProperty -Path C:\test_folder).attributes.ToString()
Directory

when Get-ItemProperty is called on a directory with the Archive bit set the logic fails and it is
reported as a file.

This causes controls to fail that are expecting a directory

control 'test folder' do
    title 'Checking c:\test_folder directory'  
    describe directory ('c:\test_folder') do
      it { should be_directory }
      its('type') { should eq :directory }
    end
  end

Train and Platform Version

Train 0.29.1
Windows 2012 R2

Replication Case

Windows 2012
another server to run Inspec from (the remote server)

create a folder with the archive bit set

PS C:\> mkdir test_folder
    Directory: C:\
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         3/28/2018  11:41 AM            test_folder
PS C:\> attrib.exe .\test_folder
             C:\test_folder
PS C:\> attrib +A .\test_folder
PS C:\> attrib.exe .\test_folder
A            C:\test_folder
PS C:\> (Get-ItemProperty -Path C:\test_folder).attributes.ToString()
Directory, Archive
PS C:\>

on the remote server
install inspec
and create a control

control 'test folder' do
    title 'Checking c:\test_folder directory'  
    describe directory ('c:\test_folder') do
      it { should be_directory }
      its('type') { should eq :directory }
    end
  end

run the control against the windows server

Possible Solutions

        def type
          if attributes.include?('Archive') && attributes.include?('Directory')
            return :directory
          elsif attributes.include?('Archive')
            return :file
          elsif attributes.include?('ReparsePoint')
            return :symlink
          elsif attributes.include?('Directory')
            return :directory
          end
          :unknown
        end

or possibly

        def type
          if attributes.include?('Archive') && !attributes.include?('Directory')
            return :file
          elsif attributes.include?('ReparsePoint')
            return :symlink
          elsif attributes.include?('Directory')
            return :directory
          end
          :unknown
        end

PR #275

Stacktrace

Need a ssh fork-and-exec transport

The benefits of fork+exec to command line ssh over net-ssh are:

  1. no bugs from net-ssh (constant problem with knife-ssh, particularly with new crypto algs)
  2. leverages all the users .ssh/config settings (constant problem with knife-ssh, again particularly with new crypto algs)
  3. MRI isn't multithreaded, so forking an ssh process allows all the crypto for the ssh process to run on a different CPU. With net-ssh and 50 ssh connections you'll be stuck in a single ruby process, no matter how many ruby threads you spawn, with fork+exec those 50 ssh connections run in their own process and can run on different cores.

odd errors when using docker container as my -t docker:// target

When testing with the dev-sec postgresql hardening build I am able to use this other than I can use the vagrant ssh key and the -t option. ( Other than that, this should be the same use case )

stig-postgres-baseline git:(master) โœ— inspec exec controls/V-73123.rb -t docker://bc7634a8664b --sudo --user=postgres --password=xxx

WARN: Unresolved specs during Gem::Specification.reset:
      net-ssh (< 5.0, >= 2.6.5, >= 2.9)
      winrm (~> 2.0)
      logging (< 3.0, >= 1.6.1)
      docker-api (~> 1.26)
      thor (~> 0.19)
      addressable (~> 2.4)
WARN: Clearing out unresolved specs.
Please report a bug if this causes problems.
/usr/local/lib/ruby/gems/2.4.0/gems/train-0.23.0/lib/train/transports/docker.rb:61:in `initialize': undefined method `get' for Docker::Container:Class (NoMethodError)
    from /usr/local/lib/ruby/gems/2.4.0/gems/train-0.23.0/lib/train/transports/docker.rb:41:in `new'
    from /usr/local/lib/ruby/gems/2.4.0/gems/train-0.23.0/lib/train/transports/docker.rb:41:in `create_new_connection'
    from /usr/local/lib/ruby/gems/2.4.0/gems/train-0.23.0/lib/train/transports/docker.rb:22:in `connection'
    from /usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.20.0/lib/inspec/backend.rb:23:in `create'
    from /usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.20.0/lib/inspec/runner.rb:64:in `configure_transport'
    from /usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.20.0/lib/inspec/runner.rb:56:in `initialize'
    from /usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.20.0/lib/inspec/base_cli.rb:81:in `new'
    from /usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.20.0/lib/inspec/base_cli.rb:81:in `run_tests'
    from /usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.20.0/lib/inspec/cli.rb:159:in `exec'
    from /usr/local/lib/ruby/gems/2.4.0/gems/thor-0.19.4/lib/thor/command.rb:27:in `run'
    from /usr/local/lib/ruby/gems/2.4.0/gems/thor-0.19.4/lib/thor/invocation.rb:126:in `invoke_command'
    from /usr/local/lib/ruby/gems/2.4.0/gems/thor-0.19.4/lib/thor.rb:369:in `dispatch'
    from /usr/local/lib/ruby/gems/2.4.0/gems/thor-0.19.4/lib/thor/base.rb:444:in `start'
    from /usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.20.0/bin/inspec:12:in `<top (required)>'
    from /usr/local/bin/inspec:22:in `load'
    from /usr/local/bin/inspec:22:in `<main>'```

OSX and probably all BSDs fail with sudo-password

Hi,

Currently the ssh transport uses base64 -d during auth for sudo with password. However on BSD machines the flag is -D.

inspec exec -t ssh://[email protected] -i key ~/.ssh/id_rsa --sudo --sudo-password 'hunter2' Sudo failed: base64: invalid option -- d Usage: base64 [-dhvD] [-b num] [-i in_file] [-o out_file] -h, --help display this message -D, --decode decodes input -b, --break break encoded string into num character lines -i, --input input file (default: "-" for stdin) -o, --output output file (default: "-" for stdout) Password:

Start testing on Ruby 2.5

Ruby 2.5 is now available and considered a "normal maintenance" branch. We need to add Travis/Appveyor testing for Ruby 2.5.

RFC: Generate unique uuid for platforms

Description

Generate a unique identifier for platforms that can be used to see if your hitting the same box over multiple runs. See if we already have a uuid on the box (via chef client or something else) else create one based on the criteria below.

Unix

  • cat /etc/machine-id || /var/lib/dbus/machine-id || /var/db/dbus/machine-id if valid
  • create uuids like:
      hash = Digest::SHA1.new
      hash.update(string)
      ary = hash.digest.unpack("NnnnnN")
      ary[2] = (ary[2] & 0x0FFF) | (5 << 12)
      ary[3] = (ary[3] & 0x3FFF) | 0x8000
      "%08x-%04x-%04x-%04x-%04x%08x" % ary

taken from https://github.com/rails/rails/blob/a9dc45459abcd9437085f4dd0aa3c9d0e64e062f/activesupport/lib/active_support/core_ext/digest/uuid.rb#L16

  • We could write a uuid to the disk if none exist. /etc/machine-uuid or local if that is not possible

OSX

hardware uuid system_profiler SPHardwareDataType | awk '/UUID/ { print $3; }'

Windows

wmic csproduct get UUID
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid in the registry

  • We could write a uuid to the disk if none exist.

AWS API

Use the account_id

Azure

Use subscription_id, fallback to tenant_id

platform names should be lower case

Running detect on some operating systems returns upper case values:

inspec detect -t ssh://[email protected]:2200 -i /Users/chartmann/Development/tests/freebsd-11/.vagrant/machines/default/virtualbox/private_key 

== Operating System Details

Name:      FreeBSD
Family:    freebsd
Release:   11.1-RELEASE-p1
Arch:      

This leads to wrong behavior where we do checks like

%w{freebsd}.include?(os[:name])

docker-api conflict when using docker cookbook

Hello,

I am attempting to use the docker cookbook, while using the Chef audit cookbook (actually, I'm trying to use the Swarm cookbook which depends on the docker cookbook, I believe it's a compatability issue between the docker cookbook and the r-train) I get the error:

Unable to activate r-train-0.12.0, because docker-api-1.28.0 conflicts with docker-api (~> 1.26.2)

This appears to be because docker has a requirement for docker-api-1.28.0, while r-train has a dependency on docker-api ~> 1.26.2?

Is there a way to work around this other than disabling Compliance?

Thanks!

Full output of error message:

================================================================================
Error executing action `fetch` on resource 'compliance_profile[ssh]'
================================================================================

Gem::ConflictError
------------------
Unable to activate r-train-0.12.0, because docker-api-1.28.0 conflicts with docker-api (~> 1.26.2)

Cookbook Trace:
---------------
/var/chef/cache/cookbooks/audit/libraries/profile.rb:37:in `block (2 levels) in <class:ComplianceProfile>'
/var/chef/cache/cookbooks/audit/libraries/profile.rb:30:in `block in <class:ComplianceProfile>'
/var/chef/cache/cookbooks/compat_resource/files/lib/chef_compat/monkeypatches/chef/runner.rb:41:in `run_action'

Resource Declaration:
---------------------
# In /var/chef/cache/cookbooks/audit/recipes/default.rb

 30:   compliance_profile p do
 31:     owner o
 32:     server server
 33:     token token
 34:     inspec_version node['audit']['inspec_version']
 35:     action [:fetch, :execute]
 36:   end
 37: end

Compiled Resource:
------------------
# Declared in /var/chef/cache/cookbooks/audit/recipes/default.rb:30:in `block in from_file'

compliance_profile("ssh") do
  action [:fetch, :execute]
  retries 0
  retry_delay 2
  default_guard_interpreter :default
  declared_type :compliance_profile
  cookbook_name "audit"
  recipe_name "default"
  owner "base"
  inspec_version "0.22.1"
end

Platform:
---------
x86_64-linux

Add integration test for PTY mode

In pty-mode, stdout and stderr is matched together. We need integration tests to ensure that at least the os-detection works straight forward. The second step is to figure out, why sudo requires tty. For that we should add documentation how a system should be configured

test remote host via ipv6 address

I want to test a remote host via ipv6 address and i got the following output:

inspec shell -t ssh://pmuench@2000:111b:ffe2:1:0:0:0:2 --port 545 --key-files /home/user/.ssh/id_rsa
/usr/lib/ruby/2.3.0/uri/rfc3986_parser.rb:67:in `split': bad URI(is not URI?): ssh://pmuench@2000:111b:ffe2:1:0:0:0:2 (URI::InvalidURIError)
        from /usr/lib/ruby/2.3.0/uri/rfc3986_parser.rb:73:in `parse'
        from /usr/lib/ruby/2.3.0/uri/common.rb:227:in `parse'
        from /usr/lib/ruby/gems/2.3.0/gems/r-train-0.11.3/lib/train.rb:66:in `target_config'
        from /usr/lib/ruby/gems/2.3.0/gems/inspec-0.21.1/lib/inspec/backend.rb:16:in `create'
        from /usr/lib/ruby/gems/2.3.0/gems/inspec-0.21.1/lib/inspec/runner.rb:45:in `configure_transport'
        from /usr/lib/ruby/gems/2.3.0/gems/inspec-0.21.1/lib/inspec/runner.rb:29:in `initialize'
        from /usr/lib/ruby/gems/2.3.0/gems/inspec-0.21.1/lib/inspec/cli.rb:141:in `new'
        from /usr/lib/ruby/gems/2.3.0/gems/inspec-0.21.1/lib/inspec/cli.rb:141:in `shell_func'
        from /usr/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
        from /usr/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
        from /usr/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch'
        from /usr/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
        from /usr/lib/ruby/gems/2.3.0/gems/inspec-0.21.1/bin/inspec:9:in `<top (required)>'
        from /home/user/.gem/ruby/2.3.0/bin/inspec:22:in `load'
        from /home/user/.gem/ruby/2.3.0/bin/inspec:22:in `<main>'

if i add a host entry in the ssh config like this:

Host testhost
        Hostname 2000:111b:ffe2:1::2

and the use the following command then it works:

inspec shell -t ssh://pmuench@testhost --port 545 --key-files /home/user/.ssh/id_rsa                  
WARN: Unresolved specs during Gem::Specification.reset:
      mixlib-shellout (~> 2.0)
      winrm-fs (~> 0.3)
      excon (>= 0.38.0)
      ffi (>= 1.0.1)
      unf_ext (>= 0)
WARN: Clearing out unresolved specs.
Please report a bug if this causes problems.
Welcome to the interactive InSpec Shell
To find out how to use it, type: help

inspec> 

please keep in mind the compressed ipv6 address notation

Add support for ssh-agent to ssh transport

NET::SSH supports using an SSH agent for ssh authentication, however train blows up if a keypath or password auth is not provided. Instead, it should allow for either the specification of using ssh agent, or allow the underlying NET::SSH library to try and use agent authentication if its available.

I ran across this by trying to run inspec in a docker container by providing access to the SSH agent socket and setting the SSH_AUTH_SOCK environment variable to point at it, but if '-t ssh://' is provided and neither '-i' or '--password' are provided, train throws an exception saying that one or the other is required.

Need push transport

The code in knife-push can be most likely pretty easily adapted to this, although it'll bring in the chef gem and Chef::REST as run-time deps to the project (and if some upstream consumer of this gem also depends on chef, or if chef at some point pulls in this gem, then you wind up with diamond or circular deps).

Cannot install train on Windows with ChefDK if username >9 chars in length due to spec filename lengths in docker-api gem.

The docker-api 1.22.4 gem which train depends on via the .gemspec appears to bundle specs that go beyond the file length limit of Windows (260 chars) when installed on my system.

Error seen:

C:\Users\StuartPreston> chef gem install r-train
WARNING:  You don't have c:\users\stuartpreston\appdata\local\chefdk\gem\ruby\2.1.0\bin in your PATH,
          gem executables will not run.
ERROR:  While executing gem ... (Errno::ENOENT)
    No such file or directory @ rb_sysopen - C:/Users/StuartPreston/AppData/Local/chefdk/gem/ruby/2.1.0/gems/docker-api-1.22.4/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_a_block_capturing_build_output/uses_a_cached_version_the_second_time/calls_the_block_and_passes_build_output.yml
C:\Users\StuartPreston>

By my calculations I believe that means only users with usernames less than 10 characters in length can install r-train on Windows at the moment but I'm doing some more testing. Thought I'd get an early report in as I'm sure others will see it.

Looks like a similar issue was encountered before by @someara in chef-docker: sous-chefs/docker#357 with the outcome being to vendor in the gems but remove the specs...

I would report this in docker-api but it's a combination of their spec length and the location of the ChefDK gems on Windows and the length of the username in combination that appear to be the problem.

Thoughts?

Edit: My own workaround for now is to build the docker-api gem from source, but without the specs then installed into the ChefDK. Note you have to clone into a folder near the root of a drive to avoid the path length failures.

reestablish support for ruby 1.9.3?

#123 introduced the winrm 2 dependency that supports ruby 2.x only. We should decouple the transports dependencies from train, so that we are able to support older systems with ruby 1.9.3 as well, even if they are not able to use all features.

Unify --keys handling

Several transports can use a key file - including SSH and WinRM. I believe this issue proposes using one option to refer to both.

get `Preparing modules for first use.` when I use train on Windows

As we experienced in our own tests on appveyor, powershell throws a Preparing modules for first use.. The use of $ProgressPreference='SilentlyContinue'; is not solving the issue.

  2) Failure:
windows local command#test_0002_run echo test [test/windows/local_test.rb:33]:
--- expected
+++ actual
@@ -1,2 +1,3 @@
 # encoding: UTF-8
-""
+"#< CLIXML\r
+<Objs Version=\"1.1.0.1\" xmlns=\"http://schemas.microsoft.com/powershell/2004/04\"><Obj S=\"progress\" RefId=\"0\"><TN RefId=\"0\"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N=\"SourceId\">1</I64><PR N=\"Record\"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S=\"progress\" RefId=\"1\"><TNRef RefId=\"0\" /><MS><I64 N=\"SourceId\">2</I64><PR N=\"Record\"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>

hostname property for WinRM::Connection

While troubleshooting a custom profile code that was parsing the hostname of the target like this:

inspec.backend.instance_variable_get(:@hostname)

I've discovered that the @hostname property is available for Train::Transports::SSH::Connection, but not for Train::Transports::WinRM::Connection:

[5] pry(#<Inspec::Resource::Registry::Ssl>)> inspec.backend
=> #<Train::Transports::SSH::Connection:0x000000039ad988
 @cmd_wrapper=nil,
 @connection_retries=5,
 @connection_retry_sleep=1,
 @files={"c:\\Windows"=>#<Train::Extras::LinuxFile:0x000000034360b8 @backend=#<Train::Transports::SSH::Connection:0x000000039ad988 ...>, @follow_symlink=true, @path="c:\\Windows", @spath="c:\\\\Windows">},
 @hostname="192.168.56.50",
 @logger=
...
[5] pry(#<Inspec::Resource::Registry::Ssl>)> inspec.backend
=> #<Train::Transports::WinRM::Connection:0x00000003cd9580
 @connection_retries=5,
 @connection_retry_sleep=1,
 @endpoint="http://192.168.56.98:5985/wsman",
 @files={"c:\\Windows"=>#<Train::Extras::WindowsFile:0x00000002461840 @backend=#<Train::Transports::WinRM::Connection:0x00000003cd9580 ...>, @follow_symlink=false, @path="c:\\Windows", @spath="c:\\Windows">},
 @logger=
...

The hostname can be extracted from @endpoint, but for consistency, it wouldn't hurt to have it in @hostname as well.

Integration test failures

Currently test kitchen integration tests fail:

         1) Error:
       run_command#test_0002_is not running sudo without password:
       Train::UserError: Sudo failed: Sudo requires a password, please configure it.
           /tmp/kitchen/data/lib/train/extras/command_wrapper.rb:101:in `load'
           /tmp/kitchen/data/lib/train/transports/local.rb:27:in `initialize'
           /tmp/kitchen/data/lib/train/transports/local.rb:19:in `new'
           /tmp/kitchen/data/lib/train/transports/local.rb:19:in `connection'
           /tmp/kitchen/data/test/integration/sudo/run_as.rb:11:in `run_as'
           test/integration/sudo/passwd.rb:13:in `block (2 levels) in <main>'


>>>>> Converge failed on instance <default-centos-511>.
>>>>>> Please see .kitchen/logs/default-centos-511.log for more details
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: SSH exited (1) for command: [sh -c '

sudo -E /opt/chef/bin/chef-solo --config /tmp/kitchen/solo.rb --log_level auto --force-formatter --no-color --json-attributes /tmp/kitchen/dna.json
']
>>>>>> ----------------------

Passing nil, or [nil] to Net::SSH.start is deprecated for keys: forward_agent

Description

Getting warning messages from Net::SSH.start when test-kitchen calls inspec (via kitchen-inspec) to ssh (via train) into GCE VM

Kitchen Version

Test Kitchen version 1.15.0

kitchen-inspec Version

kitchen-inspec (0.17.0)

Inspec Version

inspec (1.14.1)

Ruby Version

ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-linux]

Platform Version

Alpine Linux 3.4.4

Replication Case

Using test-kitchen, with kitchen-inspec and kitchen-terraform, to perform unit testing of GCE VM.
Once kitchen-terraform has successfully deployed the GCE VM, inspec attempts to ssh the VM and receives warnings are displayed from Net:SSH.start, about receiving nil for the forward_agent key, which is deprecated.

Kitchen Output

/usr/local/bundle/gems/train-0.22.1/lib/train/transports/ssh_connection.rb:188:in `establish_connection': Passing nil, or [nil] to Net::SSH.start is deprecated for keys: forward_agent
/usr/local/bundle/gems/train-0.22.1/lib/train/transports/ssh_connection.rb:188:in `establish_connection': Passing nil, or [nil] to Net::SSH.start is deprecated for keys: forward_agent
/usr/local/bundle/gems/train-0.22.1/lib/train/transports/ssh_connection.rb:188:in `establish_connection': Passing nil, or [nil] to Net::SSH.start is deprecated for keys: forward_agent

Kitchen Diagnose

https://gist.github.com/qvallance-ctc/e1a8d2d48c5beede3882e1a616027b0d

Master OS detect family

Description

Create a master OS family to contain all the base os's. This separates them from the api families.

Bastion support for SSH transport

The SSH transport should support bastion or jump hosts. A lot of folks run their hosts, especially in AWS/GCP, behind bastion or jump hosts. Without this support it's hard for downstream tools like InSpec to run tests.

have net-ssh request a pty

The issue we face is basically described here: net-ssh/net-ssh#103: when train tries to execute a command using sudo, and the target system's sudoers config contains requiretty, the call will fail with something like

$lib/train/extras/command_wrapper.rb:131:in `load': Sudo failed:  sudo: sorry, you must have a tty to run sudo (Train::UserError)

The way forward would be to request a pty, with example code here.

@chris-rock @arlimus What do you think about that?

Recommend Projects

  • React photo React

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

  • Vue.js photo Vue.js

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

  • Typescript photo Typescript

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

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

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

  • web

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

  • server

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

  • Machine learning

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

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

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

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.