Coder Social home page Coder Social logo

deislabs / hippo Goto Github PK

View Code? Open in Web Editor NEW
414.0 14.0 38.0 5.63 MB

The WebAssembly Platform

Home Page: https://docs.hippofactory.dev

License: Other

C# 47.10% Dockerfile 0.20% Shell 0.49% JavaScript 0.23% TypeScript 47.13% HTML 4.76% CSS 0.08% SCSS 0.01%

hippo's Introduction

Hippo, the WebAssembly PaaS

Hippo is the easiest way to deploy and serve applications compiled to WebAssembly.

WARNING: This is experimental code. It is not considered production-grade by its developers, nor is it "supported" software.

DeisLabs is experimenting with many WASM technologies right now. This is one of a multitude of projects (including Krustlet) designed to test the limits of WebAssembly as a cloud-based runtime.

Hippo takes a fresh spin on the PaaS ecosystem, taking advantage of the technology WebAssembly brings to the space.

Hippo works like this: A WebAssembly package is bundled up as a bindle. Bindles are collected together in a bindle server that you can search. Hippo uses bindle under the hood for storing and organizing applications.

Using the hippo command line interface, you can upload new releases or prepare a bindle for local development. In the future, you can use this CLI to create applications, configure channels, gather logs, attach TLS certificates, and other commands you’d expect to use with a PaaS.

Hippo provides a web interface for users to register new accounts, access their applications, and create new environments for testing.

Hippo makes it easy to run WebAssembly applications and services at scale.

Documentation

If you're new to the project, get started with the introduction. For more in-depth information about Hippo, plunge right into the topic guides.

Looking for the developer guide? Start here.

Community, discussion, contribution, and support

Right now, all community discussion takes place here at the project homepage. If you have a question about the project or want to start a discussion, search for existing topics or open a new topic.

Code of Conduct

This project has adopted the Microsoft Open Source Code of Conduct.

For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

hippo's People

Contributors

adamreese avatar alexandradumitru22 avatar bacongobbler avatar dependabot[bot] avatar flynnduism avatar gogeterobert avatar itowlson avatar jpflueger avatar kate-goldenring avatar lann avatar michellen avatar nitishm avatar npcristian avatar simongdavies avatar stefannedelcu avatar thangchung avatar vdice 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

hippo's Issues

bug: traefik config file not written as expected

Expected output of a deploy:

[http]
  [http.routers]
     [http.routers.to-helloworld-development]
      rule = "Host(`development.hippos.rocks`) && PathPrefix(`/`)"
      service = "helloworld-development"

  [http.services]
    [http.services.helloworld-development.loadBalancer]
      [[http.services.helloworld-development.loadBalancer.servers]]
        url = "http://127.0.0.1:32768"

Current output:

"http"

update WAGI config after adding a new Domain/Certificate

Right now, the WAGI configuration file is only updated when a Release is deployed. Instead, we should inject new domains/certificates into the config file and call systemctl reload on the unit so it picks up on the new serving domain.

Auto start can give confusing error

With #60, the WAGI scheduler now starts all seeded channels at startup (rather than only after the channel has been reconfigured). This fails with unhandled exception spew if wagi is not on the PATH and the HIPPO_WAGI_PATH EV has not been set.

It should give a meaningful error. Optionally, there could also be a way to tell it not to start channels until after they have been explicitly configured.

Support prerelease version rules

yo wasm currently sets up the Development channel as *, which matches the highest version but does not match pre-release versions. This means users have to manually update HIPPOFACTS on every push, and to pass -v production to Hippofactory. We need to provide a way to specify pre-release versions.

Longer term, it would be desirable to provide rule syntax that would allow per-user filtering. Scenarios I am thinking of are:

  • All Ivan all the time: latest revision with my username on it
  • Trunk on GitHub: latest revision with the user name canary
  • Previous version hotfix tracking: latest revision with number 1.1.3 and user name canary

Hippofactory's syntax is currently -user-yyyy.mm.dd.hh.mm.ss.fff but can change according to whatever is easiest for Hippo to implement.

implement user permissions

As the administrator of an application, I'd like to invite users to collaborate on my app. I'd also like to restrict their permissions to a subgroup of roles. e.g. I only want developers access to upload new builds, domains, certificates, and modify configuration, but be unable to modify domains or certificates I created.

django-guardian is already integrated into the project. We just need to write a few views that give users the correct permissions.

