Giter VIP home page Giter VIP logo

puppet-aptly's Introduction

Aptly Puppet module

TravisBuild Puppet Forge latest release Puppet Forge downloads Puppet Forge score

Table of Contents

  1. Overview
  2. Module Description - What the module does and why it is useful
  3. Setup - The basics of getting started with aptly
  4. Usage - Configuration options and additional functionality
  5. Reference - An under-the-hood peek at what the module is doing and how
  1. Limitations - OS compatibility, etc.
  2. Development - Guide for contributing to the module

Overview

This module installs the aptly Debian packages repository manager and configures it.

Need help of want a new feature? File an issue on our github repository: https://github.com/tubemogul/puppet-aptly/issues

Module Description

What is this module capable of doing?

  • Installing the aptly package in a specific version (or just the latest available)
  • Managing a specific user and group (with their corresponding fixed uid/gid) dedicated to the service
  • Configuring a specific debian repository (optional) where to find the package
  • Managing the /etc/aptly.conf file
  • Enabling/starting or disabling the service
  • Enabling/starting or disabling the API
  • Managing the init.d service file
  • Managing apt mirrors, repositories, snapshots and publications

The aptly service will listen on port you configure (example: 8080) on every interfaces (configurable) using the aptly serve -listen=":8080" command.

If you want to make the repository being served by an apache, nginx or whatever else, just disable the service and setup the http server you want for the HTTP(S) layer in addition to this module.

Setup

What aptly affects

Files managed by the module:

  • /etc/aptly.conf
  • /etc/apt/sources.list.d/aptly.list (optional)
  • /etc/init.d/aptly

Setup Requirements

The module requires:

Beginning with aptly

The module can be used out of the box directly, it just requires puppetlabs' apt module and its stdlib to be in your modulepath.

To install:

puppet module install TubeMogul/aptly

Puppet will install the dependencies automatically, but if you want to install the dependencies 1 by 1, you can use this before:

puppet module install puppetlabs/stdlib
puppet module install puppetlabs/apt

Usage

WARNING: the aptly service won't start as long as nothing has been published in it. It is a totally expected behavior coming from aptly itself.

