Code Monkey home page Code Monkey logo

puppet-eos's People

Contributors

alvagante avatar devrobo avatar huntburdick avatar jerearista avatar privateip avatar rknaus avatar sandynomad avatar

Stargazers

 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

puppet-eos's Issues

Gems not Ruby 1.9.3 compatible

According to the README the types and providers are compatible with Ruby 1.9.3.
When doing a bundle install I get error messages that at least Ruby 2.2.5 is required because of the ruby_dep and json Gem.
@jerearista Is it possible to use older versions of the referenced Gems which are Ruby 1.9.3 compatible?

Error messages with Ruby 1.9.3
Gem::InstallError: ruby_dep requires Ruby version >= 2.2.5, ~> 2.2.
Gem::InstallError: json requires Ruby version ~> 2.0.

eos_prefixlist doesn't create the resource . .

With

eos_prefixlist { "TEST:10":
    action  =>  'permit',
    prefix  =>  '0.0.0.0/0',
    ensure  =>  'present'
}

and running puppet:

gw-00#puppet agent --test
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Warning: Found multiple default providers for package: yum, puppet_gem, pip3; using yum
Info: Caching catalog for gw-00
Info: Applying configuration version 'master:28d1af93cf429272d9399753f9c176961eb471b7:puppet-10'
Notice: /Stage[main]/Network_eos::Bgpd/Eos_prefixlist[TEST:10]/ensure: created
Notice: Applied catalog in 4.68 seconds
% 'sudo /opt/puppetlabs/bin/puppet agent --test' returned error code: 2
gw-00#show ip prefix-list
gw-00#

installed via. these RPMs:

puppet-agent-1.9.3-1.eos4.i386
rubygem-netaddr-puppet-aio-2.0.3-4.eos4.noarch
rubygem-net_http_unix-puppet-aio-0.2.2-5.eos4.noarch
rubygem-rbeapi-puppet-aio-1.3-1.eos4.noarch
rubygem-inifile-puppet-aio-3.0.0-5.eos4.noarch

Add refreshonly parameter to eos_command

Allow eos_command to be triggered idempotently by a refresh instead of running always.

Simplified use case: the config will only be saved IF the vlan resource changes.

eos_vlan { '3':
  ensure => present,
  notify => Eos_command['save_config'],
}

eos_command { 'save_config':
  mode        => enable,
  command     => 'copy running-config startup-config',
  refreshonly => true,
}

See:
https://docs.puppetlabs.com/references/latest/type.html#exec
https://forge.puppetlabs.com/puppetlabs/postgresql
https://github.com/puppetlabs/puppetlabs-postgresql/search?utf8=%E2%9C%93&q=refreshonly

"Undefined method" error when using eos_logging_host

In a Puppet manifest, adding:

eos_logging_host { '10.0.0.1': }

Gives the following error:

bash-4.1# puppet agent -t
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Warning: Found multiple default providers for package: yum, puppet_gem, pip3; using yum
Info: Caching catalog for arista-switch-7010.example.com
Info: Applying configuration version '1511215983'
Error: Failed to apply catalog: undefined method `each' for nil:NilClass

I've been using other parts of the module just fine, like eos_user. Any tips?

Are providers properly handling errors returned from rbeapi calls?

The rbeapi api library is rescuing CommandError and ConnectionError and returning false. Is that the right thing to do? The caller should be inspecting errors to figure out why the call failed but do we really want to add an error check to each api call?

Need to analyze the problem, come up with an appropriate solution, and then make sure we have test cases to highlight the original problem.

mock not intercepting acl.getall call

The fixture file for the eos_acl_entry provider spec test was not correct but while debugging I noticed that the getall call in rbeapi was getting called and ultimately a getall call was being performed on my dut when it should have been mocked.

From: /Users/jcorbin/Desktop/EOS+/puppet-eos/spec/unit/puppet/provider/eos_acl/default_spec.rb @ line 89 :

84:       end
85: 
86:       context 'eos_acl { test1: }' do
87:         subject { described_class.instances.find { |p| p.name == 'test1' && p.seqno == 10 } }
88: 

=> 89: require 'pry'; binding.pry
90: include_examples 'provider resource methods',
91: acltype: :standard,
92: seqno: 10,
93: action: :permit,
94: srcaddr: 'host 1.2.3.4',

[1] pry(#)> print described_class.instances

From: /Users/jcorbin/Desktop/EOS+/rbeapi/lib/rbeapi/api/acl.rb @ line 80 Rbeapi::Api::Acl#getall:

79: def getall

=> 80: require 'pry'; binding.pry
81: acls = config.scan(/ip access-list standard ([^\s]+)/)
82: acls.each_with_object({}) do |name, hsh|
83: resource = get(name[0])
84: hsh[name[0]] = resource if resource
85: end
86: end

[1] pry(#Rbeapi::Api::Acl)> ^D
Rbeapi::Eapilib::ConnectionError: unable to connect to eAPI
from /Users/jcorbin/Desktop/EOS+/rbeapi/lib/rbeapi/eapilib.rb:274:in `rescue in send'