hippo/apps/views.py

Lines 30 to 32 in 04a7c9b

assign_perm('view_app', self.request.user, self.object)
assign_perm('change_app', self.request.user, self.object)
assign_perm('delete_app', self.request.user, self.object)

Need docs on getting started

I want to be able to clone the repo and run the solution, however so far:

dotnet run produces:

Building...
crit: Microsoft.AspNetCore.Hosting.Diagnostics[6]
      Application startup exception
      System.ComponentModel.Win32Exception (2): The system cannot find the file specified.
         at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
         at System.Diagnostics.Process.Start()
         at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
         at Hippo.Schedulers.WagiLocalJobScheduler.Start(Channel c) in C:\Users\sdavies\source\repos\hippo\Hippo\Schedulers\WagiLocalJobScheduler.cs:line 51
         at Hippo.Schedulers.WagiLocalJobScheduler.OnSchedulerStart(IEnumerable`1 applications) in C:\Users\sdavies\source\repos\hippo\Hippo\Schedulers\WagiLocalJobScheduler.cs:line 32
         at Hippo.Startup.Configure(IApplicationBuilder app, IServiceProvider serviceProvider) in C:\Users\sdavies\source\repos\hippo\Hippo\Startup.cs:line 136
         at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
         at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
         at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
         at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
         at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)
         at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
         at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
         at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
Unhandled exception. System.ComponentModel.Win32Exception (2): The system cannot find the file specified.
   at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
   at System.Diagnostics.Process.Start()
   at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
   at Hippo.Schedulers.WagiLocalJobScheduler.Start(Channel c) in C:\Users\sdavies\source\repos\hippo\Hippo\Schedulers\WagiLocalJobScheduler.cs:line 51
   at Hippo.Schedulers.WagiLocalJobScheduler.OnSchedulerStart(IEnumerable`1 applications) in C:\Users\sdavies\source\repos\hippo\Hippo\Schedulers\WagiLocalJobScheduler.cs:line 32
   at Hippo.Startup.Configure(IApplicationBuilder app, IServiceProvider serviceProvider) in C:\Users\sdavies\source\repos\hippo\Hippo\Startup.cs:line 136
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
   at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)
   at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
   at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at Hippo.Program.Main(String[] args) in C:\Users\sdavies\source\repos\hippo\Hippo\Program.cs:line 10

Once I fix that by cloning and building wagi and setting env var HIPPO_WAGI_PATH I now get:

dotnet run
Building...
error: The argument '--bindle-server <BINDLE_SERVER_URL>' requires a value but none was supplied

USAGE:
    wagi --bindle <bindle> --bindle-server <BINDLE_SERVER_URL> --default-host <HOSTNAME> --listen <IP_PORT>

For more information try --help
error: The argument '--bindle-server <BINDLE_SERVER_URL>' requires a value but none was supplied

USAGE:
    wagi --bindle <bindle> --bindle-server <BINDLE_SERVER_URL> --default-host <HOSTNAME> --listen <IP_PORT>

For more information try --help
error: The argument '--bindle-server <BINDLE_SERVER_URL>' requires a value but none was supplied

USAGE:
    wagi --bindle <bindle> --bindle-server <BINDLE_SERVER_URL> --default-host <HOSTNAME> --listen <IP_PORT>

For more information try --help
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/simon/github/simongdavies/hippo/Hippo

Looks like I need to install/point at a bindle server .

On windows once I set the PATH and the URL ( $env:BINDLE_SERVER_URL="https://bindle.deislabs.io") I now get:

Building...
[2021-06-14T12:54:32Z INFO  wagi] => Starting server on 127.0.0.1:32768
[2021-06-14T12:54:32Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.1.0
[2021-06-14T12:54:32Z INFO  wagi] => Starting server on 127.0.0.1:32769
[2021-06-14T12:54:32Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.0.0
[2021-06-14T12:54:32Z INFO  wagi] => Starting server on 127.0.0.1:32770
[2021-06-14T12:54:32Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.1.0
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\Users\sdavies\source\repos\hippo\Hippo
Error: Failed to load bindle hippos.rocks/helloworld/1.1.0: Failed to turn Bindle into module configuration: Invoice was not found
Error: Failed to load bindle hippos.rocks/helloworld/1.0.0: Failed to turn Bindle into module configuration: Invoice was not found
Error: Failed to load bindle hippos.rocks/helloworld/1.1.0: Failed to turn Bindle into module configuration: Invoice was not found

If I use WSL I get:

Building...
[2021-06-14T12:03:11Z INFO  wagi] => Starting server on 127.0.0.1:32768
[2021-06-14T12:03:11Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.1.0
[2021-06-14T12:03:11Z INFO  wagi] => Starting server on 127.0.0.1:32769
[2021-06-14T12:03:11Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.0.0
[2021-06-14T12:03:11Z INFO  wagi] => Starting server on 127.0.0.1:32770
[2021-06-14T12:03:11Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.1.0
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/simon/github/simongdavies/hippo/Hippo
Error: Failed to load bindle hippos.rocks/helloworld/1.1.0: Failed to turn Bindle into module configuration: Error creating request: reqwest::Error { kind: Request, url: Url { scheme: "https", username: "", password: None, host: Some(Domain("bindle.deislabs.io")), port: None, path: "/_i/hippos.rocks/helloworld/1.1.0", query: None, fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 337047686, library: "SSL routines", function: "tls_process_server_certificate", reason: "certificate verify failed", file: "../ssl/statem/statem_clnt.c", line: 1924 }]))) }, X509VerifyResult { code: 20, error: "unable to get local issuer certificate" })) }
Error: Failed to load bindle hippos.rocks/helloworld/1.0.0: Failed to turn Bindle into module configuration: Error creating request: reqwest::Error { kind: Request, url: Url { scheme: "https", username: "", password: None, host: Some(Domain("bindle.deislabs.io")), port: None, path: "/_i/hippos.rocks/helloworld/1.0.0", query: None, fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 337047686, library: "SSL routines", function: "tls_process_server_certificate", reason: "certificate verify failed", file: "../ssl/statem/statem_clnt.c", line: 1924 }]))) }, X509VerifyResult { code: 20, error: "unable to get local issuer certificate" })) }
Error: Failed to load bindle hippos.rocks/helloworld/1.1.0: Failed to turn Bindle into module configuration: Error creating request: reqwest::Error { kind: Request, url: Url { scheme: "https", username: "", password: None, host: Some(Domain("bindle.deislabs.io")), port: None, path: "/_i/hippos.rocks/helloworld/1.1.0", query: None, fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 337047686, library: "SSL routines", function: "tls_process_server_certificate", reason: "certificate verify failed", file: "../ssl/statem/statem_clnt.c", line: 1924 }]))) }, X509VerifyResult { code: 20, error: "unable to get local issuer certificate" })) }
info: Microsoft.Hosting.Lifetime[0]

Looks like the root cert for https://bindle.deislabs.io is not trusted on WSL (Ubuntu 18-04).

I added the letsencrypt root cert as follows:

cd /usr/share/ca-certificates/
sudo mkdir letsencrypt.org
cd  letsencrypt.org
sudo curl -o isrgrootx1.crt  "https://letsencrypt.org/certs/isrgrootx1.pem"
sudo dpkg-reconfigure ca-certificates

I then selected the letsencrypt cert for activation in the UI and then ran:

sudo  update-ca-certificates

No when I run dotnet run I see:

Building...
[2021-06-14T13:27:36Z INFO  wagi] => Starting server on 127.0.0.1:32768
[2021-06-14T13:27:36Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.1.0
[2021-06-14T13:27:36Z INFO  wagi] => Starting server on 127.0.0.1:32770
[2021-06-14T13:27:36Z INFO  wagi] => Starting server on 127.0.0.1:32769
[2021-06-14T13:27:36Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.1.0
[2021-06-14T13:27:36Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.0.0
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/simon/github/simongdavies/hippo/Hippo
Error: Error: Failed to load bindle hippos.rocks/helloworld/1.1.0: Failed to turn Bindle into module configuration: Error creating request: reqwest::Error { kind: Request, url: Url { scheme: "https", username: "", password: None, host: Some(Domain("bindle.deislabs.io")), port: None, path: "/_i/hippos.rocks/helloworld/1.1.0", query: None, fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 337047686, library: "SSL routines", function: "tls_process_server_certificate", reason: "certificate verify failed", file: "../ssl/statem/statem_clnt.c", line: 1924 }]))) }, X509VerifyResult { code: 20, error: "unable to get local issuer certificate" })) }Failed to load bindle hippos.rocks/helloworld/1.0.0: Failed to turn Bindle into module configuration: Error creating request: reqwest::Error { kind: Request, url: Url { scheme: "https", username: "", password: None, host: Some(Domain("bindle.deislabs.io")), port: None, path: "/_i/hippos.rocks/helloworld/1.0.0", query: None, fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 337047686, library: "SSL routines", function: "tls_process_server_certificate", reason: "certificate verify failed", file: "../ssl/statem/statem_clnt.c", line: 1924 }]))) }, X509VerifyResult { code: 20, error: "unable to get local issuer certificate" })) }