Those examples include the puppet-only configuration, and the corresponding configuration for those who use hiera (I find it more convenient for copy/paste of a full configuration when you have both - yes, I'm lazy ;-) ).

Basic example

The default values are normally sane enough to do as few parameters overwrites as possible.

But let's say you want:

  • Aptly to store its data in /data (that you created before hand)
  • to only have the architectures i386 and amd64
  • to have your ppa codename to be foo

Then you just do:

class { 'aptly':
  root_dir      => '/data',
  architectures => ['i386', 'amd64'],
  ppa_codename  => 'foo',
}

Or using hiera:

---
aptly::root_dir: /data
aptly::architectures:
  - i386
  - amd64
aptly::ppa_codename: foo

NOTE: this will also install the official aptly repo in your sources.list.d.

Enable aptly API endpoint

To:

  • enable the aptly API management
  • make the API listen on port 42000
  • have the API listen on the private interface of your server (let's say this interface's IP is 10.0.0.123)
  • have the API configured in no-lock mode as you are doing both cli and API calls

Then you can do:

class { 'aptly':
  enable_api => true,
  api_port   => 42000,
  api_bind   => '10.0.0.123',
  api_nolock => true,
}

Or using hiera:

---
aptly::enable_api: true
aptly::api_port: 42000
aptly::api_bind: 10.0.0.123
aptly::api_nolock: true

Create an apt mirror

Warning: after creating the mirror, the update of the mirror from its source is initiated. This can take a significant amount of time.

To create an APT repository:

  • of the Debian US repo
  • of the stable distribution
  • only taking the main component
  • only for the amd64 architecture

Use:

aptly::mirror { 'debian_stable':
  location      => 'http://ftp.us.debian.org/debian/',
  distribution  => 'stable',
  components    => [ 'main' ],
  architectures => ['amd64'],
}

Note: This module does not manage the gpg keys directly, so if you don't take care of adding the gpg file of your target repository, you'll end up with the following error:

Error: /Stage[main]/Main/Aptly::Mirror[debian_stable]/Aptly_mirror[debian_stable]/ensure: change from absent to present failed: Execution of 'aptly -architectures=amd64 -with-sources=false -with-udebs=false mirror create debian_stable http://ftp.us.debian.org/debian/ stable main' returned 1: Looks like your keyring with trusted keys is empty. You might consider importing some keys.
If you're running Debian or Ubuntu, it's a good idea to import current archive keys by running:

  gpg --no-default-keyring --keyring /usr/share/keyrings/debian-archive-keyring.gpg --export | gpg --no-default-keyring --keyring trustedkeys.gpg --import

(for Ubuntu, use /usr/share/keyrings/ubuntu-archive-keyring.gpg)

Downloading http://ftp.us.debian.org/debian/dists/stable/InRelease...
Downloading http://ftp.us.debian.org/debian/dists/stable/Release...
Downloading http://ftp.us.debian.org/debian/dists/stable/Release.gpg...
gpgv: Signature made Sat Jun  4 08:26:51 2016 GMT+5 using RSA key ID 46925553
gpgv: Can't check signature: public key not found
gpgv: Signature made Sat Jun  4 08:26:51 2016 GMT+5 using RSA key ID 2B90D010
gpgv: Can't check signature: public key not found
gpgv: Signature made Sat Jun  4 08:36:26 2016 GMT+5 using RSA key ID 518E17E1
gpgv: Can't check signature: public key not found

Looks like some keys are missing in your trusted keyring, you may consider importing them from keyserver:

gpg --no-default-keyring --keyring trustedkeys.gpg --keyserver keys.gnupg.net --recv-keys 8B48AD6246925553 7638D0442B90D010 CBF8D6FD518E17E1

Sometimes keys are stored in repository root in file named Release.key, to import such key:

wget -O - https://some.repo/repository/Release.key | gpg --no-default-keyring --keyring trustedkeys.gpg --import

ERROR: unable to fetch mirror: verification of detached signature failed: exit status 2

Here's a full example of how you can manage your gpg keys along with the mirror:

aptly::mirror { 'debian_stable':
  location      => 'http://ftp.us.debian.org/debian/',
  distribution  => 'stable',
  components    => [ 'main'] ,
  architectures => ['amd64'],
}

exec { 'debian_stable_key_8B48AD6246925553':
  command => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --keyserver keys.gnupg.net --recv-key 8B48AD6246925553',
  unless  => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --list-key 8B48AD6246925553 > /dev/null 2>&1',
}

exec { 'debian_stable_key_7638D0442B90D010':
  command => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --keyserver keys.gnupg.net --recv-key 7638D0442B90D010',
  unless  => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --list-key 7638D0442B90D010 > /dev/null 2>&1',
}

exec { 'debian_stable_key_CBF8D6FD518E17E1':
  command => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --keyserver keys.gnupg.net --recv-key CBF8D6FD518E17E1',
  unless  => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --list-key CBF8D6FD518E17E1 > /dev/null 2>&1',
}


Exec['debian_stable_key_8B48AD6246925553']->
Exec['debian_stable_key_7638D0442B90D010']->
Exec['debian_stable_key_CBF8D6FD518E17E1']->
Aptly::Mirror['debian_stable']

Create and drop apt repositories

Using the aptly::repo is really simple. In this example, we will:

  • drop the my_custom_repo repository
  • create the tubemogul_apps repository (with "stable" as default component for publishing)

Use:

# Dropping the 'my_custom_repo' repo
aptly::repo {'my_custom_repo':
  ensure => absent,
}

# Making sure that the 'tubemogul_apps' exists with the expected parameters
aptly::repo {'tubemogul_apps':
  default_component => 'stable',
}

Once you've done that, you can add packages using the aptly repo add tubemogul_apps my_package.deb or using the API.

Create an aptly snapshot

Once you've created your repo and added packages to it, you might want to take a snapshot of a stable stack or a coherent ensemble to publish it later.

This example creates a snapshot named nightly_20160823 based on the repository tubemogul_apps that we created in the previous example:

aptly::snapshot { 'nightly_20160823':
  source_type => 'repository',
  source_name => 'tubemogul_apps',
}

Reference

Public classes and defines

Private classes

  • aptly::install: Installs the aptly server.
  • aptly::config: Configures the aptly server.
  • aptly::service: Manages the aptly server and the API services.

Providers and types

To manage the aptly resources, this modules embeds the following custom types and corresponding providers (to be accessed via the public defines):

  • aptly_mirror to manage an aptly mirror
  • aptly_repo to manage an aptly repository
  • aptly_snapshot to manage an aptly snapshot
  • aptly_publish to manage an aptly publication

Parameters

Class aptly

version

Aptly version to ensure to install. You can use a version number to force a version or just use installed or latest to benefit from the usual Puppet behavior.

Default: installed

install_repo

Boolean to manage whether or not you want to have a sources.list repo managed by the module.

Default: true

repo_location

Location of the remote repo to manage when using install_repo to true.

Default: http://repo.aptly.info

repo_release

Release of the repo to use when using install_repo to true.

Default: squeeze

repo_repos

Repo name to use in the repo when using install_repo to true.

Default: main

repo_keyserver

Key server to use to retreive the key of the repo when using install_repo to true.

Default: keys.gnupg.net

repo_key

Key used by the signed repo when using install_repo to true.

Default: DF32BC15E2145B3FA151AED19E3E53F19C7DE460

enable_service

Boolean to enable or disable the service.

Default: true (service enabled)

port

Port for the Aptly webserver

Default : 8080

bind

IP address of the Aptly webserver (0.0.0.0 or empty string meaning that you listen on all interfaces).

Default: 0.0.0.0

config_filepath

Path of the configuration file to be used by the aptly service.

Default: /etc/aptly.conf

manage_user

Whethere should this module manage aptly user or not

Default: true

user

OS user which will run the service.

Default: aptly

uid

UID of the OS user which will run the service.

Default: 450

group

Group of the OS user which will run the service.

Default: aptly

gid

GID of the group of the OS user which will run the service.

Default: 450

root_dir

Root directory to use for storing the repo data.

Default: /var/aptly

architectures

Architectures managed by the repo.

Default: ["amd64"]

ppa_dist

Distribution code of the ppa to serve.

Default: ubuntu

ppa_codename

Codename of the ppa to serve.

Default: ''

properties

Hash containing the optional properties of the aptly.conf. The key is the property name and the value is its value!

Default:

{
  'downloadConcurrency'         => 4,
  'downloadSpeedLimit'          => 0,
  'dependencyFollowSuggests'    => false,
  'dependencyFollowRecommends'  => false,
  'dependencyFollowAllVariants' => false,
  'dependencyFollowSource'      => false,
  'gpgDisableSign'              => false,
  'gpgDisableVerify'            => false,
  'downloadSourcePackages'      => false,
}
s3_publish_endpoints

Hash to describe the s3PublishEndpoints property of the aptly.conf.

Default: {}

swift_publish_endpoints

Hash to describe the SwiftPublishEndpoints property of the aptly.conf.

Default: {}

enable_api

Enable Aptly API by starting the service

Default : false

api_port

Port for the Aptly API service.

Default : 8081

api_bind

Binding address for the Aptly API service.

Default : 0.0.0.0

api_nolock

If true, the API service will not lock the database (for situations where you heavily use both the API and the cli for example).

Default : false

manage_xz_utils

Boolean to enable or disable installation of the xz-utils package (required dependency for aptly).

Default : true

Define aptly::mirror

ensure

Ensures if the mirror must be present (should exist) or absent (or be destroyed).

Default: present

uid

UID of the OS user which will run the cli

Default: 450

gid

GID of the OS user which will run the cli

Default: 450

location

Location of the repository to mirror.

Default: undef

distribution

Distribution to mirror.

Default: $::lsbdistcodename

architectures

Architectures to mirror.

Default: []

components

Components to mirror.

Default: []

with_sources

Mirror the sources packages or not.

Default: false

with_udebs

Download the .udeb packages.

Default: false

Define aptly::repo

ensure

Ensures if the repository must be present (should exist) or absent (or be destroyed).

Default: present

uid

UID of the OS user which will run the cli

Default: 450

gid

GID of the OS user which will run the cli

Default: 450

default_distribution

Default distribution (used only when publishing).

Default: $::lsbdistcodename

default_component

Default component (used only when publishing).

Default: main

Define aptly::snapshot

ensure

Ensures if the snapshot must be present (should exist) or absent (or be destroyed).

Default: present

uid

UID of the OS user which will run the cli

Default: 450

gid

GID of the OS user which will run the cli

Default: 450

source_type

Type of source to snapshot. Correct values are:

  • mirror
  • repo
  • empty

Default: undef

source_name

Name of the source to create snapshot from.

Default: undef

Define aptly::publish

ensure

Ensures that the publication is present (should exist) or absent (or should be destroyed).

Default: present

uid

UID of the OS user which will run the cli

Default: 450

gid

GID of the OS user which will run the cli

Default: 450

source_type

Type of source to publish. Supported values are:

  • repo
  • snapshot

Default: undef

distribution

Distribution name to publish.

Default: "${::lsbdistcodename}-${name}"

Limitations

This module has been tested against Puppet 3.8 with Ubuntu clients.

The spec tests work on Puppet 3.7+ and 4.x.

To work on Debian OS family servers, it requires the apt module from Puppetlabs to be installed if you want to have this module manage your aptly repository (optionnal).

The implementation for the installation on other operating systems has not been done yet but should be pretty straightforward to do. Just ask which one you want and we'll add it or submit a pull request on our github page and we'll integrate it.

Development

We're actually nice people and we rarely bite, so you're more than welcome to contribute to our repos via the usual GitHub PR and issues.

What we ask generally is that when you push a change or a new functionnality, you add the corresponding tests at the same time. You'll find a lot of tests examples in this repository.

See the CONTRIBUTING.md file for more detailed guidelines.

puppet-aptly's People

Contributors

aerostitch avatar darkling avatar dhoppe avatar mindriot88 avatar mmogylenko avatar orieg avatar pryz avatar rhoml avatar slauger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

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

puppet-aptly's Issues

Release module

Can we create a new release of the module in puppet forge?

Use action show instead of list

For example the command aptly publish -raw=true list contains the distribution, not the name. Please rewrite all the cli.rb to use aptly publish show resource[:name] instead or you will get error messages like:

Error: Execution of 'aptly  publish repo dhoppe' returned 1: ERROR: prefix/distribution already used by another published repo: ./jessie [] publishes {main: [dhoppe]}

This happens, because the exists? function does not recognize the already published repository.

Puppet-lint Warning and Errors

Need to clean-up warning reported by puppet-lint:

WARNING: top-scope variable being used without an explicit namespace on line 115
WARNING: top-scope variable being used without an explicit namespace on line 116
WARNING: top-scope variable being used without an explicit namespace on line 117
WARNING: quoted boolean value found on line 103
WARNING: quoted boolean value found on line 104
WARNING: quoted boolean value found on line 105
WARNING: quoted boolean value found on line 106
WARNING: quoted boolean value found on line 107
WARNING: quoted boolean value found on line 108
WARNING: quoted boolean value found on line 109
WARNING: string containing only a variable on line 69

adding mirror for puppetlabs-pc1

Hi There,
I'm attempting to mirror the puppet4 AIO repo. below is my config:
class { 'aptly':
root_dir => '/srv/aptly/',
architectures => ['i386', 'amd64'],
ppa_codename => 'foo',
}

aptly::mirror { 'puppetlabs_pc1_jessie':
location => 'http://apt.puppetlabs.com',
distribution => 'jessie',
components => ['PC1'],
# architectures => ['amd64', 'i386'],
}
puppet runs successfully:
puppet agent --test
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Info: Caching catalog for aptly.fs.uwaterloo.ca
Info: Applying configuration version '1495042227'
Info: Creating Aptly Mirror puppetlabs_pc1_jessie
Info: Updating Aptly Mirror puppetlabs_pc1_jessie
Notice: /Stage[main]/Profile::Aptly/Aptly::Mirror[puppetlabs_pc1_jessie]/Aptly_mirror[puppetlabs_pc1_jessie]/ensure: created
Notice: Applied catalog in 1.44 seconds

However, when running

$ aptly mirror list

on the host, it claims no mirrors are found.

here's the aptly db log:
=============== May 17, 2017 (EDT) ===============
13:34:50.524939 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
13:34:50.525150 version@stat F·[] S·0B[] Sc·[]
13:34:50.525159 db@open opening
13:34:50.525194 journal@recovery F·1
13:34:50.525518 journal@recovery recovering @22
13:34:50.526885 version@stat F·[] S·0B[] Sc·[]
13:34:50.527270 db@janitor F·2 G·0
13:34:50.527292 db@open done T·2.123626ms
13:34:50.527342 db@close closing
13:34:50.528323 db@close done T·980.108µs
=============== May 17, 2017 (EDT) ===============
13:35:44.000241 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
13:35:44.000375 version@stat F·[] S·0B[] Sc·[]
13:35:44.000382 db@open opening
13:35:44.000411 journal@recovery F·1
13:35:44.000771 journal@recovery recovering @24
13:35:44.002153 version@stat F·[] S·0B[] Sc·[]
13:35:44.002463 db@janitor F·2 G·0
13:35:44.002493 db@open done T·2.09363ms
13:35:44.002533 db@close closing
13:35:44.003540 db@close done T·998.58µs
=============== May 17, 2017 (EDT) ===============
13:35:44.118859 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
13:35:44.118958 version@stat F·[] S·0B[] Sc·[]
13:35:44.118965 db@open opening
13:35:44.118993 journal@recovery F·1
13:35:44.119251 journal@recovery recovering @26
13:35:44.120549 version@stat F·[] S·0B[] Sc·[]
13:35:44.120818 db@janitor F·2 G·0
13:35:44.120841 db@open done T·1.868292ms
13:35:44.120893 db@close closing
13:35:44.121985 db@close done T·1.089975ms

Any ideas as to what I'm doing wrong?

aptly commands break in wrong directory

Affected Puppet, Ruby, OS and module versions/distributions

  • Puppet: All
  • Ruby: All
  • Distribution: All
  • Module version: Current master (probably olders as well)

How to reproduce (e.g Puppet code you use)

Run puppet apply -e "aptly::repo { 'testing': }" in /root.

What are you seeing

Puppet tries to recreate the Aptly repository on each run. This is done because aptly -raw=true repo list tries to auto detect the configuration file and this breaks due to insufficient read privileges to /root/.aptly.conf.

https://github.com/aptly-dev/aptly/blob/a64807efdaf5e380bfa878c71bc88eae10d62be1/context/context.go#L92

The reason for is because Puppet switches the UID/GID for this command to 450 (aptly) which obviously has no permission to read /root.

root@stage-packages-api:~# cat test.rb
#!/opt/puppetlabs/puppet/bin/ruby

require 'puppet'

puts Puppet::Util::Execution.execute('aptly -raw=true repo list', uid: 450, gid: 450)
root@stage-packages-api:~# ./test.rb

root@stage-packages-api:~#

What behaviour did you expect instead

Works as expected.

Output log

Any additional information you'd like to impart

I see two options to fix this:

  1. Change $HOME to /home/aptly
root@stage-packages-api:~# cat ./test.rb
#!/opt/puppetlabs/puppet/bin/ruby

require 'puppet'

puts Puppet::Util::Execution.execute('aptly -raw=true repo list', uid: 450, gid: 450, custom_environment: { 'HOME': '/home/aptly' })
root@stage-packages-api:~# ./test.rb
testing
  1. Add -config $config_filepath
root@stage-packages-api:~# cat ./test.rb
#!/opt/puppetlabs/puppet/bin/ruby

require 'puppet'

puts Puppet::Util::Execution.execute('aptly -raw=true repo list -config /etc/aptly.conf', uid: 450, gid: 450)
root@stage-packages-api:~# ./test.rb
testing

Unable to install aptly on Ubuntu 16.04

When I try to use this module, I get the following error when running puppet apply:

Error: Execution of '/usr/bin/apt-get -q -y -o DPkg::Options::=--force-confold install aptly' returned 100: Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
  aptly
0 upgraded, 1 newly installed, 0 to remove and 62 not upgraded.
Need to get 6420 kB of archives.
After this operation, 22.6 MB of additional disk space will be used.
WARNING: The following packages cannot be authenticated!
  aptly
E: There were unauthenticated packages and -y was used without --allow-unauthenticated
Error: /Stage[main]/Aptly::Install/Package[aptly]/ensure: change from purged to present failed: Execution of '/usr/bin/apt-get -q -y -o DPkg::Options::=--force-confold install aptly' returned 100: Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
  aptly
0 upgraded, 1 newly installed, 0 to remove and 62 not upgraded.
Need to get 6420 kB of archives.
After this operation, 22.6 MB of additional disk space will be used.
WARNING: The following packages cannot be authenticated!
  aptly
E: There were unauthenticated packages and -y was used without --allow-unauthenticated

It's like apt-get update isn't getting run? I'm not sure why this is happening. My manifest is copy-pasta'd from the readme:

class aptly-config() {
  class { 'aptly':
    root_dir      => '/mirror',
    architectures => ['amd64']
  }

  aptly::mirror { 'debian_stable':
    location      => 'http://ftp.us.debian.org/debian/',
    distribution  => 'stable',
    components    => [ 'main'] ,
    architectures => ['amd64'],
  }

  exec { 'debian_stable_key_8B48AD6246925553':
    command => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --keyserver keys.gnupg.net --recv-key 8B48AD6246925553',
    unless  => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --list-key 8B48AD6246925553 > /dev/null 2>&1',
  }

  exec { 'debian_stable_key_7638D0442B90D010':
    command => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --keyserver keys.gnupg.net --recv-key 7638D0442B90D010',
    unless  => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --list-key 7638D0442B90D010 > /dev/null 2>&1',
  }

  exec { 'debian_stable_key_CBF8D6FD518E17E1':
    command => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --keyserver keys.gnupg.net --recv-key CBF8D6FD518E17E1',
    unless  => '/usr/bin/gpg --no-default-keyring --keyring trustedkeys.gpg --list-key CBF8D6FD518E17E1 > /dev/null 2>&1',
  }


  Exec['debian_stable_key_8B48AD6246925553']->
  Exec['debian_stable_key_7638D0442B90D010']->
  Exec['debian_stable_key_CBF8D6FD518E17E1']->
  Aptly::Mirror['debian_stable']

}

Embed the defines inside the init.pp

To have a full integration and help to avoid re-declaring some of the variables, declaring the defines based on some hash directly inside the init.pp would be nice.

Release new version/process pull request

Hello,

I would like to know if there are any plans to release new versions or if you guys want to process the pull requests?

This module does officially only support:

  • Puppet >= 3.0.0 < 5.0.0
  • Debian: 8
  • Ubuntu: 14.04, 16.04

But there has been progress within Puppet and the OSes.

Can you offer some informations about future plans?

Create repos via hiera.

I'd like to have all of my aptly configuration be done by hiera, as such, I'd like to be able to create repos/mirrors via hiera hashes.

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.