Wrong datatype ine trunk_groups

If I want to create this resource
eos_vlan { '4094':
enable => true,
vlan_name => 'MLAG_control',
trunk_groups => ['trunkpeer'],
}
with this patch applied #78. There is still a missmatch in the datatype.
The config on the switch in the running-config shows.

vlan 4094
name MLAG_control
trunk group {:value=>["trunkpeer"]}

This looks like an array string missmatch, but I cannot find where.
Any help would be appreciated

Best Regards,
martin

eos_portchannel members not idempotent when interface order is not the same

hiera: eos_config::portchannel::members: ['Ethernet1', 'Ethernet2']
Switch state:

show port-channel 1 all-ports
Port Channel Port-Channel1:
  Active Ports: Ethernet2 
  Configured, but inactive ports:
       Port         Reason unconfigured                                   
    --------------- ----------------------------------------------------- 
       Ethernet1    LACP negotiated incompatible aggregate (check config) 

Produces:

Notice: /Stage[main]/Eos_config::Portchannel/Eos_portchannel[Port-Channel1]/members: members changed ['Ethernet2', 'Ethernet1'] to 'Ethernet1 Ethernet2'

Suspect this could be equally reproducible in a normal state with eos_config::portchannel::members: ['Ethernet2', 'Ethernet1']

Clean up boolean properties and parameters in types

The types are currently defining possible boolean newvalues and defining the munge_boolean method which can all be replaced by setting the :parent => Puppet::Parameter::Boolean option. A positive side effect of this change is that ruby boolean values (i.e. true, false) are now returned instead of boolean symbols (i.e. :true, :false). This will require fixing the boolean shared examples and should allow removing the symbol to boolean conversions that we do in providers.

Example:

 newparam(:force, boolean: :true, :parent => Puppet::Parameter::Boolean)

Need to add 'require 'puppet/parameter/boolean' to the top of the type module.

Also need to make sure the defautto() calls are made to set booleans to the correct default value.

eos_bgp_neighbor not configuring

This is with the rbeapi bgp and puppet-eos bgp feature branches (the one which is waiting in a pull request). I can't figure out how to create an issue in that particular branch, but it seems to be all Arista employees.

The puppet type/provider is not actually changing the configuration successfully:

[root@arista1 /persist/local]# puppet resource eos_bgp_config 65002 enable=true router_id=99.99.99.100
Notice: /Eos_bgp_config[65002]/ensure: created
eos_bgp_config { '65002':
ensure => 'present',
}
[root@arista1 /persist/local]# puppet resource eos_bgp_config
eos_bgp_config { '65002':
ensure => 'present',
enable => 'false',
}

(The puppet resource output at the end also matches the actual CLI configuration)

Manifest correctly applied but error returned

Hey there,
I've just started to dig Puppet and EOS and I've encountered some issues during the journey.
I'm using Puppet 4.3.2 on both Server (an Ubuntu 14.04 VM) and Agent (vEOS).

I've created the ~/environments/production/manifests/ directory and put here this site.pp manifest:

node 'test.test.com' {
        eos_vlan { "20":
        vlan_name => "Testing",
        ensure => present,
    }
}

Then, I started the server with puppet master --no-daemonize --verbose and the agent puppet agent -t, obtaining this:

test#puppet agent -t
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for test.test.com
Info: Applying configuration version '1456663047'
Notice: /Stage[main]/Main/Node[test.test.com]/Eos_vlan[20]/ensure: created
Notice: Applied catalog in 0.95 seconds
'sudo /opt/puppetlabs/bin/puppet agent -t' returned error code:2

Here, the manifest is correctly applied and the VLAN is configured, but I also receive that error.

test#sh vlan 20
VLAN  Name                             Status    Ports
----- -------------------------------- --------- -------------------------------
20    Testing                          active

Why is this?

load-balance doesn't eval in eos_switchconfig

Using this example puppet config example2.pp:

$running_config = @(END)
! ...
load-balance policies
   load-balance fm6000 profile LB-7
      fields mac dst-mac vlan-priority
      fields ip protocol src-ip
      distribution symmetric-hash mac-ip
! ...
end
END

eos_switchconfig { 'running-config':
  content => $running_config,
}
-bash-4.3# puppet apply example2.pp --trace
...
Error: /Stage[main]/Main/Eos_switchconfig[running-config]: Could not evaluate:
>    load-balance fm6000 profile LB-7

% Invalid input at line 6
% Configuration replace aborted due to errors in loading the file

/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/util/errors.rb:106:in `fail'
/opt/puppetlabs/puppet/modules/eos/lib/puppet/provider/eos_switchconfig/default.rb:103:in `rescue in flush'
/opt/puppetlabs/puppet/modules/eos/lib/puppet/provider/eos_switchconfig/default.rb:87:in `flush'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/type.rb:1006:in `flush'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/transaction/resource_harness.rb:25:in `evaluate'
...

Note: The only way to encounter this issue is by first solving #140.

eos_vlan provider does not properly set trunk_groups

The provider attempts to call rbeapi.api('vlans').set_trunk_group when the closest method available is add_trunk_group.

The provider should check the existing trunk groups and call add_trunk_group as many times as needed to reconcile the list. Similarly, remove_trunk_group may need to be called multiple times to purge undesired trunk_groups.

Arista#bash sudo /opt/puppet/bin/puppet apply -e "eos_vlan { '4094': trunk_groups => ['test1', 'test2'], }"
Notice: Compiled catalog for larry.localdomain in environment production in 0.03 seconds
Error: undefined method `set_trunk_group' for #<Rbeapi::Api::Vlans:0xa44aef8>
Error: /Stage[main]/Main/Eos_vlan[4094]/trunk_groups: change from [] to test1 test2 failed: undefined method `set_trunk_group' for #<Rbeapi::Api::Vlans:0xa44aef8>

spec test are failing

at the develop branch spec test are falling, testet commit 61f9dad

Failures:

  1) Puppet::Type::Eos_prefixlist::ProviderEos instance methods #create extracts seqno and prefix_list from name
     Failure/Error: new_resource.provider.flush
       Double "prefixlists" received unexpected message :add_rule with ("test99", :permit, "10.99.0.0/16", 99)
     # ./lib/puppet/provider/eos_prefixlist/default.rb:143:in `flush'
     # ./spec/unit/puppet/provider/eos_prefixlist/default_spec.rb:218:in `block (4 levels) in <top (required)>'

Finished in 1.78 seconds (files took 3.44 seconds to load)
2779 examples, 1 failure

eos_interface not controlling shutdown/enable status properly

[root@arista1 ~]# puppet resource eos_interface Loopback1
eos_interface { 'Loopback1':
ensure => 'present',
enable => 'false',
}

[root@arista1 ~]# puppet resource eos_interface Loopback1 enable=true
Notice: /Eos_interface[Loopback1]/enable: enable changed 'false' to 'true'
eos_interface { 'Loopback1':
ensure => 'present',
enable => 'true',
}

[root@arista1 ~]# puppet resource eos_interface Loopback1
eos_interface { 'Loopback1':
ensure => 'present',
enable => 'false',
}

The lack of changes are also reflected in the running-config in the CLI as well

portchannel_convergence needs two puppet runs

We need two puppet runs to get a convergence on the property lacp_mode for portchannels.