Error: Failed to load bindle hippos.rocks/helloworld/1.1.0: Failed to turn Bindle into module configuration: Error creating request: reqwest::Error { kind: Request, url: Url { scheme: "https", username: "", password: None, host: Some(Domain("bindle.deislabs.io")), port: None, path: "/_i/hippos.rocks/helloworld/1.1.0", query: None, fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 337047686, library: "SSL routines", function: "tls_process_server_certificate", reason: "certificate verify failed", file: "../ssl/statem/statem_clnt.c", line: 1924 }]))) }, X509VerifyResult { code: 20, error: "unable to get local issuer certificate" })) }

I then added the lets-encrypt intermediate certs:

sudo curl -o lets-encrypt-r3.crt  https://letsencrypt.org/certs/lets-encrypt-r3.pem
sudo dpkg-reconfigure ca-certificates
sudo  update-ca-certificates

Now I see (same as in windows):

Building...
[2021-06-14T13:33:02Z INFO  wagi] => Starting server on 127.0.0.1:32768
[2021-06-14T13:33:02Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.1.0
[2021-06-14T13:33:02Z INFO  wagi] => Starting server on 127.0.0.1:32769
[2021-06-14T13:33:02Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.0.0
[2021-06-14T13:33:02Z INFO  wagi] => Starting server on 127.0.0.1:32770
[2021-06-14T13:33:02Z TRACE wagi] Loading bindle hippos.rocks/helloworld/1.1.0
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/simon/github/simongdavies/hippo/Hippo
Error: Failed to load bindle hippos.rocks/helloworld/1.1.0: Failed to turn Bindle into module configuration: Invoice was not found
Error: Failed to load bindle hippos.rocks/helloworld/1.0.0: Failed to turn Bindle into module configuration: Invoice was not found
Error: Failed to load bindle hippos.rocks/helloworld/1.1.0: Failed to turn Bindle into module configuration: Invoice was not found

For completeness I also tried this on macos and once I set the environment vars I see the same error.

Upload WebAssembly modules to bindle

As an administrator, I would like to make certain modules available to the system to be provisioned as an application. The workflow should allow the administrator to upload their modules through a web form. Once uploaded, it will be signed with the administrator's key and uploaded to bindle.

app summary page

A node summary page should provide overall health of the application. Things like

  • RAM usage
  • CPU usage
  • hard drive space used/available
  • CPU information
  • Kernel version
  • service daemon versions (WAGI)

Discussion: file upload workflows

Hippo is a platform where users can deploy and serve applications written in WASM. The presumed framework for application authoring is WAGI; the tentative assumption is that applications are stored in a Bindle repository. An application may require assets over and above the WASM binaries, such as images or stylesheets. We need to define how Hippo thinks about the assets that make up an application, how it stores them, and how users upload and manage them in the user interface.

The current assumption is that at the database level a Build will simply refer to a Bindle URL; it should not have to care how the assets got into Bindle.

There are two key workflows to consider:

  1. Production (including staging, gradual rollout and other 'controlled' phases of deployment) - when a set of source artifacts has been committed to version control, and has been blessed to go forth.
  2. Development - when a developer is working on a fix or feature and wants to make sure it works correctly on the Hippo platform.

Production

The production workflow is fairly simple. The project can have a CI workflow (such as a GitHub action) which uploads the assets (parcels and invoice) to the Bindle server and then creates a Hippo application build that references the Bindle URI. We can scaffold the GitHub action using yo wasm.

The main issue here is knowing which files to include in the bindle. This is also an issue for the developer workflow and we'll come back to it.

Development

The development workflow is trickier. It needs to be:

  • Fast enough not to be interfere with the inner loop
  • Repeatable enough not to be error-prone
  • Simple enough not to interrupt flow

What we don't want:

  • Having to manually upload potentially dozens of files, and assemble them into a bindle, every time they do a test build. (This doesn't mean upload by hand shouldn't be an option. But it shouldn't be the only way.)
  • Having to push to GitHub on every tweak you want to test.

Perhaps the ideal UI for this is more like the old Visual Studio “Publish” command, which built your Web application and deployed it to a server. This was integrated into the development environment, and did not require a commit or any per-publish configuration. But Visual Studio knew what ASP.NET applications looked like; we don't know how to build user apps or how they're laid out.

QUESTION: Could we mandate the layout and build structures e.g. assets must be under X directory, modules must be under Y directory, building must be via a make build command? Some of this could be hostile to environments that have their own conventions and tools.

Suppose we have a bill of materials that tells us what assets are needed in an application build. Then we can consider three stages:

  1. Build the modules (and any non-module assets such as Sass -> CSS) - this is language-specific.
  2. Publish the assets as a bindle. This will do much the same as the GitHub action – we could drive it off many of the same tools.
  3. Create a Hippo build that refers to the bindle – this is the same as in CI.

A VS Code Publish task could combine those three stages, and could be scaffolded by yo wasm just as the current Build Wasm task is. The BOM could also be used in the GitHub action rather than the user having to maintain that separately.

This does have the implication that every test build gets pushed to a Bindle server, and since Bindle servers are never allowed to delete anything, this could lead to unwanted cruft. It could also make the versioning process tedious for a developer performing a rapid iteration. But we don’t want Hippo to have to maintain a parallel object storage mechanism.

QUESTION: Should we lobby Bindle to support a "dev mode" in which bindles can be overwritten or deleted? If not, should Hippo provide temporary, disposable Bindle servers for dev builds?

What might a BOM-based workflow look like

Imagine, then, that we define a HIPPOFACTS file (short for Hippo artifacts, roughly similar to a Dockerfile, but by convention would also include interesting facts about hippos). This could contain glob patterns for all the assets constituting the application bindle:

# HIPPO FACT: The closest living relatives of hippos are whales and dolphins
[invoice]
package/invoice.toml
[parcels]
modules.toml
out/todo-app.wasm
images/*
styles/*

Or it could be a bastardised invoice.toml but with things like parcel sizes left off, and permitting globs in place of names (that would be expanded in the generated invoice), and with wildcard versioning (so a user could keep redeploying and we would just add incrementing patch number or +timestamp or something), etc.

In either case, the HIPPOFACTS file could be scaffolded by yo wasm, but would have to be maintained by the user.

Then the Hippo deployment workflow would be

  • Build from source
  • Run a bindle publishing tool that read HIPPOFACTS and uploaded the invoice and parcels
  • Create a Hippo build object pointing to the created bindle
  • Profit Test

This could be encapsulated by a VS Code task for dev and a GitHub action for production; both could be scaffolded by yo wasm.

Authorisation considerations

This workflow assumes the user has permission to upload directly to the Bindle server. This may be considered undesirable; the PaaS operator may want to gate all uploads through Hippo to verify that the user has permission to upload builds for this project. This could be addressed by having the publish tool send a tarball to Hippo which it authorises, unpacks, and validates, and then creates the bindle itself.

We need to understand and capture the usage scenarios and requirements around this.

UI file management

What does this mean in terms of Hippo UI file management requirements? It means probably the only case we have left is the super simple “one or two files”. For this, we can synthesise a bindle with the uploaded modules as the only parcels, with bindle name and version inferred from the build. This would be of limited use for all but the simplest one-off configurations though – hello world, spiking out ideas, etc.

Prioritisation

How we prioritise this probably depends on our demo cases. We could get something ultra-simple going in the UI, but having only that could limit what we do in our demos (because you would not want to show more than a very few files). I feel we are better off prioritising a tool-based approach if we have resources, but it's likely to be more effort than a quick web upload form!

needs to run as superuser in most scenarios

In test/development scenarios, Hippo should write systemd services and traefik config files to a scratch directory and "pretend" that a new release has been deployed. That way as developers we can test the web API and the UX without worrying about the end-to-end experience.

discussion: should a channel be able to bind to multiple domains?

Here's my current train of thought... Let's assume I have an application with the following releases available:

  • 1.0.0
  • 1.1.0
  • 2.0.0
  • 2.0.1
  • 2.0.2
  • 2.1.0
  • 2.1.1
  • 2.2.0-rc.1

As an application operator, I would like to have the following URLs pointing at my application:

  • hippos.rocks
  • dev.hippos.rocks
  • nightly.hippos.rocks
  • v1.hippos.rocks

hippos.rocks is the "stable" channel. It's configured to deploy the latest stable release of the application. (~2.0.0 -> 2.0.2)

dev is the "development" channel. It's configured to deploy the latest release of the application. (^2.0.0 -> 2.1.1)

nightly is the "testing" channel. It's configured to deploy the most recently released of the application, including pre-releases (*-* -> 2.2.0-rc.1)

v1 is an "archived" site, deploying the latest v1 release. (^1.0.0 -> 1.1.0)

Is there a case I'm missing where there may be a channel that needs to point to two domains at once?

Add an API for creating a new application

For the yo wasm -> HF -> It Just Works workflow to be seamless, we need a way to create a Hippo application and the scaffold for that application together.

There are two ways to approach this:

  1. Hippo UI first: When you create an application in Hippo it can provide you with instructions (or even a script/config file?) for installing and running yo wasm to scaffold code that is associated with the application.

  2. yo wasm first: When you scaffold a project in yo wasm and choose the Hippo publish option, it could ask you if you want to create a Hippo application and connect it up to your new project.

We are currently reckoning on doing option 2 (at least as the first step). For this to work we need an API along the following lines:

Request:

  • A friendly name for the application
  • The bindle name for the application (i.e. the bit to which versions get appended, e.g. hippos.rocks/weather)
  • The owner of the new application (probably implicitly derived from the auth, however we do auth)

Response:

  • The application GUID

yo wasm will want to immediately create a 'Development' channel for the new application, but we should probably make that a separate API.

add logs view

A user should be able to view all aggregated logs from their application via an endpoint. Similar to other platforms like heroku logs.

This tracks the work to be done on the UI side after #610 has been implemented.

trigger an automatic Release after a build is added or an environment variable is added/changed/removed

Right now, Releases are manually created with a foreign key reference to a Build. Instead, when an EnvironmentVariable is added, removed, or updated, and similarly when a new Build is uploaded, a new Release should be created automatically.

This follows the 12-factor mantra where a Build + Config = Release.

When adding a new environment variable, there should be a check for there being a Build object present before triggering a Release. If none is present, no Release should be created (no Build = no Release).

Add an API for creating a new channel

#57 describes the context of creating "just enough" Hippo and code together to get a new developer up and running, and proposes an API for creating an application. For publishing, the new application also needs a channel. We decouple these operations so that clients can control channel creation to behave differently from yo wasm if they want to.

So we need a separate API to create a channel as follows:

Request:

  • The GUID of the application to which the channel belongs
  • A friendly name for the channel
  • Whether the channel should be locked to a specific revision, or automatically adopt new revisions based on a rule
  • The specific revision to lock to, or the range rule, depending on the previous value
  • TBD if we need to allow setup of domain and configuration via the API - can be omitted on day 1

Response:

  • The GUID of the newly created channel
  • TBD if we should return any other info, e.g. the assigned port or the initially active revision

Hippo model transformations

After yesterday's stargazing meeting, we thought of a few new concepts:

  • a channel is bound to a domain, a release (build), and some configuration.
  • channels automatically roll forward depending on the configured semantic version constraint (do we trigger a release every time a new minor/patch/major release?)
  • a snapshot, which contains a "point-in-time" release of a channel. This would allow an administrator the ability to roll back to a prior state.

refactor: use the Repository pattern for fetching entities

There is an opportunity to DRY up some code in AppController. Right now each request tries to lookup applications owned by the user who is signed in using the DataContext. We could abstract this away in an AppRepository to clean up some of this code.

var a = context.Applications.Where(application=>application.Id==id && application.Owner.UserName==User.Identity.Name).SingleOrDefault();

https://social.technet.microsoft.com/wiki/contents/articles/36287.repository-pattern-in-asp-net-core.aspx

WagiLocalJobScheduler does not check to see if Wagi started properly

To reproduce do not set environment variable BINDLE_SERVER_URL and then run dotnet run:

Building...
error: The argument '--bindle-server <BINDLE_SERVER_URL>' requires a value but none was supplied

USAGE:
    wagi --bindle <bindle> --bindle-server <BINDLE_SERVER_URL> --default-host <HOSTNAME> --listen <IP_PORT>

For more information try --help
error: The argument '--bindle-server <BINDLE_SERVER_URL>' requires a value but none was supplied

USAGE:
    wagi --bindle <bindle> --bindle-server <BINDLE_SERVER_URL> --default-host <HOSTNAME> --listen <IP_PORT>

For more information try --help
error: The argument '--bindle-server <BINDLE_SERVER_URL>' requires a value but none was supplied

USAGE:
    wagi --bindle <bindle> --bindle-server <BINDLE_SERVER_URL> --default-host <HOSTNAME> --listen <IP_PORT>

For more information try --help
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/simon/github/simongdavies/hippo/Hippo
info: Microsoft.Hosting.Lifetime[0]

provide a shell terminal

As an administrator, I should be able to use a remote shell to run some commands on the host to run simple operations such as:

  • apt update && apt upgrade (or apt dist-upgrade)
  • update the WASI runtime
  • change DNS, time, hostname, locale, etc.
  • change, add or remove VLANs/network bridges
  • update firewall permissions
  • fix postfix

noVNC, SPICE, or xterm.js are all good options to consider here.

As an Application owner, I can set up snapshots for each channel

As an Application owner, I should be able to create snapshots of a channel's current state. It should contain everything required to "roll back" to the channel's state at that point in time.

public class ChannelSnapshot: Channel
{
}

When a snapshot is applied, the "auto-deploy" option for the Channel should be disabled.

This would be useful when I've deployed a few revisions to the channel and I want to roll back to a deployment from a few hours ago.

cluster status page

the cluster status view should provide information about Hippo's overall health. Things like:

  • status of all Hippo services (bindle, postgres, mail server)
  • status of the Job Scheduler (is it healthy? how long has it been running? what is its current capacity levels?)
  • status of last backups (did they succeed? When was the last backup? When is the next one scheduled?)
  • cluster-wide available resources (#298)
  • status of all apps (compressed version of #16 - how many running? How many are stopped?)

create a CLI

There should be a command-line interface that can interact with the API. That way, users can integrate hippo into their CI pipelines.

Basic workflow:

$ hippo accounts register https://my.hippo.local
username: admin
password:
password (confirm):
Registered admin
Logged in as admin
$ hippo apps create
name: myapp
Creating myapp... done
$ hippo channels add staging
domain: staging.hippos.dev
Adding channel staging to myapp... done
$ hippo releases add mybindle.bundle --as 1.0.0-rc.1
Deploying myapp 1.0.0-rc.1... done
$ curl https://staging.hippos.dev
Powered by Hippo

implement group permissions

As an administrator of hippo, I'd like to create access groups and invite users to that group. Any member of that group should be able to create new applications under the group name. I should be able to make applications created under that group public (anyone can view) or private (must be logged in to view and/or make changes)

replace Channel.VersionRange comparator with a Semver range comparaator

Right now we're using a NuGet version range comparator. Same functionality, different syntax.

var filter = VersionRange.Parse(c.VersionRange);
// find the latest version that satisfies the filter.
foreach (Release r in a.Releases.OrderBy(r => r.Revision))
{
if (filter.Satisfies(NuGetVersion.Parse(r.Revision)))
{
c.UnPublish();
c.Release = r;
c.Publish();
}

https://github.com/Masterminds/semver is what we've used in past projects.

Also in this case it appears we're ordering by string comparison rather than actual NuGet version comparison. We should fix that.

foreach (Release r in a.Releases.OrderBy(r => r.Revision))

Scheduled database/bindle backups

As an administrator, I would like to perform scheduled backups to a location so that I can delete and restore the state of my cluster.

This includes:

  • backups of the database
  • bindle backups

add CI

depends on #1. This project should be tested on every pull request and merge to main.

Implement a nomad job scheduler

What we are thinking is that Hippo would send a Job definition to Nomad, and Nomad would schedule it to WAGI. That would mean we'll need a regular Nomad driver that can submit jobs.

For the future dashboard work (#17 #16 #9), we’ll probably have to do some fancier querying of the Nomad API.

GET /apps should return collaborating apps

The Apps entity has a field called Collaborators:

public virtual ICollection<Account> Collaborators { get; set; }

As a user, I should be able to see any applications I have been added to as a Collaborator. It's still unclear what permissions Collaborators should receive at this point, but read-only permissions should do for now.

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.