add rust registrry (#1072)

This commit is contained in:
中弈
2022-05-28 20:03:33 +08:00
committed by GitHub
parent c13958794c
commit 28cf2338da
14 changed files with 699 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "dashboard"
version = "0.1.0"
authors = ["fanux <fhtjob@hotmail.com>"]
edition = "2018"
[dependencies]
anyhow = "1"
serde = "1"
serde_derive = "1"
yew = "0.18"
yew-router = "0.15"
+84
View File
@@ -0,0 +1,84 @@
# Build the dashboard
```
cargo install trunk wasm-bindgen-cli
rustup target add wasm32-unknown-unknown
trunk serve
```
## init registry
```
docker run -p 5000:5000 -d --name registry registry:2.7.1
```
using nginx to proxy cors:
nginx.conf:
```
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
server {
listen 8000; #监听8000端口,可以改成其他端口
server_name localhost; # 当前服务的域名
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE' always;
add_header 'Access-Control-Allow-Headers' '*' always;
add_header 'Access-Control-Max-Age' 1728000 always;
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain; charset=utf-8';
return 204;
}
if ($request_method ~* '(GET|POST|DELETE|PUT)') {
add_header 'Access-Control-Allow-Origin' '*' always;
}
proxy_pass http://172.17.0.3:5000; # the registry IP or domain name
proxy_http_version 1.1;
}
}
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
```
```
docker run -d --name registry-proxy -p 8001:8000 \
-v /Users/fanghaitao/nginx/nginx.conf:/etc/nginx/nginx.conf nginx:1.19.0
```
Then you can test the registry api:
```
curl http://localhost:8001/v2/_catalog
{"repositories":["centos","golang"]}
```
+28
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<!--
Copyright © 2021 Alibaba Group Holding Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sealer Cloud</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
</head>
<body>
</body>
</html>
+14
View File
@@ -0,0 +1,14 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+88
View File
@@ -0,0 +1,88 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use yew::{html, Component,ComponentLink,Html,ShouldRender};
pub struct Header {
// props: Props,
}
pub enum Msg {}
impl Component for Header {
type Message = Msg;
type Properties = ();
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
Header {}
}
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
true
}
fn change(&mut self, props: Self::Properties) -> ShouldRender {
true
}
fn view(&self) -> Html {
html! {
<nav class="navbar is-primary block" role="navigation" aria-label="main navigation">
{ self.logo_name() }
{ self.search() }
{ self.login() }
</nav>
}
}
}
impl Header {
fn logo_name(&self) -> Html {
html! {
<div class="navbar-brand">
<div class="navbar-item">
<i class="far fa-cloud fa-2x fa-pull-left"></i>
<strong> { "Sealer Cloud" }</strong>
</div>
</div>
}
}
fn login(&self) -> Html {
html! {
<div class="navbar-end">
<div class="navbar-item">
<div class="botton" >
<i class="fab fa-github fa-2x"></i>
</div>
</div>
</div>
}
}
fn search(&self) -> Html {
html! {
<div class="nav-brand">
<div class="navbar-item">
<div class="control has-icons-left has-icons-right">
<input class="input is-success" type="text" placeholder="image name" value="" />
<span class="icon is-small is-left">
<i class="fas fa-search"></i>
</span>
</div>
</div>
</div>
}
}
}
+64
View File
@@ -0,0 +1,64 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use yew::{html, Component,ComponentLink,Html,ShouldRender,Properties};
pub struct ImageDetail{
props: Props,
}
#[derive(Properties, Clone)]
pub struct Props {
pub image_name: String,
}
pub enum Msg {}
impl Component for ImageDetail{
type Message = Msg;
type Properties = Props;
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
ImageDetail{
props,
}
}
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
true
}
fn change(&mut self, props: Self::Properties) -> ShouldRender {
true
}
fn view(&self) -> Html {
html! {
<div>
{ "this is image info" }
{ self.props.image_name.to_string() }
</div>
}
}
}
impl ImageDetail{
fn detail(&self) -> Html {
html! {
<div class="navbar-brand">
</div>
}
}
}
+207
View File
@@ -0,0 +1,207 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::routes::{router::Anchor, router::AppRoute};
use crate::services::requests::{Image, Images, RegistryCatalog};
use yew::services::ConsoleService;
use serde::Deserialize;
use yew::{
format::{Json, Nothing},
html,
services::fetch::{FetchService, FetchTask, Request, Response},
Component, ComponentLink, Html, ShouldRender,
};
#[derive(Debug)]
pub enum Msg {
GetRegistryCatelog(Result<RegistryCatalog, anyhow::Error>),
}
enum Class {
Provider,
Categories,
OperatingSystems,
Architectrues,
}
enum Label {
ThirdPart(Class, String),
Official(Class, String),
Analytics(Class, String),
ApplicationRuntime(Class, String),
BaseImages(Class, String),
Databases(Class, String),
DevOps(Class, String),
Messaging(Class, String),
Monitoring(Class, String),
OperatingSystem(Class, String),
Storage(Class, String),
Networking(Class, String),
Linux(Class, String),
Windows(Class, String),
ARM64(Class, String),
AMD64(Class, String),
}
impl Component for Images {
type Message = Msg;
type Properties = ();
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
ConsoleService::info("create app");
Self {
repos: None,
link,
error: None,
task: None,
}
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
use Msg::*;
match msg {
GetRegistryCatelog(response) => match response {
Ok(repos) => {
ConsoleService::info(&format!("info {:?}", repos));
self.repos = Some(repos.repositories);
}
Err(error) => {
ConsoleService::info(&format!("info {:?}", error.to_string()));
},
},
}
true
}
fn rendered(&mut self, first_render: bool) {
if first_render {
ConsoleService::info("view app");
let request = Request::get("http://localhost:8001/v2/_catalog")
.body(Nothing)
.expect("could not build request.");
let callback = self.link.callback(
|response: Response<Json<Result<RegistryCatalog, anyhow::Error>>>| {
let Json(data) = response.into_body();
Msg::GetRegistryCatelog(data)
},
);
let task = FetchService::fetch(request, callback).expect("failed to start request");
self.task = Some(task);
}
}
fn change(&mut self, props: Self::Properties) -> ShouldRender {
true
}
fn view(&self) -> Html {
html! {
<div>
<div class="columns is-multiline">
<div class="container column is-1">
{ self.filter() }
</div>
<div class="container column is-10">
{ self.image_list() }
</div>
</div>
</div>
}
}
fn destroy(&mut self) {}
}
impl Images {
fn filter(&self) -> Html {
html! {
<aside class="menu">
<p class="menu-label">
{ "Provider" }
</p>
<ul class="menu-list">
<li><a>{ "Official" }</a></li>
<li><a>{ "ThirdPart" }</a></li>
</ul>
<p class="menu-label">
{ "Categories" }
</p>
<ul class="menu-list">
<li><a>{ "BaseImage" }</a></li>
<li><a>{ "DataBases" }</a></li>
<li><a>{ "Messaging" }</a></li>
<li><a>{ "Monitoring" }</a></li>
</ul>
<p class="menu-label">
{ "Architecutures" }
</p>
<ul class="menu-list">
<li><a>{ "ARM64" }</a></li>
<li><a>{ "AMD64" }</a></li>
</ul>
</aside>
}
}
fn image_list(&self) -> Html {
match &self.repos {
Some(images) => {
html! {
<div class="columns is-multiline">
{
for images.iter().map(|image|{
self.image_info(image)
})
}
</div>
}
}
None => {
html! {
<p> {"image not found"} </p>
}
}
}
}
fn image_info(&self, image: &String) -> Html {
html! {
<div class="column is-6">
<div class="card">
<Anchor route=AppRoute::ImageDetail(image.to_string())>
<header class="card-header">
<p class="card-header-title">
{ image.to_string() }
</p>
<button class="card-header-icon" aria-label="more options">
<span class="icon">
<i class="fal fa-expand" aria-hidden="true"></i>
</span>
</button>
</header>
</Anchor>
<div class="card-content">
<div class="content">
{ "describe" }
<br />
<time datetime="2016-1-1">{ "11:09 PM - 1 Jan 2016" }</time>
</div>
</div>
</div>
</div>
}
}
}
+17
View File
@@ -0,0 +1,17 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod header;
pub mod image_list;
pub mod image_info;
+75
View File
@@ -0,0 +1,75 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod components;
pub mod routes;
pub mod services;
use yew::prelude::*;
use yew_router::prelude::*;
use crate::components::{header::Header, image_info::ImageDetail};
use crate::routes::{router::AppRoute};
use crate::services::{requests::Images};
enum Msg {
}
struct Model {
// `ComponentLink` is like a reference to a component.
// It can be used to send messages to the component
link: ComponentLink<Self>,
value: i64,
}
impl Component for Model {
type Message = Msg;
type Properties = ();
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
Self {
link,
value: 0,
}
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
true
}
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
false
}
fn view(&self) -> Html {
html! {
<div>
<Header />
<Router<AppRoute> render = Router::render(Self::switch) />
</div>
}
}
}
impl Model {
fn switch(route: AppRoute) -> Html {
match route {
AppRoute::Images => html! { <Images /> },
AppRoute::ImageDetail(name)=> html! { <ImageDetail image_name=name /> }
}
}
}
fn main() {
yew::start_app::<Model>();
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+15
View File
@@ -0,0 +1,15 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod router;
+25
View File
@@ -0,0 +1,25 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use yew_router::prelude::*;
#[derive(Switch,Clone)]
pub enum AppRoute {
#[to = "/images/{name}"]
ImageDetail(String),
#[to = "/images"]
Images
}
pub type Anchor = RouterAnchor<AppRoute>;
+15
View File
@@ -0,0 +1,15 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod requests;
+41
View File
@@ -0,0 +1,41 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use anyhow::Error;
use serde::Deserialize;
use yew::{ComponentLink, callback::Callback, format::Nothing, services::fetch::{FetchTask, Request}};
pub struct Image {
pub name: String,
pub body: String,
}
#[derive(Deserialize, Debug, Clone)]
pub struct RegistryCatalog {
pub repositories: Vec<String>,
}
pub struct Images {
// props: Props,
pub repos: Option<Vec<String>>,
pub error: Option<String>,
pub link: ComponentLink<Self>,
pub task: Option<FetchTask>
}
pub fn get_image_list(callback: Callback<Result<String, Error>>) {
let images_list = Request::get("https://localhost:5000/v2/_catalog")
.body(Nothing)
.expect("Could not build that request");
}