leaf01(config)#bash sudo /opt/puppetlabs/bin/puppet resource eos_portchannel Port-Channel1 description='leaf02 po1 trunk mlag' lacp_mode='active' members='Ethernet7'
Notice: /Eos_portchannel[Port-Channel1]/ensure: created
eos_portchannel { 'Port-Channel1':
ensure => 'present',
description => 'leaf02 po1 trunk mlag',
lacp_mode => 'active',
members => ['Ethernet7'],
}
show running-config section interface
....
interface Ethernet7
channel-group 1 mode on

leaf01(config)#bash sudo /opt/puppetlabs/bin/puppet resource eos_portchannel Port-Channel1 description='leaf02 po1 trunk mlag' lacp_mode='active' members='Ethernet7'
Notice: /Eos_portchannel[Port-Channel1]/lacp_mode: lacp_mode changed 'on' to 'active'
eos_portchannel { 'Port-Channel1':
ensure => 'present',
description => 'leaf02 po1 trunk mlag',
lacp_mode => 'active',
members => ['Ethernet7'],
}

show running-config section interface
...
interface Ethernet7
channel-group 1 mode active

Proposed fix from the PR:

leaf01(config)#bash sudo /opt/puppetlabs/bin/puppet resource eos_portchannel Port-Channel1 description='leaf02 po1 trunk mlag' lacp_mode='active' members='Ethernet7'
Notice: /Eos_portchannel[Port-Channel1]/ensure: created
eos_portchannel { 'Port-Channel1':
ensure => 'present',
description => 'leaf02 po1 trunk mlag',
lacp_mode => 'active',
members => ['Ethernet7'],
}

show running-config section interface
...
interface Ethernet7
channel-group 1 mode active

Cleanup documentation

Need to go through and review the generated documentation. Seeing minor issues in the type docstrings.

Missing properties on eos_bgp_neighbor

This is primarily a limitation of RBEAPI, but it is not possible to set several properties (we use) of a BGP neighbor:

  • password
  • update source
  • monitoring
  • graceful restart
  • maximum routes

Of them, the most critical is the absence of setting a password. Although eos_config can be used to set all the the above properties, with eos_config the command being injected is being captured in the logs (which is not desirable behaviour for passwords).

eos_command should take "refreshonly" parameter.

After a configuration modifying event, it's necessary to save the running configuration to startup. While the configuration can be saved with the following:

eos_command { 'Save running-config':
    mode     => 'enable',
    commands => 'copy running-config startup-config',
}

This is done every time that puppet is run. Thus "eos_command" needs a "refreshonly" parameter when another resource is changed (for example, changing a configuration).

Default value for staging_file not used for eos_switchconfig

Using this example puppet config example1.pp:

$running_config = ... # Config is a string
eos_switchconfig { 'running-config':
  content => $running_config,
}
-bash-4.3# puppet apply example1.pp --trace
...
Error: /Stage[main]/Main/Eos_switchconfig[running-config]: Could not evaluate: no implicit conversion of nil into String
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/util/errors.rb:106:in `fail'
/opt/puppetlabs/puppet/modules/eos/lib/puppet/provider/eos_switchconfig/default.rb:102:in `rescue in flush'
/opt/puppetlabs/puppet/modules/eos/lib/puppet/provider/eos_switchconfig/default.rb:88:in `flush'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/type.rb:1006:in `flush'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/transaction/resource_harness.rb:25:in `evaluate'
...

Manually patched /opt/puppetlabs/puppet/modules/eos/lib/puppet/provider/eos_switchconfig/default.rb to resolve issue

It is not possible to change a user password if they are encryptet in md5 or sha512

It is not possible to change a user password if they are encrypted in md5 or sha512

In the rbeapi in the file lib/rbeapi/api/users.rb

line 220 "enc = opts.fetch(:encryption, 'cleartext')"
we default to cleartext if no encryption is set.

In the module puppet-eos file lib/puppet/provider/eos_user/default.rb
line 125 we use the @property_flush to send the changes to rbeapi.

In the case we just want to change the password of a user, which is encryptet with md5 or sha512,
The @property_flush just contains the :secret not the :encryption therefore in the rbeapi we fallback to cleartext. That is the reason why it is not working.

We should set the :encryption in the @porperty_flush as well to fix that.
Please see my PR.

autoload issue with netaddr gem in eos_varp type

We have an issue with the munge function of the eos_varp type because it uses an external gem (netaddr). When using the type in our puppet module we get the following error when the puppet agent runs:


clnchsw19f2bez#bash sudo ip netns exec ns-cloud-mgmt /opt/puppetlabs/bin/puppet agent --environment production --server rh7pt-64.mgmt.sccloudpoc.net --confdir /persist/sys/puppet --daemonize --no-onetime -t --trace
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Warning: Found multiple default providers for package: yum, puppet_gem, pip3; using yum
Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Evaluation Error: Error while evaluating a Resource Statement, Evaluation Error: Error while evaluating a Resource Statement, Could not autoload puppet/type/eos_varp: no such file to load -- netaddr at /etc/puppetlabs/code/environments/production/modules/nc_arista_eos/manifests/flavors/leaf.pp:206:3 at /etc/puppetlabs/code/environments/production/modules/role_base/manifests/flavors.pp:25 on node clnchsw19f2bez.mgmt.sccloudpoc.net
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/indirector/rest.rb:212:in is_http_200?' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/indirector/rest.rb:110:infind'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/indirector/indirection.rb:194:in find' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/configurer.rb:377:inblock in retrieve_new_catalog'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/util.rb:386:in block in thinmark' /opt/puppetlabs/puppet/lib/ruby/2.1.0/benchmark.rb:294:inrealtime'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/util.rb:385:in thinmark' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/configurer.rb:376:inretrieve_new_catalog'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/configurer.rb:78:in retrieve_catalog' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/configurer.rb:147:inprepare_and_retrieve_catalog'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/configurer.rb:281:in run_internal' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/configurer.rb:186:inblock in run'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/context.rb:65:in override' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet.rb:240:inoverride'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/configurer.rb:185:in run' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/agent.rb:45:inblock (4 levels) in run'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/agent/locker.rb:21:in lock' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/agent.rb:45:inblock (3 levels) in run'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/agent.rb:98:in with_client' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/agent.rb:42:inblock (2 levels) in run'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/agent.rb:65:in run_in_fork' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/agent.rb:41:inblock in run'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/application.rb:179:in call' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/application.rb:179:incontrolled_run'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/agent.rb:39:in run' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/application/agent.rb:353:inonetime'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/application/agent.rb:331:in run_command' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/application.rb:344:inblock in run'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/util.rb:540:in exit_on_fail' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/application.rb:344:inrun'
/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/util/command_line.rb:128:in run' /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/util/command_line.rb:72:inexecute'
/opt/puppetlabs/puppet/bin/puppet:5:in `

'
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run
'sudo ip netns exec ns-cloud-mgmt /opt/puppetlabs/bin/puppet agent --environment production --server rh7pt-64.mgmt.sccloudpoc.net --confdir /persist/sys/puppet --daemonize --no-onetime -t --trace' returned error code:1
clnchsw19f2bez#


In our puppet module we use the resource like this:

create the varp mac address

eos_varp { 'settings':
mac_address => $default_varp_mac_address,
}

Would it be possible to remove the munge function with the used netaddr gem (https://github.com/arista-eosplus/puppet-eos/blob/develop/lib/puppet/type/eos_varp.rb#L53) and validate the mac address with a simple regex?

Or is there a way to avoid the autoload issue with puppet?

'Could not find a suitable provider' on EOS 4.18

On EOS 4.18, the puppet agent may report the following error when attempting to use eos_* resource types:

Error: Could not find a suitable provider for eos_vlan

Cause:

In EOS 4.18, the file /etc/redhat-release exists which causes facter to register the operatingsystem as Fedora instead of getting to the check for /etc/Eos-release and registering it as AristaEOS. This causes the provider selection criteria to fail.

Workaround:

On EOS, ensure the puppet agent runs with the RBEAPI_CONNECTION=localhost included within its environment. Example for running puppet from the EOS CLI. Place the following in the EOS configuration:

alias puppet bash sudo RBEAPI_CONNECTION=localhost /opt/puppet/bin/puppet

Found in puppet-enterprise-3.8.7-eos-4-i386.swix

Providers only actually work in tests

Error: Could not autoload puppet/type/eos_user: Could not autoload puppet/provider/eos_user/default: undefined method `version' for nil:NilClass

This is because the confine relies on the gem already being required somewhere once. Obviously tests are fine as the spec_helper loads the rbeapi gem - but nothing else does.

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.