replase values with overrides

This commit is contained in:
GLYASAI 2021-04-29 15:56:34 +08:00
parent 161443cccf
commit ef9d4ef057
45 changed files with 609 additions and 546 deletions

View File

@ -169,7 +169,6 @@ type ApplicationInterface interface {
Install(w http.ResponseWriter, r *http.Request)
ListServices(w http.ResponseWriter, r *http.Request)
EnsureAppName(w http.ResponseWriter, r *http.Request)
ParseServices(w http.ResponseWriter, r *http.Request)
ListHelmAppReleases(w http.ResponseWriter, r *http.Request)
DeleteConfigGroup(w http.ResponseWriter, r *http.Request)

View File

@ -320,7 +320,6 @@ func (v2 *V2) applicationRouter() chi.Router {
r.Put("/status", controller.GetManager().GetAppStatus)
r.Get("/detect-process", controller.GetManager().GetDetectProcess)
r.Post("/install", controller.GetManager().Install)
r.Post("/parse-services", controller.GetManager().ParseServices)
r.Get("/helm-releases", controller.GetManager().ListHelmAppReleases)
r.Delete("/configgroups/{config_group_name}", controller.GetManager().DeleteConfigGroup)

View File

@ -215,7 +215,7 @@ func (a *ApplicationController) Install(w http.ResponseWriter, r *http.Request)
return
}
if err := handler.GetApplicationHandler().Install(r.Context(), app, installAppReq.Values); err != nil {
if err := handler.GetApplicationHandler().Install(r.Context(), app, installAppReq.Overrides); err != nil {
httputil.ReturnBcodeError(r, w, err)
return
}
@ -267,23 +267,6 @@ func (a *ApplicationController) EnsureAppName(w http.ResponseWriter, r *http.Req
httputil.ReturnSuccess(r, w, res)
}
func (a *ApplicationController) ParseServices(w http.ResponseWriter, r *http.Request) {
app := r.Context().Value(middleware.ContextKey("application")).(*dbmodel.Application)
var installAppReq model.ParseAppServicesReq
if !httputil.ValidatorRequestStructAndErrorResponse(r, w, &installAppReq, nil) {
return
}
services, err := handler.GetApplicationHandler().ParseServices(r.Context(), app, installAppReq.Values)
if err != nil {
httputil.ReturnBcodeError(r, w, err)
return
}
httputil.ReturnSuccess(r, w, services)
}
func (a *ApplicationController) ListHelmAppReleases(w http.ResponseWriter, r *http.Request) {
app := r.Context().Value(middleware.ContextKey("application")).(*dbmodel.Application)

View File

@ -282,7 +282,7 @@ func TestListConfigGroups(t *testing.T) {
db.SetTestManager(manager)
tc.mockFunc(manager, ctrl)
appAction := NewApplicationHandler(nil, nil)
appAction := NewApplicationHandler(nil, nil, nil, nil)
resp, err := appAction.ListConfigGroups(tc.appID, 1, 10)
if (err != nil) != tc.wanterr {
t.Errorf("Unexpected error = %v, wantErr %v", err, tc.wanterr)

View File

@ -2,6 +2,7 @@ package handler
import (
"context"
"encoding/base64"
"fmt"
"sort"
"strconv"
@ -24,6 +25,7 @@ import (
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
"sigs.k8s.io/yaml"
)
// ApplicationAction -
@ -50,10 +52,9 @@ type ApplicationHandler interface {
BatchUpdateComponentPorts(appID string, ports []*model.AppPort) error
GetStatus(ctx context.Context, app *dbmodel.Application) (*model.AppStatus, error)
GetDetectProcess(ctx context.Context, app *dbmodel.Application) ([]*model.AppDetectProcess, error)
Install(ctx context.Context, app *dbmodel.Application, values string) error
Install(ctx context.Context, app *dbmodel.Application, overrides []string) error
ListServices(ctx context.Context, app *dbmodel.Application) ([]*model.AppService, error)
EnsureAppName(ctx context.Context, namespace, appName string) (*model.EnsureAppNameResp, error)
ParseServices(ctx context.Context, app *dbmodel.Application, values string) ([]*model.AppService, error)
ListHelmAppReleases(ctx context.Context, app *dbmodel.Application) ([]*model.HelmAppRelease, error)
DeleteConfigGroup(appID, configGroupName string) error
@ -191,8 +192,8 @@ func (a *ApplicationAction) updateHelmApp(ctx context.Context, app *dbmodel.Appl
}
return errors.Wrap(err, "update app")
}
if req.Values != "" {
helmApp.Spec.Values = req.Values
if len(req.Overrides) > 0 {
helmApp.Spec.Overrides = req.Overrides
}
if req.Version != "" {
helmApp.Spec.Version = req.Version
@ -204,6 +205,20 @@ func (a *ApplicationAction) updateHelmApp(ctx context.Context, app *dbmodel.Appl
return err
}
func (a *ApplicationAction) validateValues(encodedValues string) error {
values, err := base64.StdEncoding.DecodeString(encodedValues)
if err != nil {
return errors.Wrap(bcode.ErrInvalidHelmAppValues, err.Error())
}
obj := make(map[string]interface{})
if err = yaml.Unmarshal(values, obj); err != nil {
return errors.Wrap(bcode.ErrInvalidHelmAppValues, err.Error())
}
return nil
}
// ListApps -
func (a *ApplicationAction) ListApps(tenantID, appName string, page, pageSize int) (*model.ListAppResponse, error) {
var resp model.ListAppResponse
@ -401,16 +416,16 @@ func (a *ApplicationAction) GetStatus(ctx context.Context, app *dbmodel.Applicat
}
res := &model.AppStatus{
Status: status.Status,
Cpu: cpu,
Memory: memory,
Disk: int64(diskUsage),
Phase: status.Phase,
ValuesTemplate: status.ValuesTemplate,
Values: status.Values,
Readme: status.Readme,
Version: status.Version,
Revision: int(status.Revision),
Status: status.Status,
Cpu: cpu,
Memory: memory,
Disk: int64(diskUsage),
Phase: status.Phase,
Overrides: status.Overrides,
Values: status.Values,
Readme: status.Readme,
Version: status.Version,
Revision: int(status.Revision),
}
return res, nil
}
@ -438,36 +453,7 @@ func (a *ApplicationAction) GetDetectProcess(ctx context.Context, app *dbmodel.A
return conditions, nil
}
func (a *ApplicationAction) ParseServices(ctx context.Context, app *dbmodel.Application, values string) ([]*model.AppService, error) {
nctx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
services, err := a.statusCli.ParseAppServices(nctx, &pb.ParseAppServicesReq{
AppID: app.AppID,
Values: values,
})
if err != nil {
return nil, err
}
var appServices []*model.AppService
for _, service := range services.Services {
svc := &model.AppService{
ServiceName: service.Name,
Address: service.Address,
}
for _, port := range service.TcpPorts {
svc.TCPPorts = append(svc.TCPPorts, port)
}
appServices = append(appServices, svc)
}
return appServices, nil
}
func (a *ApplicationAction) Install(ctx context.Context, app *dbmodel.Application, values string) error {
func (a *ApplicationAction) Install(ctx context.Context, app *dbmodel.Application, overrides []string) error {
ctx1, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
@ -481,7 +467,8 @@ func (a *ApplicationAction) Install(ctx context.Context, app *dbmodel.Applicatio
ctx3, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
helmApp.Spec.Values = values
helmApp.Spec.Overrides = overrides
helmApp.Spec.PreStatus = "Configured"
_, err = a.rainbondClient.RainbondV1alpha1().HelmApps(app.TenantID).Update(ctx3, helmApp, metav1.UpdateOptions{})
if err != nil {
return err

View File

@ -10,16 +10,16 @@ type AppPort struct {
// AppStatus -
type AppStatus struct {
Status string `json:"status"`
Cpu *int64 `json:"cpu"`
Memory *int64 `json:"memory"`
Disk int64 `json:"disk"`
Phase string `json:"phase"`
ValuesTemplate string `json:"valuesTemplate"`
Values string `json:"values"`
Readme string `json:"readme"`
Version string `json:"version"`
Revision int `json:"revision"`
Status string `json:"status"`
Cpu *int64 `json:"cpu"`
Memory *int64 `json:"memory"`
Disk int64 `json:"disk"`
Phase string `json:"phase"`
Values string `json:"values"`
Readme string `json:"readme"`
Version string `json:"version"`
Revision int `json:"revision"`
Overrides []string `json:"overrides"`
}
// AppDetectProcess -

View File

@ -1691,16 +1691,16 @@ type ListServiceResponse struct {
// UpdateAppRequest -
type UpdateAppRequest struct {
AppName string `json:"app_name"`
GovernanceMode string `json:"governance_mode"`
Values string `json:"values"`
Version string `json:"version"`
Revision int `json:"revision"`
AppName string `json:"app_name"`
GovernanceMode string `json:"governance_mode"`
Overrides []string `json:"overrides"`
Version string `json:"version"`
Revision int `json:"revision"`
}
// NeedUpdateHelmApp check if necessary to update the helm app.
func (u *UpdateAppRequest) NeedUpdateHelmApp() bool {
return u.Values != "" || u.Version != "" || u.Revision != 0
return len(u.Overrides) > 0 || u.Version != "" || u.Revision != 0
}
// BindServiceRequest -
@ -1710,7 +1710,7 @@ type BindServiceRequest struct {
// InstallAppReq -
type InstallAppReq struct {
Values string `json:"values"`
Overrides []string `json:"overrides"`
}
// ParseAppServicesReq -

View File

@ -14,6 +14,8 @@ var (
ErrDeleteDueToBindService = newByMessage(400, 11005, "the application cannot be deleted because there are bound services")
ErrK8sServiceNameExists = newByMessage(400, 11006, "kubernetes service name already exists")
ErrInvalidHelmAppValues = newByMessage(400, 11007, "invalid helm app values")
)
// app config group 11100~11199

View File

@ -37,23 +37,28 @@ spec:
description: HelmAppSpec defines the desired state of HelmApp
properties:
appName:
description: 'The application name. TODO: validation'
description: The application name.
type: string
appStore:
description: 'The helm app store. TODO: validation. not null'
description: The helm app store.
properties:
branch:
description: The branch of a git repo.
type: string
name:
description: The name of app store.
type: string
password:
description: The chart repository password where to locate the requested
chart
type: string
url:
description: The url of helm repo, sholud be a helm native repo
url or a git url.
type: string
username:
description: The chart repository username where to locate the requested
chart
type: string
version:
description: The verision of the helm app store.
@ -65,6 +70,11 @@ spec:
type: object
eid:
type: string
overrides:
description: Overrides will overrides the values in the chart.
items:
type: string
type: array
preStatus:
description: The prerequisite status.
enum:
@ -74,11 +84,8 @@ spec:
revision:
description: The application revision.
type: integer
values:
description: The values.yaml of the helm app, encoded by base64.
type: string
version:
description: 'The application version. TODO: validation'
description: The application version.
type: string
required:
- appName
@ -124,11 +131,14 @@ spec:
description: The actual revision of the helm app, as same as the revision
from 'helm status'
type: integer
currentValues:
description: The base64 encoded string from the active values.
type: string
currentVersion:
description: The version infect.
type: string
overrides:
additionalProperties:
type: string
description: Overrides in effect.
type: object
phase:
description: The phase of the helm app.
type: string
@ -139,13 +149,13 @@ spec:
description: The status of helm app.
type: string
targetRevision:
description: TargetRevision is the revision that used to rollbak the
description: TargetRevision is the revision that used to rollback the
helm app. After executing command 'helm rollback [appName] [targetRevision]',
the actual revision of helm app is currentRevision, not targetRevision.
The new currentRevision is equals to the origin currentRevision plus
one.
type: integer
valuesTemplate:
values:
description: The base64 encoded string from values.yaml
type: string
required:

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -5,7 +5,7 @@ set -o nounset
set -o pipefail
vendor/k8s.io/code-generator/generate-groups.sh \
"all" \
"defaulter,client,lister,informer" \
"github.com/goodrain/rainbond/pkg/generated" \
"github.com/goodrain/rainbond/pkg/apis" \
"rainbond:v1alpha1" \

View File

@ -117,22 +117,19 @@ type HelmAppSpec struct {
PreStatus string `json:"preStatus,omitempty"`
// The application name.
// TODO: validation
TemplateName string `json:"appName"`
// The application version.
// TODO: validation
Version string `json:"version"`
// The application revision.
Revision int `json:"revision,omitempty"`
// The values.yaml of the helm app, encoded by base64.
Values string `json:"values,omitempty"`
// The helm app store.
// TODO: validation. not null
AppStore *HelmAppStore `json:"appStore"`
// Overrides will overrides the values in the chart.
Overrides []string `json:"overrides,omitempty"`
}
// FullName returns the full name of the app store.
@ -148,6 +145,7 @@ type HelmAppStore struct {
// The verision of the helm app store.
Version string `json:"version"`
// The name of app store.
Name string `json:"name"`
// The url of helm repo, sholud be a helm native repo url or a git url.
@ -156,8 +154,10 @@ type HelmAppStore struct {
// The branch of a git repo.
Branch string `json:"branch,omitempty"`
// The chart repository username where to locate the requested chart
Username string `json:"username,omitempty"`
// The chart repository password where to locate the requested chart
Password string `json:"password,omitempty"`
}
@ -175,25 +175,26 @@ type HelmAppStatus struct {
// Current state of helm app.
Conditions []HelmAppCondition `json:"conditions,omitempty"`
// The base64 encoded string from the active values.
CurrentValues string `json:"currentValues,omitempty"`
// The actual revision of the helm app, as same as the revision from 'helm status'
CurrentRevision int `json:"currentRevision,omitempty"`
// TargetRevision is the revision that used to rollbak the helm app.
// TargetRevision is the revision that used to rollback the helm app.
// After executing command 'helm rollback [appName] [targetRevision]', the actual
// revision of helm app is currentRevision, not targetRevision.
// The new currentRevision is equals to the origin currentRevision plus one.
TargetRevision int `json:"targetRevision,omitempty"`
// The version infect.
CurrentVersion string `json:"currentVersion,omitempty"`
// The base64 encoded string from values.yaml
ValuesTemplate string `json:"valuesTemplate,omitempty"`
Values string `json:"values,omitempty"`
// The base64 encoded string from README.md
Readme string `json:"readme,omitempty"`
// Overrides in effect.
Overrides []string `json:"overrides,omitempty"`
}
// +genclient
@ -210,6 +211,26 @@ type HelmApp struct {
Status HelmAppStatus `json:"status,omitempty"`
}
// OverridesEqual tells whether overrides in spec and status contain the same elements.
func (in *HelmApp) OverridesEqual() bool {
if len(in.Spec.Overrides) != len(in.Status.Overrides) {
return false
}
candidates := make(map[string]struct{})
for _, o := range in.Spec.Overrides {
candidates[o] = struct{}{}
}
for _, o := range in.Status.Overrides {
_, ok := candidates[o]
if !ok {
return false
}
}
return true
}
// +kubebuilder:object:root=true
// HelmAppList contains a list of HelmApp

View File

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -109,6 +109,11 @@ func (in *HelmAppSpec) DeepCopyInto(out *HelmAppSpec) {
*out = new(HelmAppStore)
**out = **in
}
if in.Overrides != nil {
in, out := &in.Overrides, &out.Overrides
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmAppSpec.
@ -131,6 +136,11 @@ func (in *HelmAppStatus) DeepCopyInto(out *HelmAppStatus) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Overrides != nil {
in, out := &in.Overrides, &out.Overrides
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmAppStatus.

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2020 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by

View File

@ -2,6 +2,7 @@ package helmapp
import (
"context"
"errors"
"strings"
"github.com/goodrain/rainbond/pkg/apis/rainbond/v1alpha1"
@ -9,6 +10,7 @@ import (
k8sutil "github.com/goodrain/rainbond/util/k8s"
"github.com/goodrain/rainbond/worker/controllers/helmapp/helm"
"github.com/sirupsen/logrus"
"helm.sh/helm/v3/pkg/storage/driver"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/util/workqueue"
@ -17,7 +19,7 @@ import (
type ControlLoop struct {
clientset versioned.Interface
storer Storer
workqueue workqueue.Interface
workQueue workqueue.Interface
repo *helm.Repo
repoFile string
repoCache string
@ -26,7 +28,7 @@ type ControlLoop struct {
// NewControlLoop -
func NewControlLoop(clientset versioned.Interface,
storer Storer,
workqueue workqueue.Interface,
workQueue workqueue.Interface,
repoFile string,
repoCache string,
) *ControlLoop {
@ -35,7 +37,7 @@ func NewControlLoop(clientset versioned.Interface,
return &ControlLoop{
clientset: clientset,
storer: storer,
workqueue: workqueue,
workQueue: workQueue,
repo: repo,
repoFile: repoFile,
repoCache: repoCache,
@ -44,7 +46,7 @@ func NewControlLoop(clientset versioned.Interface,
func (c *ControlLoop) Run() {
for {
obj, shutdown := c.workqueue.Get()
obj, shutdown := c.workQueue.Get()
if shutdown {
return
}
@ -58,7 +60,7 @@ func (c *ControlLoop) run(obj interface{}) {
if !ok {
return
}
defer c.workqueue.Done(obj)
defer c.workQueue.Done(obj)
name, ns := nameNamespace(key)
helmApp, err := c.storer.GetHelmApp(ns, name)
@ -79,7 +81,7 @@ func (c *ControlLoop) Reconcile(helmApp *v1alpha1.HelmApp) error {
appStore := helmApp.Spec.AppStore
app, err := helm.NewApp(helmApp.Name, helmApp.Namespace,
helmApp.Spec.TemplateName, helmApp.Spec.Version, helmApp.Spec.Revision, helmApp.Spec.Values,
helmApp.Spec.TemplateName, helmApp.Spec.Version, helmApp.Spec.Revision, helmApp.Spec.Overrides,
helmApp.Spec.FullName(), appStore.URL, c.repoFile, c.repoCache)
if err != nil {
@ -92,7 +94,9 @@ func (c *ControlLoop) Reconcile(helmApp *v1alpha1.HelmApp) error {
helmApp.Status = status.GetHelmAppStatus()
appStatus, err := app.Status()
if err != nil {
logrus.Warningf("get app status: %v", err)
if !errors.Is(err, driver.ErrReleaseNotFound) {
logrus.Warningf("get app status: %v", err)
}
} else {
helmApp.Status.Status = v1alpha1.HelmAppStatusStatus(appStatus.Info.Status)
helmApp.Status.CurrentRevision = appStatus.Version
@ -121,8 +125,8 @@ func (c *ControlLoop) Reconcile(helmApp *v1alpha1.HelmApp) error {
return err
}
status.UpdateConditionStatus(v1alpha1.HelmAppInstalled, corev1.ConditionTrue)
status.CurrentValues = helmApp.Spec.Values
status.CurrentVersion = helmApp.Spec.Version
status.Overrides = helmApp.Spec.Overrides
}
if needRollback(helmApp) {
@ -138,8 +142,10 @@ func (c *ControlLoop) Reconcile(helmApp *v1alpha1.HelmApp) error {
// check if the helmApp needed to be update
func needUpdate(helmApp *v1alpha1.HelmApp) bool {
return helmApp.Spec.Values != helmApp.Status.CurrentValues ||
helmApp.Spec.Version != helmApp.Status.CurrentVersion
if helmApp.Spec.PreStatus != "Configured" {
return false
}
return !helmApp.OverridesEqual() || helmApp.Spec.Version != helmApp.Status.CurrentVersion
}
// check if the helmApp needed to be rollback

View File

@ -69,7 +69,7 @@ func (d *Detector) Detect() error {
return err
}
d.status.UpdateConditionStatus(v1alpha1.HelmAppChartParsed, corev1.ConditionTrue)
d.status.ValuesTemplate = values
d.status.Values = values
d.status.Readme = readme
}

View File

@ -58,7 +58,7 @@ func (c *Finalizer) run(obj interface{}) error {
// TODO: too much args
app, err := helm.NewApp(helmApp.Name, helmApp.Namespace,
helmApp.Spec.TemplateName, helmApp.Spec.Version, helmApp.Spec.Revision,
helmApp.Spec.Values,
helmApp.Spec.Overrides,
helmApp.Spec.FullName(), appStore.URL, c.repoFile, c.repoCache)
if err != nil {
return err

View File

@ -8,16 +8,12 @@ import (
"path"
"path/filepath"
"github.com/goodrain/rainbond/util/commonutil"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/kube"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/storage/driver"
"k8s.io/cli-runtime/pkg/genericclioptions"
"sigs.k8s.io/yaml"
)
type App struct {
@ -29,8 +25,7 @@ type App struct {
version string
chartDir string
revision int
encodedValues string
overrides []string
helm *Helm
repo *Repo
@ -40,29 +35,25 @@ func (a *App) Chart() string {
return a.repoName + "/" + a.templateName
}
func NewApp(name, namespace, templateName, version string, revision int, values, repoName, repoURL, repoFile, repoCache string) (*App, error) {
configFlags := genericclioptions.NewConfigFlags(true)
configFlags.Namespace = commonutil.String(namespace)
kubeClient := kube.New(configFlags)
helm, err := NewHelm(kubeClient, configFlags, namespace, repoFile, repoCache)
func NewApp(name, namespace, templateName, version string, revision int, overrides []string, repoName, repoURL, repoFile, repoCache string) (*App, error) {
helm, err := NewHelm(namespace, repoFile, repoCache)
if err != nil {
return nil, err
}
repo := NewRepo(repoFile, repoCache)
return &App{
name: name,
namespace: namespace,
templateName: templateName,
repoName: repoName,
repoURL: repoURL,
version: version,
revision: revision,
encodedValues: values,
helm: helm,
repo: repo,
chartDir: path.Join("/tmp/helm/chart", namespace, name, version),
name: name,
namespace: namespace,
templateName: templateName,
repoName: repoName,
repoURL: repoURL,
version: version,
revision: revision,
overrides: overrides,
helm: helm,
repo: repo,
chartDir: path.Join("/tmp/helm/chart", namespace, name, version),
}, nil
}
@ -110,11 +101,11 @@ func (a *App) PreInstall() error {
}
func (a *App) Status() (*release.Release, error) {
release, err := a.helm.Status(a.name)
rel, err := a.helm.Status(a.name)
if err != nil {
return nil, err
}
return release, nil
return rel, nil
}
func (a *App) InstallOrUpdate() error {
@ -122,23 +113,14 @@ func (a *App) InstallOrUpdate() error {
return err
}
b, err := base64.StdEncoding.DecodeString(a.encodedValues)
if err != nil {
return errors.Wrap(err, "decode values")
}
values := map[string]interface{}{}
if err := yaml.Unmarshal(b, &values); err != nil {
return errors.Wrap(err, "parse values")
}
_, err = a.helm.Status(a.name)
_, err := a.helm.Status(a.name)
if err != nil && !errors.Is(err, driver.ErrReleaseNotFound) {
return err
}
if errors.Is(err, driver.ErrReleaseNotFound) {
logrus.Debugf("name: %s; namespace: %s; chart: %s; install helm app", a.name, a.namespace, a.Chart())
if err := a.helm.Install(a.name, a.Chart(), a.version, values); err != nil {
if err := a.helm.Install(a.name, a.Chart(), a.version, a.overrides); err != nil {
return err
}
@ -146,7 +128,7 @@ func (a *App) InstallOrUpdate() error {
}
logrus.Debugf("name: %s; namespace: %s; chart: %s; upgrade helm app", a.name, a.namespace, a.Chart())
return a.helm.Upgrade(a.name, a.chart(), a.version, values)
return a.helm.Upgrade(a.name, a.chart(), a.version, a.overrides)
}
func (a *App) ParseChart() (string, string, error) {
@ -191,5 +173,9 @@ func (a *App) Uninstall() error {
}
func (a *App) Rollback() error {
if err := a.repo.Add(a.repoName, a.repoURL, "", ""); err != nil {
return err
}
return a.helm.Rollback(a.name, a.revision)
}

View File

@ -6,6 +6,7 @@ import (
"io/ioutil"
"unsafe"
"github.com/goodrain/rainbond/util/commonutil"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"helm.sh/helm/v3/pkg/action"
@ -17,6 +18,7 @@ import (
"helm.sh/helm/v3/pkg/kube"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/releaseutil"
"helm.sh/helm/v3/pkg/strvals"
helmtime "helm.sh/helm/v3/pkg/time"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
@ -42,7 +44,11 @@ type Helm struct {
}
// NewHelm creates a new helm.
func NewHelm(kubeClient kube.Interface, configFlags *genericclioptions.ConfigFlags, namespace, repoFile, repoCache string) (*Helm, error) {
func NewHelm(namespace, repoFile, repoCache string) (*Helm, error) {
configFlags := genericclioptions.NewConfigFlags(true)
configFlags.Namespace = commonutil.String(namespace)
kubeClient := kube.New(configFlags)
cfg := &action.Configuration{
KubeClient: kubeClient,
Log: func(s string, i ...interface{}) {
@ -77,20 +83,20 @@ func (h *Helm) PreInstall(name, chart, version string, out io.Writer) error {
return err
}
func (h *Helm) Install(name, chart, version string, vals map[string]interface{}) error {
_, err := h.install(name, chart, version, vals, false, ioutil.Discard)
func (h *Helm) Install(name, chart, version string, overrides []string) error {
_, err := h.install(name, chart, version, overrides, false, ioutil.Discard)
return err
}
func (h *Helm) Manifests(name, chart, version string, vals map[string]interface{}, out io.Writer) (string, error) {
rel, err := h.install(name, chart, version, vals, true, out)
func (h *Helm) Manifests(name, chart, version string, overrides []string, out io.Writer) (string, error) {
rel, err := h.install(name, chart, version, overrides, true, out)
if err != nil {
return "", err
}
return rel.Manifest, nil
}
func (h *Helm) install(name, chart, version string, vals map[string]interface{}, dryRun bool, out io.Writer) (*release.Release, error) {
func (h *Helm) install(name, chart, version string, overrides []string, dryRun bool, out io.Writer) (*release.Release, error) {
client := action.NewInstall(h.cfg)
client.ReleaseName = name
client.Namespace = h.namespace
@ -105,6 +111,11 @@ func (h *Helm) install(name, chart, version string, vals map[string]interface{},
logrus.Debugf("CHART PATH: %s\n", cp)
p := getter.All(h.settings)
// User specified a value via --set
vals, err := h.parseOverrides(overrides)
if err != nil {
return nil, err
}
// Check chart dependencies to make sure all are present in /charts
chartRequested, err := loader.Load(cp)
@ -152,7 +163,16 @@ func (h *Helm) install(name, chart, version string, vals map[string]interface{},
return client.Run(chartRequested, vals)
}
func (h *Helm) Upgrade(name string, chart, version string, vals map[string]interface{}) error {
func (h *Helm) parseOverrides(overrides []string) (map[string]interface{}, error) {
vals := make(map[string]interface{})
for _, value := range overrides {
if err := strvals.ParseInto(value, vals); err != nil {
return nil, errors.Wrap(err, "failed parsing --set data")
}
}
return vals, nil
}
func (h *Helm) Upgrade(name string, chart, version string, overrides []string) error {
client := action.NewUpgrade(h.cfg)
client.Namespace = h.namespace
client.Version = version
@ -162,6 +182,12 @@ func (h *Helm) Upgrade(name string, chart, version string, vals map[string]inter
return err
}
// User specified a value via --set
vals, err := h.parseOverrides(overrides)
if err != nil {
return err
}
// Check chart dependencies to make sure all are present in /charts
ch, err := loader.Load(chartPath)
if err != nil {

View File

@ -6,8 +6,9 @@ import (
)
type Status struct {
helmApp *v1alpha1.HelmApp
v1alpha1.HelmAppStatus
values string
overrides []string
}
// NewStatus creates a new helm app status.
@ -30,7 +31,7 @@ func NewStatus(app *v1alpha1.HelmApp) (*Status, bool) {
}
return &Status{
HelmAppStatus: app.Status,
values: app.Spec.Values,
helmApp: app,
}, continu3
}
@ -47,10 +48,11 @@ func (s *Status) getPhase() v1alpha1.HelmAppStatusPhase {
if s.isDetected() {
phase = v1alpha1.HelmAppStatusPhaseConfiguring
}
if s.values != "" {
if s.helmApp.Spec.PreStatus == "Configured" {
phase = v1alpha1.HelmAppStatusPhaseInstalling
}
if s.values != "" && s.values == s.CurrentValues {
idx, condition := s.helmApp.Status.GetCondition(v1alpha1.HelmAppInstalled)
if idx != -1 && condition.Status == corev1.ConditionTrue {
phase = v1alpha1.HelmAppStatusPhaseInstalled
}
return phase

View File

@ -1944,6 +1944,7 @@ type AppStatus struct {
Values string `protobuf:"bytes,9,opt,name=values,proto3" json:"values,omitempty"`
Version string `protobuf:"bytes,10,opt,name=version,proto3" json:"version,omitempty"`
Revision int32 `protobuf:"varint,11,opt,name=revision,proto3" json:"revision,omitempty"`
Overrides []string `protobuf:"bytes,12,rep,name=overrides,proto3" json:"overrides,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -2051,6 +2052,13 @@ func (m *AppStatus) GetRevision() int32 {
return 0
}
func (m *AppStatus) GetOverrides() []string {
if m != nil {
return m.Overrides
}
return nil
}
type AppDetectCondition struct {
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Ready bool `protobuf:"varint,2,opt,name=ready,proto3" json:"ready,omitempty"`
@ -2302,53 +2310,6 @@ func (m *AppServices) GetServices() []*AppService {
return nil
}
type ParseAppServicesReq struct {
AppID string `protobuf:"bytes,1,opt,name=appID,proto3" json:"appID,omitempty"`
Values string `protobuf:"bytes,2,opt,name=values,proto3" json:"values,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ParseAppServicesReq) Reset() { *m = ParseAppServicesReq{} }
func (m *ParseAppServicesReq) String() string { return proto.CompactTextString(m) }
func (*ParseAppServicesReq) ProtoMessage() {}
func (*ParseAppServicesReq) Descriptor() ([]byte, []int) {
return fileDescriptor_f94cf1a886c479d6, []int{36}
}
func (m *ParseAppServicesReq) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParseAppServicesReq.Unmarshal(m, b)
}
func (m *ParseAppServicesReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ParseAppServicesReq.Marshal(b, m, deterministic)
}
func (m *ParseAppServicesReq) XXX_Merge(src proto.Message) {
xxx_messageInfo_ParseAppServicesReq.Merge(m, src)
}
func (m *ParseAppServicesReq) XXX_Size() int {
return xxx_messageInfo_ParseAppServicesReq.Size(m)
}
func (m *ParseAppServicesReq) XXX_DiscardUnknown() {
xxx_messageInfo_ParseAppServicesReq.DiscardUnknown(m)
}
var xxx_messageInfo_ParseAppServicesReq proto.InternalMessageInfo
func (m *ParseAppServicesReq) GetAppID() string {
if m != nil {
return m.AppID
}
return ""
}
func (m *ParseAppServicesReq) GetValues() string {
if m != nil {
return m.Values
}
return ""
}
type HelmAppReleases struct {
HelmAppRelease []*HelmAppRelease `protobuf:"bytes,1,rep,name=helmAppRelease,proto3" json:"helmAppRelease,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@ -2360,7 +2321,7 @@ func (m *HelmAppReleases) Reset() { *m = HelmAppReleases{} }
func (m *HelmAppReleases) String() string { return proto.CompactTextString(m) }
func (*HelmAppReleases) ProtoMessage() {}
func (*HelmAppReleases) Descriptor() ([]byte, []int) {
return fileDescriptor_f94cf1a886c479d6, []int{37}
return fileDescriptor_f94cf1a886c479d6, []int{36}
}
func (m *HelmAppReleases) XXX_Unmarshal(b []byte) error {
@ -2404,7 +2365,7 @@ func (m *HelmAppRelease) Reset() { *m = HelmAppRelease{} }
func (m *HelmAppRelease) String() string { return proto.CompactTextString(m) }
func (*HelmAppRelease) ProtoMessage() {}
func (*HelmAppRelease) Descriptor() ([]byte, []int) {
return fileDescriptor_f94cf1a886c479d6, []int{38}
return fileDescriptor_f94cf1a886c479d6, []int{37}
}
func (m *HelmAppRelease) XXX_Unmarshal(b []byte) error {
@ -2521,7 +2482,6 @@ func init() {
proto.RegisterType((*AppService)(nil), "pb.AppService")
proto.RegisterType((*AppService_Pod)(nil), "pb.AppService.Pod")
proto.RegisterType((*AppServices)(nil), "pb.AppServices")
proto.RegisterType((*ParseAppServicesReq)(nil), "pb.ParseAppServicesReq")
proto.RegisterType((*HelmAppReleases)(nil), "pb.HelmAppReleases")
proto.RegisterType((*HelmAppRelease)(nil), "pb.HelmAppRelease")
}
@ -2529,171 +2489,170 @@ func init() {
func init() { proto.RegisterFile("app_runtime_server.proto", fileDescriptor_f94cf1a886c479d6) }
var fileDescriptor_f94cf1a886c479d6 = []byte{
// 2615 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x19, 0x5d, 0x6f, 0xdb, 0xc8,
0xd1, 0x92, 0xac, 0xaf, 0x91, 0x2d, 0xcb, 0xeb, 0x2f, 0x9d, 0xee, 0xf2, 0x71, 0x6c, 0x12, 0x04,
0xc9, 0xd5, 0x97, 0xb8, 0x97, 0xe6, 0xe3, 0xd2, 0x14, 0x8a, 0xa4, 0x73, 0xd4, 0xda, 0xb2, 0x40,
0xcb, 0x57, 0x1c, 0x50, 0x40, 0xa0, 0xc5, 0x3d, 0x87, 0x0d, 0x3f, 0xf6, 0x48, 0xca, 0x57, 0x3d,
0xb6, 0x7f, 0xa1, 0x3f, 0xa1, 0x0f, 0x7d, 0x68, 0x1f, 0x8b, 0x3e, 0xde, 0x3f, 0x28, 0xfa, 0x53,
0xee, 0xa5, 0x4f, 0x05, 0x0a, 0x14, 0xb3, 0xbb, 0x24, 0x97, 0x14, 0x9d, 0x34, 0x45, 0x8b, 0xbe,
0x71, 0x66, 0x67, 0x76, 0x66, 0x67, 0x66, 0x67, 0x66, 0x87, 0xd0, 0x36, 0x18, 0x9b, 0xfa, 0x73,
// 2593 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x19, 0xcb, 0x72, 0xdb, 0xc8,
0x51, 0x24, 0xc5, 0x57, 0x53, 0xa2, 0xa8, 0xd1, 0x8b, 0x4b, 0xaf, 0x1f, 0x8b, 0xd8, 0x2e, 0x97,
0xbd, 0xd1, 0xda, 0xca, 0x3a, 0x7e, 0xac, 0xb3, 0x29, 0x5a, 0xe4, 0xca, 0x4c, 0x24, 0x8a, 0x05,
0x52, 0x9b, 0xda, 0xaa, 0x54, 0xb1, 0x20, 0x62, 0x56, 0x46, 0x8c, 0xc7, 0x2c, 0x00, 0x6a, 0xc3,
0x63, 0xf2, 0x0b, 0x39, 0xe6, 0x98, 0x43, 0x0e, 0xc9, 0x31, 0x95, 0x43, 0x0e, 0xfb, 0x07, 0xa9,
0x7c, 0xca, 0x5e, 0xf2, 0x01, 0xa9, 0x9e, 0x19, 0x00, 0x03, 0x10, 0xb2, 0xe3, 0x54, 0x52, 0xb9,
0xa1, 0x7b, 0xba, 0xa7, 0x7b, 0xba, 0x7b, 0xba, 0x7b, 0x1a, 0xd0, 0x36, 0x18, 0x9b, 0xfa, 0x73,
0x37, 0xb4, 0x1c, 0x3a, 0x0d, 0xa8, 0x7f, 0x49, 0xfd, 0x7d, 0xe6, 0x7b, 0xa1, 0x47, 0x8a, 0xec,
0x5c, 0xab, 0x42, 0x79, 0xe0, 0xb0, 0x70, 0xa1, 0xdd, 0x80, 0x4a, 0x97, 0x31, 0x9d, 0x7e, 0x43,
0x76, 0xa0, 0x82, 0x2c, 0x96, 0xd9, 0x2e, 0xdc, 0x2c, 0xdc, 0xad, 0xeb, 0x65, 0x83, 0xb1, 0xa1,
0xa9, 0xdd, 0x86, 0xb5, 0x2e, 0x63, 0xa7, 0xa1, 0x11, 0xce, 0x83, 0xb7, 0x90, 0x7d, 0x0a, 0xcd,
0x53, 0xea, 0x5f, 0x5a, 0x33, 0xaa, 0xd3, 0x6f, 0xe6, 0x34, 0x08, 0xc9, 0x35, 0x80, 0x40, 0x60,
0x12, 0xe2, 0xba, 0xc4, 0x0c, 0x4d, 0xed, 0x00, 0x36, 0x24, 0x43, 0x10, 0x71, 0xdc, 0x80, 0x46,
0xc2, 0x11, 0x48, 0x16, 0x88, 0x59, 0x02, 0xed, 0x13, 0x58, 0x9f, 0x50, 0xd7, 0x70, 0xc3, 0x88,
0xe3, 0x43, 0xa8, 0x87, 0x1c, 0x91, 0x88, 0xa8, 0x09, 0xc4, 0xd0, 0xd4, 0x7e, 0x53, 0x80, 0x75,
0xa1, 0xf7, 0x31, 0x0d, 0x02, 0xe3, 0x82, 0x92, 0x47, 0x50, 0x09, 0x38, 0xa2, 0x5d, 0xb8, 0x59,
0xba, 0xdb, 0x38, 0xb8, 0xb6, 0xcf, 0xce, 0xf7, 0x53, 0x24, 0x12, 0x1a, 0xb8, 0xa1, 0xbf, 0xd0,
0x25, 0x71, 0xe7, 0x29, 0x34, 0x14, 0x34, 0x69, 0x41, 0xe9, 0x0d, 0x5d, 0x48, 0x71, 0xf8, 0x49,
0xb6, 0xa1, 0x7c, 0x69, 0xd8, 0x73, 0xda, 0x2e, 0x0a, 0x93, 0x70, 0xe0, 0x59, 0xf1, 0x49, 0x41,
0x5b, 0x40, 0xa3, 0x6f, 0x05, 0x6f, 0x22, 0x05, 0x1e, 0x40, 0xd9, 0xb4, 0x82, 0x37, 0x91, 0xfc,
0x0e, 0xca, 0x57, 0xd6, 0xf9, 0xb7, 0x14, 0x2e, 0x08, 0x3b, 0x4f, 0x00, 0x12, 0xe4, 0xbb, 0x44,
0x17, 0x54, 0xd1, 0x0e, 0x6c, 0x4a, 0x03, 0x77, 0x19, 0x1b, 0x7b, 0xe6, 0x91, 0x15, 0x84, 0xe4,
0x3e, 0x54, 0x3d, 0xdb, 0x1c, 0x7b, 0x66, 0xa4, 0xc2, 0x26, 0x37, 0x81, 0x4a, 0xa7, 0x47, 0x14,
0x48, 0xec, 0xd2, 0x6f, 0x39, 0x71, 0xf1, 0x4a, 0x62, 0x49, 0xa1, 0x7d, 0x57, 0x80, 0xdd, 0xe3,
0xb9, 0x1d, 0x5a, 0xcb, 0x42, 0x8f, 0x63, 0xbf, 0x2a, 0x82, 0xef, 0xe3, 0x5e, 0xf9, 0x0c, 0x91,
0x08, 0xa4, 0x16, 0xc6, 0x50, 0xf9, 0x3b, 0x67, 0xd0, 0xca, 0x12, 0xe4, 0x18, 0xe6, 0xbe, 0x6a,
0x98, 0xc6, 0xc1, 0xce, 0x92, 0xea, 0x28, 0x49, 0xb5, 0xd7, 0xf7, 0x45, 0x58, 0x4f, 0x11, 0xbc,
0x23, 0x82, 0x31, 0xf8, 0x4c, 0xca, 0x6c, 0x6f, 0x81, 0xab, 0xc2, 0xf3, 0x35, 0x81, 0x18, 0x9a,
0x18, 0xcb, 0x72, 0x31, 0x5c, 0x30, 0xda, 0x2e, 0x89, 0x58, 0x16, 0xa8, 0xc9, 0x82, 0x51, 0xf2,
0x01, 0xd4, 0x98, 0x67, 0x4e, 0x5d, 0xc3, 0xa1, 0xed, 0x55, 0xbe, 0x5a, 0x65, 0x9e, 0x39, 0x32,
0x1c, 0x8a, 0x57, 0x0c, 0x97, 0x2c, 0xd6, 0x2e, 0x8b, 0x78, 0x62, 0x9e, 0x39, 0x64, 0xa8, 0x0e,
0xa2, 0x65, 0x04, 0x57, 0x84, 0x3a, 0xcc, 0x33, 0x45, 0x6c, 0x92, 0x2e, 0xc0, 0xcc, 0x73, 0x43,
0xc3, 0x72, 0xa9, 0x1f, 0xb4, 0xab, 0xdc, 0xc8, 0x1f, 0x2f, 0x9d, 0x7a, 0xbf, 0x17, 0xd3, 0x08,
0xd3, 0x2a, 0x4c, 0xa8, 0x34, 0x4a, 0xb8, 0xf4, 0xec, 0xb9, 0x43, 0x83, 0x76, 0xed, 0x66, 0x09,
0x95, 0x66, 0x9e, 0xf9, 0xa5, 0xc0, 0x74, 0x8e, 0x60, 0x23, 0xc3, 0x9f, 0x63, 0xf9, 0x1f, 0xa4,
0x2d, 0xbf, 0x8e, 0x3a, 0xc4, 0x5c, 0xaa, 0xc5, 0x2f, 0xa1, 0x1e, 0xe3, 0xc9, 0x6d, 0x68, 0xc6,
0x9a, 0x08, 0xab, 0x88, 0x2d, 0xd7, 0x63, 0x2c, 0xb7, 0xcd, 0xc7, 0xb0, 0xe6, 0x50, 0xc7, 0xf3,
0x17, 0x53, 0xdb, 0x72, 0xac, 0x90, 0xcb, 0x28, 0xe9, 0x0d, 0x81, 0x3b, 0x42, 0x14, 0x9e, 0x62,
0xc6, 0xe6, 0x53, 0x5f, 0xe4, 0x08, 0x6e, 0xfa, 0x92, 0x0e, 0x33, 0x36, 0x97, 0x59, 0x43, 0xfb,
0xbe, 0x02, 0xd0, 0x17, 0x8e, 0x72, 0xbf, 0xf6, 0xc8, 0x47, 0x50, 0x47, 0x79, 0x01, 0x33, 0x66,
0x91, 0xd0, 0x04, 0x41, 0x34, 0x58, 0x43, 0x8b, 0xd3, 0xaf, 0xe7, 0x36, 0x0d, 0x68, 0x28, 0x1d,
0x9d, 0xc2, 0x91, 0xeb, 0x20, 0x3d, 0xeb, 0x50, 0x37, 0x4c, 0xfb, 0x1a, 0x31, 0x3c, 0x90, 0x42,
0xc3, 0x0f, 0xa7, 0x98, 0x8c, 0xa5, 0xb7, 0xeb, 0x1c, 0x33, 0xb1, 0x1c, 0x4a, 0x3e, 0x81, 0x55,
0x86, 0x17, 0xa3, 0xcc, 0x7d, 0xd6, 0xe6, 0x49, 0x21, 0x56, 0x6f, 0x3f, 0xb9, 0x05, 0x9c, 0x8a,
0x3c, 0x81, 0x9a, 0x8c, 0x41, 0x0c, 0x02, 0xe4, 0xf8, 0x28, 0xc3, 0x11, 0xe5, 0x55, 0xc1, 0x15,
0x53, 0x93, 0xcf, 0xa1, 0x4e, 0x5d, 0x93, 0x79, 0x96, 0x1b, 0x46, 0x01, 0x72, 0x2d, 0xc3, 0x3a,
0x88, 0xd6, 0x05, 0x6f, 0x42, 0x4f, 0x1e, 0x41, 0x35, 0xa0, 0x33, 0x9f, 0x86, 0x22, 0x2e, 0x1a,
0x07, 0x1f, 0x2e, 0x49, 0xe5, 0xab, 0x82, 0x31, 0xa2, 0x45, 0x99, 0x96, 0x7b, 0xe1, 0xd3, 0x20,
0xa0, 0x41, 0xbb, 0x9e, 0x2b, 0x73, 0x18, 0xad, 0x4b, 0x99, 0x31, 0x3d, 0xe9, 0x42, 0xc3, 0xa7,
0xcc, 0xb6, 0x66, 0x46, 0x88, 0xa6, 0x07, 0xce, 0x7e, 0x23, 0xc3, 0xae, 0x27, 0x14, 0x32, 0x59,
0x28, 0x3c, 0x64, 0x37, 0x4e, 0xf9, 0x0d, 0x6e, 0xf6, 0x28, 0xa7, 0x3f, 0x86, 0xfa, 0xdb, 0xb2,
0xc7, 0x95, 0x19, 0xbd, 0xf3, 0x79, 0x9c, 0x25, 0xfe, 0x03, 0xe6, 0xe7, 0xd0, 0x4c, 0x5b, 0xf8,
0xbd, 0xb8, 0x9f, 0xc1, 0x9a, 0x6a, 0xe4, 0xf7, 0x95, 0x9c, 0xb6, 0xf3, 0x7b, 0x71, 0xbf, 0x80,
0x56, 0xd6, 0xcc, 0xef, 0x55, 0x06, 0xff, 0x54, 0x84, 0x66, 0x54, 0xb9, 0x03, 0x6f, 0xee, 0xcf,
0x68, 0xf6, 0x96, 0x16, 0xb2, 0xb7, 0x14, 0xd3, 0x2b, 0x12, 0xa8, 0xd7, 0xbc, 0x36, 0x63, 0x73,
0x71, 0xc7, 0x6f, 0x43, 0x53, 0xa6, 0x81, 0xf4, 0x35, 0x5f, 0x17, 0xd8, 0x68, 0x8f, 0x6c, 0xb6,
0x58, 0x5d, 0xce, 0x16, 0x77, 0x60, 0xc3, 0x9f, 0xbb, 0xae, 0xe5, 0x5e, 0x4c, 0xb1, 0xaf, 0x71,
0xe7, 0x0e, 0xcf, 0xba, 0x25, 0x7d, 0x5d, 0xa2, 0xbb, 0x8c, 0x8d, 0xe6, 0x0e, 0x79, 0x08, 0x3b,
0x2a, 0x5d, 0xf8, 0xda, 0xf2, 0x4d, 0x4e, 0x0d, 0x9c, 0x9a, 0x24, 0xd4, 0x13, 0x5c, 0x42, 0x96,
0xc7, 0xd0, 0x56, 0x59, 0x2c, 0x37, 0xa4, 0xbe, 0x6b, 0xd8, 0x9c, 0xab, 0xc1, 0xb9, 0x76, 0x12,
0xae, 0xa1, 0x5c, 0x1d, 0xcd, 0x1d, 0xed, 0x8f, 0x05, 0x20, 0x69, 0x73, 0xf1, 0x3a, 0xda, 0x83,
0xba, 0x2f, 0xe1, 0xa8, 0x8a, 0xde, 0xc6, 0xcb, 0xb0, 0x4c, 0xba, 0x1f, 0x01, 0xd1, 0x9d, 0x8a,
0xf9, 0x3a, 0x63, 0x68, 0xa6, 0x17, 0x73, 0x1c, 0x79, 0x37, 0x9d, 0xc1, 0xc9, 0xb2, 0x10, 0xd5,
0xb9, 0xbf, 0x2d, 0xc0, 0x07, 0x5d, 0xd3, 0xe4, 0xc7, 0x1e, 0x1b, 0x7e, 0xb8, 0x88, 0x43, 0x1c,
0xfb, 0x45, 0x02, 0xab, 0xf3, 0x79, 0x5c, 0x3e, 0xf9, 0x37, 0x4a, 0x0c, 0xe2, 0x9a, 0x89, 0x9f,
0xa4, 0x09, 0x45, 0x8b, 0xc9, 0xcc, 0x59, 0xb4, 0x18, 0x72, 0x31, 0xcf, 0x17, 0x0e, 0x2b, 0xeb,
0xfc, 0x1b, 0x03, 0xc2, 0x0a, 0xa6, 0x9e, 0x6b, 0x5b, 0x2e, 0xe5, 0x3e, 0xaa, 0xe9, 0x35, 0x2b,
0x38, 0xe1, 0x30, 0x57, 0xe2, 0x8c, 0xfd, 0x9f, 0x95, 0xa0, 0xf0, 0x41, 0x9f, 0xda, 0xff, 0x6b,
0x1d, 0xb4, 0xdf, 0x61, 0x78, 0x2c, 0x09, 0xf9, 0x2f, 0x1e, 0x32, 0x49, 0x9a, 0x65, 0x35, 0x69,
0xa6, 0x0f, 0x5f, 0xc9, 0x1c, 0xfe, 0xa7, 0xb0, 0x95, 0x73, 0x72, 0x72, 0x17, 0x4a, 0xde, 0xf9,
0xaf, 0x64, 0xb8, 0xee, 0xf2, 0x48, 0x5a, 0xa2, 0xd2, 0x91, 0x44, 0xbb, 0x05, 0x2d, 0x8c, 0x5d,
0x4c, 0xcb, 0x2f, 0x17, 0xa7, 0xc3, 0x3e, 0x1a, 0x4d, 0xea, 0x5f, 0x88, 0xf5, 0xd7, 0x5e, 0xc0,
0xc6, 0x21, 0x45, 0xa2, 0x3e, 0x0d, 0x0d, 0xcb, 0xce, 0x25, 0x4a, 0x35, 0x57, 0xc5, 0x54, 0x73,
0xa5, 0x9d, 0x43, 0x6d, 0xec, 0x99, 0x83, 0x4b, 0x2a, 0x2c, 0xc6, 0xbb, 0x33, 0x69, 0x31, 0xfc,
0xc6, 0xb3, 0xfb, 0xd4, 0x08, 0x3c, 0x57, 0x32, 0x4a, 0x08, 0x85, 0x18, 0x17, 0x51, 0x23, 0x87,
0x9f, 0xa4, 0x0d, 0x55, 0x47, 0xf4, 0xed, 0xd2, 0x4c, 0x11, 0xa8, 0x7d, 0x57, 0xe4, 0xd5, 0x45,
0x36, 0x66, 0x77, 0x14, 0x29, 0x4d, 0x71, 0x99, 0xe2, 0xc5, 0x7d, 0xec, 0x05, 0xdf, 0x21, 0x59,
0x91, 0x53, 0x4a, 0xc9, 0x41, 0x0e, 0xc3, 0xc4, 0x52, 0x24, 0x7b, 0x0a, 0x09, 0xe1, 0xf1, 0x71,
0xc7, 0x69, 0x10, 0xfa, 0x91, 0x6a, 0x08, 0x9f, 0x86, 0xbe, 0xf6, 0xfb, 0x02, 0xac, 0xf2, 0xfe,
0xb3, 0x01, 0xd5, 0xf1, 0x60, 0xd4, 0x1f, 0x8e, 0x0e, 0x5b, 0x2b, 0x08, 0xe8, 0x67, 0xa3, 0x11,
0x02, 0x05, 0xb2, 0x0e, 0xf5, 0xd3, 0xb3, 0x5e, 0x6f, 0x30, 0xe8, 0x0f, 0xfa, 0xad, 0x22, 0x01,
0xa8, 0x7c, 0xd1, 0x1d, 0x1e, 0x0d, 0xfa, 0xad, 0x12, 0xd2, 0x9d, 0x8d, 0x7e, 0x3e, 0x3a, 0xf9,
0xc5, 0xa8, 0xb5, 0x4a, 0x9a, 0x00, 0x93, 0xc1, 0xf1, 0x70, 0xd4, 0x9d, 0x20, 0x5f, 0x99, 0xac,
0x41, 0xad, 0xfb, 0x72, 0x74, 0xa2, 0x1f, 0x77, 0x8f, 0x5a, 0x15, 0x5c, 0x1d, 0x8e, 0x86, 0x93,
0xa1, 0x58, 0xad, 0x22, 0x7c, 0xda, 0x7b, 0x35, 0xe8, 0x9f, 0x1d, 0x21, 0x5c, 0x43, 0xea, 0xd1,
0xc9, 0x44, 0x1f, 0x74, 0xfb, 0x5f, 0xb5, 0xea, 0x28, 0xf3, 0x6c, 0xf4, 0x6a, 0xd0, 0x3d, 0x9a,
0xbc, 0xfa, 0xaa, 0x05, 0xda, 0xdf, 0x0b, 0xb0, 0x36, 0xf6, 0xcc, 0xa4, 0x3b, 0xdc, 0x86, 0xb2,
0xe5, 0xa0, 0x05, 0xe4, 0xa3, 0x93, 0x03, 0x88, 0xe5, 0x7d, 0x58, 0x54, 0x70, 0x38, 0xa0, 0xd8,
0xb1, 0x94, 0xb5, 0x23, 0xef, 0xb9, 0xa8, 0x19, 0x35, 0xdc, 0x12, 0xc4, 0x32, 0xc1, 0xeb, 0xc3,
0x54, 0x14, 0x06, 0x69, 0xb3, 0x06, 0xc7, 0x1d, 0x73, 0x14, 0x86, 0xbe, 0x20, 0x99, 0xb1, 0xb9,
0xec, 0xbd, 0x6b, 0x1c, 0xd1, 0x63, 0x73, 0xac, 0x46, 0xb2, 0x0c, 0x45, 0x3b, 0x54, 0x45, 0xef,
0x2a, 0xb1, 0x72, 0x8f, 0x1b, 0xd8, 0xce, 0x08, 0x32, 0xdc, 0xa5, 0x26, 0xfa, 0x44, 0x89, 0xea,
0xb1, 0xb9, 0xf6, 0x37, 0x11, 0x37, 0x22, 0xb2, 0x31, 0x3a, 0x95, 0x3e, 0x98, 0x7f, 0x73, 0x9c,
0x67, 0x46, 0x07, 0xe6, 0xdf, 0x99, 0xee, 0xb2, 0x94, 0xed, 0x2e, 0x6f, 0xc7, 0x97, 0x79, 0x35,
0xe9, 0xc7, 0xe3, 0x00, 0x8c, 0xef, 0xb6, 0xc8, 0x0b, 0xe5, 0x38, 0x2f, 0xec, 0x41, 0x15, 0x77,
0xc7, 0x57, 0x88, 0x38, 0x6e, 0x05, 0xc1, 0x21, 0x43, 0x33, 0x5e, 0x52, 0x3f, 0xb0, 0x3c, 0x57,
0x9e, 0x32, 0x02, 0xc9, 0x53, 0xd8, 0xb0, 0x5c, 0x34, 0x51, 0xf2, 0x0c, 0x11, 0xad, 0x62, 0x4b,
0x8a, 0x4c, 0x5e, 0x01, 0x4d, 0x24, 0x4c, 0x9e, 0x12, 0xe4, 0x41, 0xea, 0xf1, 0x52, 0xbf, 0x82,
0x4b, 0x7d, 0xab, 0xdc, 0x82, 0x0a, 0xc5, 0x4b, 0x1c, 0xc8, 0xb6, 0x70, 0x4d, 0x52, 0xf3, 0x9b,
0xad, 0xcb, 0x35, 0xed, 0x39, 0x34, 0x4f, 0x43, 0xcf, 0x37, 0x2e, 0x68, 0xcf, 0x36, 0x78, 0x4f,
0x79, 0x0f, 0x56, 0x6d, 0x8b, 0x37, 0x1c, 0x71, 0x42, 0x52, 0x29, 0x64, 0x56, 0xe1, 0x34, 0xda,
0x1f, 0x4a, 0x40, 0x96, 0x17, 0x73, 0x1d, 0x73, 0x13, 0x1a, 0xcc, 0xf7, 0x2e, 0x2d, 0x34, 0x04,
0xf5, 0xa5, 0x7f, 0x54, 0x14, 0xf9, 0x02, 0x80, 0x19, 0xbe, 0xe1, 0xd0, 0x10, 0x8f, 0x58, 0xe2,
0xe2, 0xef, 0xe4, 0x8b, 0xdf, 0x1f, 0xc7, 0x84, 0xf2, 0x91, 0x96, 0x70, 0x8a, 0x60, 0x9b, 0xd9,
0x86, 0xe5, 0x4c, 0x99, 0x67, 0x5b, 0xb3, 0x85, 0x8c, 0xe6, 0x75, 0x89, 0x1d, 0x73, 0x24, 0xf9,
0x0c, 0x76, 0x0d, 0xdb, 0xf6, 0xbe, 0x95, 0xaf, 0xb9, 0x29, 0xfd, 0x35, 0x33, 0x5c, 0xee, 0x35,
0x51, 0xb5, 0xb6, 0xf9, 0xaa, 0x78, 0xd8, 0x0d, 0xa2, 0x35, 0xb2, 0x0f, 0x5b, 0x92, 0xfe, 0xdc,
0x72, 0x4d, 0xec, 0x5c, 0x1c, 0x0c, 0x37, 0x11, 0x01, 0x9b, 0x62, 0xe9, 0xa5, 0x58, 0x39, 0xc6,
0xd8, 0x3b, 0x04, 0xc2, 0xf7, 0xa1, 0xe6, 0x34, 0xf4, 0x98, 0x67, 0x7b, 0x17, 0x16, 0x8d, 0xde,
0x16, 0xfc, 0x21, 0x33, 0x11, 0xd8, 0xc5, 0x29, 0xb5, 0xe9, 0x2c, 0xf4, 0xfc, 0x09, 0xf5, 0x1d,
0x5c, 0xab, 0x42, 0xb9, 0xef, 0xb0, 0x70, 0xa1, 0xdd, 0x84, 0x4a, 0x97, 0x31, 0x9d, 0x7e, 0x43,
0x76, 0xa0, 0x82, 0x2c, 0x96, 0xd9, 0x2e, 0xdc, 0x2a, 0xdc, 0xab, 0xeb, 0x65, 0x83, 0xb1, 0x81,
0xa9, 0xdd, 0x81, 0xb5, 0x2e, 0x63, 0xe3, 0xd0, 0x08, 0xe7, 0xc1, 0x5b, 0xc8, 0x3e, 0x81, 0xe6,
0x98, 0xfa, 0x97, 0xd6, 0x8c, 0xea, 0xf4, 0x9b, 0x39, 0x0d, 0x42, 0x72, 0x1d, 0x20, 0x10, 0x98,
0x84, 0xb8, 0x2e, 0x31, 0x03, 0x53, 0x3b, 0x80, 0x0d, 0xc9, 0x10, 0x44, 0x1c, 0x37, 0xa1, 0x91,
0x70, 0x04, 0x92, 0x05, 0x62, 0x96, 0x40, 0xfb, 0x18, 0xd6, 0x27, 0xd4, 0x35, 0xdc, 0x30, 0xe2,
0xb8, 0x06, 0xf5, 0x90, 0x23, 0x12, 0x11, 0x35, 0x81, 0x18, 0x98, 0xda, 0x6f, 0x0a, 0xb0, 0x2e,
0xf4, 0x3e, 0xa1, 0x41, 0x60, 0x5c, 0x50, 0xf2, 0x18, 0x2a, 0x01, 0x47, 0xb4, 0x0b, 0xb7, 0x4a,
0xf7, 0x1a, 0x07, 0xd7, 0xf7, 0xd9, 0xf9, 0x7e, 0x8a, 0x44, 0x42, 0x7d, 0x37, 0xf4, 0x17, 0xba,
0x24, 0xee, 0x3c, 0x83, 0x86, 0x82, 0x26, 0x2d, 0x28, 0xbd, 0xa1, 0x0b, 0x29, 0x0e, 0x3f, 0xc9,
0x36, 0x94, 0x2f, 0x0d, 0x7b, 0x4e, 0xdb, 0x45, 0x61, 0x12, 0x0e, 0x3c, 0x2f, 0x3e, 0x2d, 0x68,
0x0b, 0x68, 0xf4, 0xac, 0xe0, 0x4d, 0xa4, 0xc0, 0x43, 0x28, 0x9b, 0x56, 0xf0, 0x26, 0x92, 0xdf,
0x41, 0xf9, 0xca, 0x3a, 0xff, 0x96, 0xc2, 0x05, 0x61, 0xe7, 0x29, 0x40, 0x82, 0x7c, 0x97, 0xe8,
0x82, 0x2a, 0xda, 0x81, 0x4d, 0x69, 0xe0, 0x2e, 0x63, 0x23, 0xcf, 0x3c, 0xb6, 0x82, 0x90, 0x3c,
0x80, 0xaa, 0x67, 0x9b, 0x23, 0xcf, 0x8c, 0x54, 0xd8, 0xe4, 0x26, 0x50, 0xe9, 0xf4, 0x88, 0x02,
0x89, 0x5d, 0xfa, 0x2d, 0x27, 0x2e, 0x5e, 0x49, 0x2c, 0x29, 0xb4, 0xef, 0x0a, 0xb0, 0x7b, 0x32,
0xb7, 0x43, 0x6b, 0x59, 0xe8, 0x49, 0xec, 0x57, 0x45, 0xf0, 0x03, 0xdc, 0x2b, 0x9f, 0x21, 0x12,
0x81, 0xd4, 0xc2, 0x18, 0x2a, 0x7f, 0xe7, 0x0c, 0x5a, 0x59, 0x82, 0x1c, 0xc3, 0x3c, 0x50, 0x0d,
0xd3, 0x38, 0xd8, 0x59, 0x52, 0x1d, 0x25, 0xa9, 0xf6, 0xfa, 0xbe, 0x08, 0xeb, 0x29, 0x82, 0x77,
0x44, 0x30, 0x06, 0x9f, 0x49, 0x99, 0xed, 0x2d, 0x70, 0x55, 0x78, 0xbe, 0x26, 0x10, 0x03, 0x13,
0x63, 0x59, 0x2e, 0x86, 0x0b, 0x46, 0xdb, 0x25, 0x11, 0xcb, 0x02, 0x35, 0x59, 0x30, 0x4a, 0x3e,
0x80, 0x1a, 0xf3, 0xcc, 0xa9, 0x6b, 0x38, 0xb4, 0xbd, 0xca, 0x57, 0xab, 0xcc, 0x33, 0x87, 0x86,
0x43, 0xf1, 0x8a, 0xe1, 0x92, 0xc5, 0xda, 0x65, 0x11, 0x4f, 0xcc, 0x33, 0x07, 0x0c, 0xd5, 0x41,
0xb4, 0x8c, 0xe0, 0x8a, 0x50, 0x87, 0x79, 0xa6, 0x88, 0x4d, 0xd2, 0x05, 0x98, 0x79, 0x6e, 0x68,
0x58, 0x2e, 0xf5, 0x83, 0x76, 0x95, 0x1b, 0xf9, 0xa3, 0xa5, 0x53, 0xef, 0x1f, 0xc6, 0x34, 0xc2,
0xb4, 0x0a, 0x13, 0x2a, 0x8d, 0x12, 0x2e, 0x3d, 0x7b, 0xee, 0xd0, 0xa0, 0x5d, 0xbb, 0x55, 0x42,
0xa5, 0x99, 0x67, 0x7e, 0x29, 0x30, 0x9d, 0x63, 0xd8, 0xc8, 0xf0, 0xe7, 0x58, 0xfe, 0x07, 0x69,
0xcb, 0xaf, 0xa3, 0x0e, 0x31, 0x97, 0x6a, 0xf1, 0x4b, 0xa8, 0xc7, 0x78, 0x72, 0x07, 0x9a, 0xb1,
0x26, 0xc2, 0x2a, 0x62, 0xcb, 0xf5, 0x18, 0xcb, 0x6d, 0xf3, 0x11, 0xac, 0x39, 0xd4, 0xf1, 0xfc,
0xc5, 0xd4, 0xb6, 0x1c, 0x2b, 0xe4, 0x32, 0x4a, 0x7a, 0x43, 0xe0, 0x8e, 0x11, 0x85, 0xa7, 0x98,
0xb1, 0xf9, 0xd4, 0x17, 0x39, 0x82, 0x9b, 0xbe, 0xa4, 0xc3, 0x8c, 0xcd, 0x65, 0xd6, 0xd0, 0xbe,
0xaf, 0x00, 0xf4, 0x84, 0xa3, 0xdc, 0xaf, 0x3d, 0xf2, 0x21, 0xd4, 0x51, 0x5e, 0xc0, 0x8c, 0x59,
0x24, 0x34, 0x41, 0x10, 0x0d, 0xd6, 0xd0, 0xe2, 0xf4, 0xeb, 0xb9, 0x4d, 0x03, 0x1a, 0x4a, 0x47,
0xa7, 0x70, 0xe4, 0x06, 0x48, 0xcf, 0x3a, 0xd4, 0x0d, 0xd3, 0xbe, 0x46, 0x0c, 0x0f, 0xa4, 0xd0,
0xf0, 0xc3, 0x29, 0x26, 0x63, 0xe9, 0xed, 0x3a, 0xc7, 0x4c, 0x2c, 0x87, 0x92, 0x8f, 0x61, 0x95,
0xe1, 0xc5, 0x28, 0x73, 0x9f, 0xb5, 0x79, 0x52, 0x88, 0xd5, 0xdb, 0x4f, 0x6e, 0x01, 0xa7, 0x22,
0x4f, 0xa1, 0x26, 0x63, 0x10, 0x83, 0x00, 0x39, 0x3e, 0xcc, 0x70, 0x44, 0x79, 0x55, 0x70, 0xc5,
0xd4, 0xe4, 0x33, 0xa8, 0x53, 0xd7, 0x64, 0x9e, 0xe5, 0x86, 0x51, 0x80, 0x5c, 0xcf, 0xb0, 0xf6,
0xa3, 0x75, 0xc1, 0x9b, 0xd0, 0x93, 0xc7, 0x50, 0x0d, 0xe8, 0xcc, 0xa7, 0xa1, 0x88, 0x8b, 0xc6,
0xc1, 0xb5, 0x25, 0xa9, 0x7c, 0x55, 0x30, 0x46, 0xb4, 0x28, 0xd3, 0x72, 0x2f, 0x7c, 0x1a, 0x04,
0x34, 0x68, 0xd7, 0x73, 0x65, 0x0e, 0xa2, 0x75, 0x29, 0x33, 0xa6, 0x27, 0x5d, 0x68, 0xf8, 0x94,
0xd9, 0xd6, 0xcc, 0x08, 0xd1, 0xf4, 0xc0, 0xd9, 0x6f, 0x66, 0xd8, 0xf5, 0x84, 0x42, 0x26, 0x0b,
0x85, 0x87, 0xec, 0xc6, 0x29, 0xbf, 0xc1, 0xcd, 0x1e, 0xe5, 0xf4, 0x27, 0x50, 0x7f, 0x5b, 0xf6,
0xb8, 0x32, 0xa3, 0x77, 0x3e, 0x8b, 0xb3, 0xc4, 0x7f, 0xc0, 0xfc, 0x02, 0x9a, 0x69, 0x0b, 0xbf,
0x17, 0xf7, 0x73, 0x58, 0x53, 0x8d, 0xfc, 0xbe, 0x92, 0xd3, 0x76, 0x7e, 0x2f, 0xee, 0xcf, 0xa1,
0x95, 0x35, 0xf3, 0x7b, 0x95, 0xc1, 0x3f, 0x17, 0xa1, 0x19, 0x55, 0xee, 0xc0, 0x9b, 0xfb, 0x33,
0x9a, 0xbd, 0xa5, 0x85, 0xec, 0x2d, 0xc5, 0xf4, 0x8a, 0x04, 0xea, 0x35, 0xaf, 0xcd, 0xd8, 0x5c,
0xdc, 0xf1, 0x3b, 0xd0, 0x94, 0x69, 0x20, 0x7d, 0xcd, 0xd7, 0x05, 0x36, 0xda, 0x23, 0x9b, 0x2d,
0x56, 0x97, 0xb3, 0xc5, 0x5d, 0xd8, 0xf0, 0xe7, 0xae, 0x6b, 0xb9, 0x17, 0x53, 0xec, 0x6b, 0xdc,
0xb9, 0xc3, 0xb3, 0x6e, 0x49, 0x5f, 0x97, 0xe8, 0x2e, 0x63, 0xc3, 0xb9, 0x43, 0x1e, 0xc1, 0x8e,
0x4a, 0x17, 0xbe, 0xb6, 0x7c, 0x93, 0x53, 0x03, 0xa7, 0x26, 0x09, 0xf5, 0x04, 0x97, 0x90, 0xe5,
0x09, 0xb4, 0x55, 0x16, 0xcb, 0x0d, 0xa9, 0xef, 0x1a, 0x36, 0xe7, 0x6a, 0x70, 0xae, 0x9d, 0x84,
0x6b, 0x20, 0x57, 0x87, 0x73, 0x47, 0xfb, 0x53, 0x01, 0x48, 0xda, 0x5c, 0xbc, 0x8e, 0x1e, 0x42,
0xdd, 0x97, 0x70, 0x54, 0x45, 0xef, 0xe0, 0x65, 0x58, 0x26, 0xdd, 0x8f, 0x80, 0xe8, 0x4e, 0xc5,
0x7c, 0x9d, 0x11, 0x34, 0xd3, 0x8b, 0x39, 0x8e, 0xbc, 0x97, 0xce, 0xe0, 0x64, 0x59, 0x88, 0xea,
0xdc, 0xdf, 0x16, 0xe0, 0x83, 0xae, 0x69, 0xf2, 0x63, 0x8f, 0x0c, 0x3f, 0x5c, 0xc4, 0x21, 0x8e,
0xfd, 0x22, 0x81, 0xd5, 0xf9, 0x3c, 0x2e, 0x9f, 0xfc, 0x1b, 0x25, 0x06, 0x71, 0xcd, 0xc4, 0x4f,
0xd2, 0x84, 0xa2, 0xc5, 0x64, 0xe6, 0x2c, 0x5a, 0x0c, 0xb9, 0x98, 0xe7, 0x0b, 0x87, 0x95, 0x75,
0xfe, 0x8d, 0x01, 0x61, 0x05, 0x53, 0xcf, 0xb5, 0x2d, 0x97, 0x72, 0x1f, 0xd5, 0xf4, 0x9a, 0x15,
0x9c, 0x72, 0x98, 0x2b, 0x71, 0xc6, 0xfe, 0xcf, 0x4a, 0x50, 0xf8, 0xa0, 0x47, 0xed, 0xff, 0xb5,
0x0e, 0xda, 0xef, 0x30, 0x3c, 0x96, 0x84, 0xfc, 0x17, 0x0f, 0x99, 0x24, 0xcd, 0xb2, 0x9a, 0x34,
0xd3, 0x87, 0xaf, 0x64, 0x0e, 0xff, 0x53, 0xd8, 0xca, 0x39, 0x39, 0xb9, 0x07, 0x25, 0xef, 0xfc,
0x57, 0x32, 0x5c, 0x77, 0x79, 0x24, 0x2d, 0x51, 0xe9, 0x48, 0xa2, 0xdd, 0x86, 0x16, 0xc6, 0x2e,
0xa6, 0xe5, 0x97, 0x8b, 0xf1, 0xa0, 0x87, 0x46, 0x93, 0xfa, 0x17, 0x62, 0xfd, 0xb5, 0xcf, 0x61,
0xe3, 0x88, 0x22, 0x51, 0x8f, 0x86, 0x86, 0x65, 0xe7, 0x12, 0xa5, 0x9a, 0xab, 0x62, 0xaa, 0xb9,
0xd2, 0xce, 0xa1, 0x36, 0xf2, 0xcc, 0xfe, 0x25, 0x15, 0x16, 0xe3, 0xdd, 0x99, 0xb4, 0x18, 0x7e,
0xe3, 0xd9, 0x7d, 0x6a, 0x04, 0x9e, 0x2b, 0x19, 0x25, 0x84, 0x42, 0x8c, 0x8b, 0xa8, 0x91, 0xc3,
0x4f, 0xd2, 0x86, 0xaa, 0x23, 0xfa, 0x76, 0x69, 0xa6, 0x08, 0xd4, 0xbe, 0x2b, 0xf2, 0xea, 0x22,
0x1b, 0xb3, 0xbb, 0x8a, 0x94, 0xa6, 0xb8, 0x4c, 0xf1, 0xe2, 0x3e, 0xf6, 0x82, 0xef, 0x90, 0xac,
0xc8, 0x29, 0xa5, 0xe4, 0x20, 0x87, 0x61, 0x62, 0x29, 0x92, 0x3d, 0x85, 0x84, 0xf0, 0xf8, 0xb8,
0xe3, 0x34, 0x08, 0xfd, 0x48, 0x35, 0x84, 0xc7, 0xa1, 0xaf, 0xfd, 0xa1, 0x00, 0xab, 0xbc, 0xff,
0x6c, 0x40, 0x75, 0xd4, 0x1f, 0xf6, 0x06, 0xc3, 0xa3, 0xd6, 0x0a, 0x02, 0xfa, 0xd9, 0x70, 0x88,
0x40, 0x81, 0xac, 0x43, 0x7d, 0x7c, 0x76, 0x78, 0xd8, 0xef, 0xf7, 0xfa, 0xbd, 0x56, 0x91, 0x00,
0x54, 0xbe, 0xe8, 0x0e, 0x8e, 0xfb, 0xbd, 0x56, 0x09, 0xe9, 0xce, 0x86, 0x3f, 0x1f, 0x9e, 0xfe,
0x62, 0xd8, 0x5a, 0x25, 0x4d, 0x80, 0x49, 0xff, 0x64, 0x30, 0xec, 0x4e, 0x90, 0xaf, 0x4c, 0xd6,
0xa0, 0xd6, 0x7d, 0x39, 0x3c, 0xd5, 0x4f, 0xba, 0xc7, 0xad, 0x0a, 0xae, 0x0e, 0x86, 0x83, 0xc9,
0x40, 0xac, 0x56, 0x11, 0x1e, 0x1f, 0xbe, 0xea, 0xf7, 0xce, 0x8e, 0x11, 0xae, 0x21, 0xf5, 0xf0,
0x74, 0xa2, 0xf7, 0xbb, 0xbd, 0xaf, 0x5a, 0x75, 0x94, 0x79, 0x36, 0x7c, 0xd5, 0xef, 0x1e, 0x4f,
0x5e, 0x7d, 0xd5, 0x02, 0xed, 0x9f, 0x05, 0x58, 0x1b, 0x79, 0x66, 0xd2, 0x1d, 0x6e, 0x43, 0xd9,
0x72, 0xd0, 0x02, 0xf2, 0xd1, 0xc9, 0x01, 0xc4, 0xf2, 0x3e, 0x2c, 0x2a, 0x38, 0x1c, 0x50, 0xec,
0x58, 0xca, 0xda, 0x91, 0xf7, 0x5c, 0xd4, 0x8c, 0x1a, 0x6e, 0x09, 0x62, 0x99, 0xe0, 0xf5, 0x61,
0x2a, 0x0a, 0x83, 0xb4, 0x59, 0x83, 0xe3, 0x4e, 0x38, 0x0a, 0x43, 0x5f, 0x90, 0xcc, 0xd8, 0x5c,
0xf6, 0xde, 0x35, 0x8e, 0x38, 0x64, 0x73, 0xac, 0x46, 0xb2, 0x0c, 0x45, 0x3b, 0x54, 0x45, 0xef,
0x2a, 0xb1, 0x72, 0x8f, 0x9b, 0xd8, 0xce, 0x08, 0x32, 0xdc, 0xa5, 0x26, 0xfa, 0x44, 0x89, 0x3a,
0x64, 0x73, 0xed, 0x1f, 0x22, 0x6e, 0x44, 0x64, 0x63, 0x74, 0x2a, 0x7d, 0x30, 0xff, 0xe6, 0x38,
0xcf, 0x8c, 0x0e, 0xcc, 0xbf, 0x33, 0xdd, 0x65, 0x29, 0xdb, 0x5d, 0xde, 0x89, 0x2f, 0xf3, 0x6a,
0xd2, 0x8f, 0xc7, 0x01, 0x18, 0xdf, 0x6d, 0x91, 0x17, 0xca, 0x71, 0x5e, 0xd8, 0x83, 0x2a, 0xee,
0x8e, 0xaf, 0x10, 0x71, 0xdc, 0x0a, 0x82, 0x03, 0x86, 0x66, 0xbc, 0xa4, 0x7e, 0x60, 0x79, 0xae,
0x3c, 0x65, 0x04, 0x92, 0x67, 0xb0, 0x61, 0xb9, 0x68, 0xa2, 0xe4, 0x19, 0x22, 0x5a, 0xc5, 0x96,
0x14, 0x99, 0xbc, 0x02, 0x9a, 0x48, 0x98, 0x3c, 0x25, 0xc8, 0xc3, 0xd4, 0xe3, 0xa5, 0x7e, 0x05,
0x97, 0xfa, 0x56, 0xb9, 0x0d, 0x15, 0x8a, 0x97, 0x38, 0x90, 0x6d, 0xe1, 0x9a, 0xa4, 0xe6, 0x37,
0x5b, 0x97, 0x6b, 0xda, 0x0b, 0x68, 0x8e, 0x43, 0xcf, 0x37, 0x2e, 0xe8, 0xa1, 0x6d, 0xf0, 0x9e,
0xf2, 0x3e, 0xac, 0xda, 0x16, 0x6f, 0x38, 0xe2, 0x84, 0xa4, 0x52, 0xc8, 0xac, 0xc2, 0x69, 0xb4,
0x3f, 0x96, 0x80, 0x2c, 0x2f, 0xe6, 0x3a, 0xe6, 0x16, 0x34, 0x98, 0xef, 0x5d, 0x5a, 0x68, 0x08,
0xea, 0x4b, 0xff, 0xa8, 0x28, 0xf2, 0x05, 0x00, 0x33, 0x7c, 0xc3, 0xa1, 0x21, 0x1e, 0xb1, 0xc4,
0xc5, 0xdf, 0xcd, 0x17, 0xbf, 0x3f, 0x8a, 0x09, 0xe5, 0x23, 0x2d, 0xe1, 0x14, 0xc1, 0x36, 0xb3,
0x0d, 0xcb, 0x99, 0x32, 0xcf, 0xb6, 0x66, 0x0b, 0x19, 0xcd, 0xeb, 0x12, 0x3b, 0xe2, 0x48, 0xf2,
0x29, 0xec, 0x1a, 0xb6, 0xed, 0x7d, 0x2b, 0x5f, 0x73, 0x53, 0xfa, 0x6b, 0x66, 0xb8, 0xdc, 0x6b,
0xa2, 0x6a, 0x6d, 0xf3, 0x55, 0xf1, 0xb0, 0xeb, 0x47, 0x6b, 0x64, 0x1f, 0xb6, 0x24, 0xfd, 0xb9,
0xe5, 0x9a, 0xd8, 0xb9, 0x38, 0x18, 0x6e, 0x22, 0x02, 0x36, 0xc5, 0xd2, 0x4b, 0xb1, 0x72, 0x82,
0xb1, 0x77, 0x04, 0x84, 0xef, 0x43, 0xcd, 0x69, 0xe8, 0x31, 0xcf, 0xf6, 0x2e, 0x2c, 0x1a, 0xbd,
0x2d, 0xf8, 0x43, 0x66, 0x22, 0xb0, 0x8b, 0x31, 0xb5, 0xe9, 0x2c, 0xf4, 0xfc, 0x09, 0xf5, 0x1d,
0x7d, 0x53, 0xf2, 0x4c, 0x62, 0x96, 0xce, 0x4f, 0x60, 0x23, 0x73, 0xe8, 0xf7, 0x6a, 0x30, 0x43,
0xd8, 0xce, 0x93, 0x44, 0x7e, 0x09, 0x7b, 0x8e, 0x11, 0xce, 0x5e, 0x4f, 0x6d, 0xe3, 0x9c, 0xda,
0x68, 0x04, 0x6c, 0x81, 0x2d, 0xcf, 0x8d, 0x1a, 0xa8, 0x5b, 0x79, 0x4a, 0x1e, 0x21, 0x31, 0xf6,
0x90, 0x96, 0x4f, 0xf1, 0x01, 0xa7, 0xef, 0xf0, 0x4d, 0x38, 0x7a, 0x90, 0x6c, 0xa1, 0x1d, 0xc1,
0xcd, 0x77, 0xb1, 0xe6, 0x9c, 0x62, 0x17, 0x2a, 0x5c, 0x71, 0x31, 0x55, 0xa9, 0xeb, 0x12, 0xd2,
0xfe, 0x5c, 0x80, 0x8e, 0x7c, 0x5a, 0x08, 0xb7, 0xa4, 0x87, 0x57, 0x2f, 0x33, 0xc3, 0xab, 0x7b,
0x68, 0x04, 0x6c, 0x81, 0x2d, 0xcf, 0x8d, 0x1a, 0xa8, 0xdb, 0x79, 0x4a, 0x1e, 0x23, 0x31, 0xf6,
0x90, 0x96, 0x4f, 0xf1, 0x01, 0xa7, 0xef, 0xf0, 0x4d, 0x38, 0xba, 0x9f, 0x6c, 0xa1, 0x1d, 0xc3,
0xad, 0x77, 0xb1, 0xe6, 0x9c, 0x62, 0x17, 0x2a, 0x5c, 0x71, 0x31, 0x55, 0xa9, 0xeb, 0x12, 0xd2,
0xfe, 0x52, 0x80, 0x8e, 0x7c, 0x5a, 0x08, 0xb7, 0xa4, 0x87, 0x57, 0x2f, 0x33, 0xc3, 0xab, 0xfb,
0xca, 0xdb, 0x3e, 0x87, 0x3e, 0x77, 0x92, 0xa5, 0xbf, 0x6b, 0x92, 0xf5, 0x43, 0xd5, 0xc2, 0xcd,
0x83, 0xbd, 0x2b, 0x64, 0xa8, 0xa6, 0xff, 0x67, 0x11, 0xea, 0xf1, 0x84, 0x50, 0x69, 0x1d, 0x0a,
0x83, 0xbd, 0x2b, 0x64, 0xa8, 0xa6, 0xff, 0x7d, 0x09, 0xea, 0xf1, 0x84, 0x50, 0x69, 0x1d, 0x0a,
0xa9, 0xd6, 0xa1, 0x05, 0x25, 0xcc, 0x79, 0xa2, 0x8f, 0xc7, 0x4f, 0xa4, 0x94, 0xc9, 0x52, 0xb4,
0xee, 0x12, 0x42, 0x27, 0xb3, 0xd7, 0x46, 0x10, 0xd5, 0x34, 0x01, 0x90, 0x3b, 0xd0, 0x14, 0x66,
0xee, 0x12, 0x42, 0x27, 0xb3, 0xd7, 0x46, 0x10, 0xd5, 0x34, 0x01, 0x90, 0xbb, 0xd0, 0x14, 0x66,
0x9a, 0x50, 0x87, 0xd9, 0x98, 0xf3, 0x45, 0xaa, 0xca, 0x60, 0x65, 0xf2, 0x37, 0x9d, 0x28, 0x66,
0x25, 0xc4, 0xf5, 0xa2, 0x61, 0x6f, 0x7c, 0xc6, 0x93, 0x56, 0x4d, 0x97, 0x10, 0x3e, 0xfe, 0x03,
0x2a, 0x13, 0x34, 0xcf, 0xc8, 0x35, 0x3d, 0x41, 0x28, 0xae, 0xaa, 0x8b, 0xdd, 0x04, 0xa4, 0xe6,
0x40, 0x48, 0xe7, 0xc0, 0x0e, 0xd4, 0x7c, 0x2a, 0xee, 0x3c, 0xef, 0xf1, 0xcb, 0x7a, 0x0c, 0x6b,
0x13, 0xa8, 0x48, 0x2b, 0x55, 0xa1, 0x34, 0x1a, 0x1e, 0x65, 0x0b, 0x2f, 0x40, 0xa5, 0x77, 0x74,
0x72, 0xca, 0xab, 0xae, 0x5a, 0x4c, 0x4b, 0x08, 0x9d, 0x4e, 0xba, 0x3a, 0x2f, 0xa5, 0xab, 0x02,
0x3a, 0x19, 0x8f, 0x79, 0xd9, 0xd5, 0x26, 0x40, 0xba, 0x8c, 0xf5, 0x69, 0x48, 0x67, 0x98, 0x51,
0x4d, 0x2b, 0x44, 0x3d, 0xf2, 0x5a, 0x9b, 0x6d, 0x28, 0xa3, 0x35, 0x16, 0xdc, 0x0b, 0x35, 0x5d,
0x00, 0x88, 0xa5, 0xbe, 0xef, 0xf9, 0xb2, 0x72, 0x08, 0x40, 0x3b, 0x86, 0xad, 0xe5, 0x5d, 0x03,
0xf2, 0x63, 0x9e, 0xa7, 0x25, 0xa4, 0xe6, 0xd0, 0x65, 0x62, 0x5d, 0xa1, 0xd4, 0xfe, 0x5a, 0x00,
0xc0, 0x20, 0x11, 0xa1, 0x94, 0x9b, 0x41, 0xdb, 0x50, 0x35, 0x4c, 0x13, 0xef, 0x56, 0xd4, 0xb2,
0x49, 0x10, 0x6d, 0x1a, 0xce, 0xd8, 0xd8, 0xf3, 0x43, 0x91, 0x37, 0xcb, 0x7a, 0x0c, 0xe3, 0xda,
0xdc, 0x94, 0x6b, 0xab, 0x62, 0x2d, 0x82, 0xb1, 0xf1, 0x52, 0xe6, 0x2a, 0x44, 0xaa, 0x29, 0x75,
0xc0, 0x5a, 0x21, 0x26, 0x2a, 0x9d, 0x87, 0x50, 0x1a, 0x7b, 0x66, 0xae, 0x52, 0x49, 0x38, 0x17,
0xd5, 0x70, 0xd6, 0x9e, 0x42, 0x23, 0xd9, 0x0a, 0x8b, 0x4a, 0x32, 0x93, 0x11, 0x46, 0x69, 0xa6,
0xa5, 0x25, 0x53, 0x18, 0xad, 0x07, 0x5b, 0x63, 0xc3, 0x0f, 0xa8, 0xc2, 0x8f, 0x4d, 0xec, 0x36,
0xf0, 0x49, 0x7a, 0x5f, 0x1d, 0xab, 0xf7, 0x53, 0xb9, 0x42, 0x09, 0x40, 0xed, 0x18, 0x36, 0x5e,
0x51, 0xdb, 0xe1, 0xa3, 0x7b, 0x9b, 0x1a, 0x58, 0xd8, 0x9e, 0x41, 0xf3, 0x75, 0x0a, 0x25, 0x35,
0xe1, 0xe7, 0x4e, 0x13, 0xeb, 0x19, 0x4a, 0xed, 0x2f, 0x05, 0x68, 0xa6, 0x49, 0x52, 0x81, 0x5c,
0x48, 0x07, 0x32, 0xba, 0x6a, 0xce, 0x4c, 0x03, 0x3b, 0x29, 0xe9, 0x2a, 0x09, 0x2a, 0xf6, 0x2a,
0xa5, 0xae, 0xff, 0x36, 0x94, 0x67, 0xaf, 0x0d, 0xf9, 0xcc, 0xa8, 0xeb, 0x02, 0x20, 0xd7, 0x01,
0x0c, 0xc6, 0xbe, 0x94, 0x37, 0x49, 0x5c, 0x68, 0x05, 0x83, 0x45, 0xd5, 0xa4, 0xc1, 0xcc, 0xb7,
0x18, 0x46, 0x91, 0xbc, 0xd1, 0x2a, 0xea, 0xde, 0xa7, 0xb0, 0x95, 0x93, 0x9e, 0x48, 0x1d, 0xca,
0xa2, 0xb3, 0x5c, 0xc1, 0xce, 0x72, 0x74, 0x32, 0x99, 0x0a, 0xb0, 0x70, 0xf0, 0x8f, 0x1a, 0x34,
0xf1, 0x94, 0xe2, 0xc7, 0xc8, 0xe9, 0xc2, 0x9d, 0x91, 0x97, 0xb0, 0x7b, 0x48, 0xc3, 0x38, 0x85,
0xf5, 0x29, 0xf3, 0xe9, 0x8c, 0x9f, 0x66, 0x4b, 0x49, 0x7f, 0xd1, 0x5f, 0x8a, 0xce, 0xe6, 0xd2,
0x4f, 0x03, 0x6d, 0x85, 0x3c, 0x84, 0x35, 0x75, 0x0f, 0xd2, 0x8a, 0xdc, 0x1f, 0xfd, 0x37, 0xe9,
0xac, 0xa7, 0x30, 0xda, 0x0a, 0x79, 0x0a, 0x20, 0x58, 0xf8, 0xac, 0x9d, 0x28, 0xa2, 0x22, 0x49,
0xf9, 0x33, 0x6b, 0x6d, 0x85, 0xf4, 0xf9, 0x1b, 0x88, 0x0f, 0xcf, 0x23, 0xfe, 0x5c, 0x55, 0x3b,
0x57, 0xcf, 0xd8, 0xb5, 0x15, 0xf2, 0x08, 0xd6, 0x0f, 0x69, 0xa8, 0x0c, 0x42, 0xf3, 0x74, 0x68,
0xa6, 0xa7, 0x6d, 0xda, 0x0a, 0x79, 0x0e, 0x9b, 0x87, 0x34, 0xcc, 0x4c, 0x73, 0x36, 0xd5, 0x11,
0x81, 0xe0, 0xcc, 0x99, 0x1a, 0xf0, 0x53, 0x93, 0x25, 0xee, 0x80, 0xd4, 0x91, 0x96, 0xff, 0x90,
0xea, 0xec, 0xe6, 0x4f, 0x34, 0xb4, 0x15, 0xf2, 0x0a, 0xf6, 0xf0, 0x2b, 0xef, 0x91, 0x99, 0xa7,
0xf9, 0x5e, 0xfe, 0x5b, 0x13, 0x4d, 0xdf, 0x83, 0x9d, 0xdc, 0x81, 0x05, 0xe1, 0xa3, 0xc9, 0x2b,
0x67, 0x19, 0x9d, 0x44, 0x4d, 0xb1, 0x49, 0xee, 0xc0, 0x41, 0x6c, 0x72, 0xe5, 0x2c, 0x62, 0x69,
0x93, 0xdc, 0x89, 0x01, 0x91, 0x43, 0x52, 0xfb, 0xdf, 0xd9, 0xe4, 0x33, 0x1e, 0x7c, 0xc9, 0xc3,
0x81, 0xc7, 0x42, 0xe6, 0x91, 0xdc, 0x89, 0xda, 0x7e, 0x81, 0xe1, 0x5c, 0xe8, 0xc7, 0x4c, 0x77,
0xac, 0x38, 0x82, 0x64, 0x7b, 0x53, 0x8a, 0xa6, 0xfb, 0x19, 0xf7, 0x5f, 0x97, 0xb1, 0xd4, 0x7d,
0xcb, 0xb3, 0xff, 0xf5, 0xb7, 0xf7, 0x27, 0x3c, 0x8c, 0x3f, 0x44, 0x87, 0xca, 0xc4, 0xb3, 0x54,
0x6b, 0x40, 0xde, 0x18, 0xd4, 0x7e, 0x2f, 0xbf, 0xc6, 0xa0, 0x46, 0x0f, 0x60, 0x03, 0x77, 0x51,
0xd3, 0xb1, 0xca, 0xb9, 0x91, 0x4e, 0xc4, 0xc8, 0xf1, 0x02, 0x5a, 0xd9, 0x0c, 0x4c, 0xb8, 0x80,
0x9c, 0xbc, 0x9c, 0xc7, 0xff, 0x18, 0x88, 0xa2, 0x77, 0x94, 0x30, 0x55, 0xa1, 0x5b, 0xcb, 0x39,
0x37, 0xd0, 0x56, 0xce, 0x2b, 0xfc, 0x07, 0xec, 0x8f, 0xfe, 0x15, 0x00, 0x00, 0xff, 0xff, 0x71,
0xdb, 0x30, 0xf5, 0x9c, 0x1d, 0x00, 0x00,
0x25, 0xc4, 0xf5, 0xa2, 0xe1, 0xe1, 0xe8, 0x8c, 0x27, 0xad, 0x9a, 0x2e, 0x21, 0x7c, 0xfc, 0x07,
0x54, 0x26, 0x68, 0x9e, 0x91, 0x6b, 0x7a, 0x82, 0x50, 0x5c, 0x55, 0x17, 0xbb, 0x09, 0x48, 0xcd,
0x81, 0x90, 0xce, 0x81, 0x1d, 0xa8, 0xf9, 0x54, 0xdc, 0x79, 0xde, 0xe3, 0x97, 0xf5, 0x18, 0x46,
0x59, 0xde, 0x25, 0xf5, 0x7d, 0xcb, 0xa4, 0x41, 0x7b, 0x8d, 0xfb, 0x3e, 0x41, 0x68, 0x13, 0xa8,
0x48, 0x1b, 0x56, 0xa1, 0x34, 0x1c, 0x1c, 0x67, 0xcb, 0x32, 0x40, 0xe5, 0xf0, 0xf8, 0x74, 0xcc,
0x6b, 0xb2, 0x5a, 0x6a, 0x4b, 0x08, 0x8d, 0x27, 0x5d, 0x9d, 0x17, 0xda, 0x55, 0x01, 0x9d, 0x8e,
0x46, 0xbc, 0x28, 0x6b, 0x13, 0x20, 0x5d, 0xc6, 0x7a, 0x34, 0xa4, 0x33, 0xcc, 0xb7, 0xa6, 0x15,
0xa2, 0x26, 0x79, 0x8d, 0xcf, 0x36, 0x94, 0xd1, 0x56, 0x0b, 0xee, 0xa3, 0x9a, 0x2e, 0x00, 0xc4,
0x52, 0xdf, 0xf7, 0x7c, 0x59, 0x57, 0x04, 0xa0, 0x9d, 0xc0, 0xd6, 0xf2, 0xae, 0x01, 0xf9, 0x31,
0xcf, 0xe2, 0x12, 0x52, 0x33, 0xec, 0x32, 0xb1, 0xae, 0x50, 0x6a, 0x7f, 0x2f, 0x00, 0x60, 0x08,
0x89, 0x40, 0xcb, 0xcd, 0xaf, 0x6d, 0xa8, 0x1a, 0xa6, 0x89, 0x37, 0x2f, 0x6a, 0xe8, 0x24, 0x88,
0x16, 0x0f, 0x67, 0x6c, 0xe4, 0xf9, 0xa1, 0xc8, 0xaa, 0x65, 0x3d, 0x86, 0x71, 0x6d, 0x6e, 0xca,
0xb5, 0x55, 0xb1, 0x16, 0xc1, 0xd8, 0x96, 0x29, 0x53, 0x17, 0x22, 0xd5, 0x94, 0x3a, 0x60, 0x25,
0x11, 0xf3, 0x96, 0xce, 0x23, 0x28, 0x8d, 0x3c, 0x33, 0x57, 0xa9, 0x24, 0xd8, 0x8b, 0x6a, 0xb0,
0x6b, 0xcf, 0xa0, 0x91, 0x6c, 0x85, 0x25, 0x27, 0x99, 0xd8, 0x08, 0xa3, 0x34, 0xd3, 0xd2, 0x92,
0x19, 0x8d, 0x76, 0x02, 0x1b, 0xaf, 0xa8, 0xed, 0xf0, 0x99, 0xbc, 0x4d, 0x0d, 0xac, 0x58, 0xcf,
0xa1, 0xf9, 0x3a, 0x85, 0x92, 0x9b, 0x70, 0x95, 0xd3, 0xc4, 0x7a, 0x86, 0x52, 0xfb, 0x6b, 0x01,
0x9a, 0x69, 0x92, 0x54, 0x84, 0x16, 0x32, 0x11, 0xda, 0x86, 0xea, 0x9c, 0x99, 0x06, 0xb6, 0x48,
0xd2, 0xca, 0x12, 0x54, 0x8e, 0x5a, 0x4a, 0xdd, 0xeb, 0x6d, 0x28, 0xcf, 0x5e, 0x1b, 0xf2, 0xfd,
0x50, 0xd7, 0x05, 0x40, 0x6e, 0x00, 0x18, 0x8c, 0x7d, 0x29, 0xaf, 0x88, 0xb8, 0xa9, 0x0a, 0x06,
0xab, 0xa5, 0x49, 0x83, 0x99, 0x6f, 0x31, 0x0c, 0x00, 0x79, 0x55, 0x55, 0xd4, 0xfd, 0x4f, 0x60,
0x2b, 0x27, 0xef, 0x90, 0x3a, 0x94, 0x45, 0xcb, 0xb8, 0x82, 0x2d, 0xe3, 0xf0, 0x74, 0x32, 0x15,
0x60, 0xe1, 0xe0, 0x6f, 0x35, 0x68, 0xe2, 0x29, 0xc5, 0x1f, 0x8f, 0xf1, 0xc2, 0x9d, 0x91, 0x97,
0xb0, 0x7b, 0x44, 0xc3, 0x38, 0x37, 0xf5, 0x28, 0xf3, 0xe9, 0x8c, 0x9f, 0x66, 0x4b, 0xc9, 0x6b,
0xd1, 0xef, 0x87, 0xce, 0xe6, 0xd2, 0xdf, 0x00, 0x6d, 0x85, 0x3c, 0x82, 0x35, 0x75, 0x0f, 0xd2,
0x8a, 0x3c, 0x17, 0xfd, 0x10, 0xe9, 0xac, 0xa7, 0x30, 0xda, 0x0a, 0x79, 0x06, 0x20, 0x58, 0xf8,
0x10, 0x9d, 0x28, 0xa2, 0x22, 0x49, 0xf9, 0xc3, 0x68, 0x6d, 0x85, 0xf4, 0xf8, 0xe3, 0x86, 0x4f,
0xc5, 0x23, 0xfe, 0x5c, 0x55, 0x3b, 0x57, 0x0f, 0xcf, 0xb5, 0x15, 0xf2, 0x18, 0xd6, 0x8f, 0x68,
0xa8, 0x4c, 0x38, 0xf3, 0x74, 0x68, 0xa6, 0xc7, 0x68, 0xda, 0x0a, 0x79, 0x01, 0x9b, 0x47, 0x34,
0xcc, 0x8c, 0x69, 0x36, 0xd5, 0xb7, 0xbf, 0xe0, 0xcc, 0x19, 0x07, 0xf0, 0x53, 0x93, 0x25, 0xee,
0x80, 0xd4, 0x91, 0x96, 0xff, 0x69, 0xea, 0xec, 0xe6, 0x8f, 0x2a, 0xb4, 0x15, 0xf2, 0x0a, 0xf6,
0xf0, 0x2b, 0xef, 0xf5, 0x98, 0xa7, 0xf9, 0x5e, 0xfe, 0x23, 0x12, 0x4d, 0x7f, 0x08, 0x3b, 0xb9,
0x93, 0x08, 0xc2, 0x67, 0x8e, 0x57, 0x0e, 0x29, 0x3a, 0x89, 0x9a, 0x62, 0x93, 0xdc, 0x49, 0x82,
0xd8, 0xe4, 0xca, 0x21, 0xc3, 0xd2, 0x26, 0xb9, 0xa3, 0x00, 0x22, 0xa7, 0x9f, 0xf6, 0xbf, 0xb3,
0xc9, 0xa7, 0x3c, 0xf8, 0x92, 0x17, 0x01, 0x8f, 0x85, 0xcc, 0xeb, 0xb7, 0x13, 0xf5, 0xf3, 0x02,
0xc3, 0xb9, 0xd0, 0x8f, 0x99, 0xb6, 0x57, 0x71, 0x04, 0xc9, 0x36, 0x9d, 0x14, 0x4d, 0xf7, 0x33,
0xee, 0xbf, 0x2e, 0x63, 0xa9, 0xfb, 0x96, 0x67, 0xff, 0x1b, 0x6f, 0x6f, 0x3c, 0x78, 0x18, 0x5f,
0x43, 0x87, 0xca, 0xc4, 0xb3, 0x54, 0x26, 0x40, 0xde, 0x18, 0xd4, 0x7e, 0x2f, 0xbf, 0x3c, 0xa0,
0x46, 0x0f, 0x61, 0x03, 0x77, 0x51, 0x33, 0xa9, 0xca, 0xb9, 0x91, 0xce, 0xa1, 0xc8, 0xf1, 0x04,
0x88, 0x22, 0x37, 0x4a, 0x78, 0x2a, 0xd3, 0xd6, 0x72, 0xce, 0x0c, 0xb4, 0x95, 0xf3, 0x0a, 0xff,
0x33, 0xfa, 0xa3, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xec, 0x8f, 0xf1, 0x1c, 0x35, 0x1d, 0x00,
0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -2725,7 +2684,6 @@ type AppRuntimeSyncClient interface {
GetAppVolumeStatus(ctx context.Context, in *ServiceRequest, opts ...grpc.CallOption) (*ServiceVolumeStatusMessage, error)
ListHelmAppDetectConditions(ctx context.Context, in *AppReq, opts ...grpc.CallOption) (*AppDetectConditions, error)
ListAppServices(ctx context.Context, in *AppReq, opts ...grpc.CallOption) (*AppServices, error)
ParseAppServices(ctx context.Context, in *ParseAppServicesReq, opts ...grpc.CallOption) (*AppServices, error)
ListHelmAppRelease(ctx context.Context, in *AppReq, opts ...grpc.CallOption) (*HelmAppReleases, error)
}
@ -2881,15 +2839,6 @@ func (c *appRuntimeSyncClient) ListAppServices(ctx context.Context, in *AppReq,
return out, nil
}
func (c *appRuntimeSyncClient) ParseAppServices(ctx context.Context, in *ParseAppServicesReq, opts ...grpc.CallOption) (*AppServices, error) {
out := new(AppServices)
err := c.cc.Invoke(ctx, "/pb.AppRuntimeSync/ParseAppServices", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *appRuntimeSyncClient) ListHelmAppRelease(ctx context.Context, in *AppReq, opts ...grpc.CallOption) (*HelmAppReleases, error) {
out := new(HelmAppReleases)
err := c.cc.Invoke(ctx, "/pb.AppRuntimeSync/ListHelmAppRelease", in, out, opts...)
@ -2918,7 +2867,6 @@ type AppRuntimeSyncServer interface {
GetAppVolumeStatus(context.Context, *ServiceRequest) (*ServiceVolumeStatusMessage, error)
ListHelmAppDetectConditions(context.Context, *AppReq) (*AppDetectConditions, error)
ListAppServices(context.Context, *AppReq) (*AppServices, error)
ParseAppServices(context.Context, *ParseAppServicesReq) (*AppServices, error)
ListHelmAppRelease(context.Context, *AppReq) (*HelmAppReleases, error)
}
@ -3214,24 +3162,6 @@ func _AppRuntimeSync_ListAppServices_Handler(srv interface{}, ctx context.Contex
return interceptor(ctx, in, info, handler)
}
func _AppRuntimeSync_ParseAppServices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ParseAppServicesReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AppRuntimeSyncServer).ParseAppServices(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.AppRuntimeSync/ParseAppServices",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AppRuntimeSyncServer).ParseAppServices(ctx, req.(*ParseAppServicesReq))
}
return interceptor(ctx, in, info, handler)
}
func _AppRuntimeSync_ListHelmAppRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AppReq)
if err := dec(in); err != nil {
@ -3318,10 +3248,6 @@ var _AppRuntimeSync_serviceDesc = grpc.ServiceDesc{
MethodName: "ListAppServices",
Handler: _AppRuntimeSync_ListAppServices_Handler,
},
{
MethodName: "ParseAppServices",
Handler: _AppRuntimeSync_ParseAppServices_Handler,
},
{
MethodName: "ListHelmAppRelease",
Handler: _AppRuntimeSync_ListHelmAppRelease_Handler,

View File

@ -19,7 +19,6 @@ service AppRuntimeSync {
rpc GetAppVolumeStatus(ServiceRequest) returns(ServiceVolumeStatusMessage){}
rpc ListHelmAppDetectConditions(AppReq) returns(AppDetectConditions){}
rpc ListAppServices(AppReq) returns(AppServices){}
rpc ParseAppServices(ParseAppServicesReq) returns(AppServices){}
rpc ListHelmAppRelease(AppReq) returns(HelmAppReleases){}
}
@ -267,6 +266,7 @@ message AppStatus {
string values = 9;
string version = 10;
int32 revision = 11;
repeated string overrides = 12;
}
message AppDetectCondition {
@ -296,11 +296,6 @@ message AppServices {
repeated AppService services=1;
}
message ParseAppServicesReq {
string appID=1;
string values=2;
}
message HelmAppReleases {
repeated HelmAppRelease helmAppRelease=1;
}

View File

@ -19,24 +19,12 @@
package server
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"io/ioutil"
"net"
"strings"
"time"
"github.com/goodrain/rainbond/util/commonutil"
"github.com/goodrain/rainbond/worker/controllers/helmapp/helm"
"github.com/pkg/errors"
"helm.sh/helm/v3/pkg/kube"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/yaml"
"github.com/eapache/channels"
"github.com/goodrain/rainbond/cmd/worker/option"
"github.com/goodrain/rainbond/db"
@ -50,6 +38,7 @@ import (
"github.com/goodrain/rainbond/worker/appm/store"
"github.com/goodrain/rainbond/worker/appm/thirdparty/discovery"
v1 "github.com/goodrain/rainbond/worker/appm/types/v1"
"github.com/goodrain/rainbond/worker/controllers/helmapp/helm"
"github.com/goodrain/rainbond/worker/server/pb"
wutil "github.com/goodrain/rainbond/worker/util"
"github.com/sirupsen/logrus"
@ -190,17 +179,17 @@ func (r *RuntimeServer) getHelmAppStatus(app *model.Application) (*pb.AppStatus,
}
return &pb.AppStatus{
Status: string(helmApp.Status.Status),
Phase: phase,
ValuesTemplate: helmApp.Status.ValuesTemplate,
Cpu: cpu,
SetCPU: cpu > 0,
Memory: memory,
SetMemory: memory > 0,
Readme: helmApp.Status.Readme,
Values: helmApp.Status.CurrentValues,
Version: helmApp.Status.CurrentVersion,
Revision: int32(helmApp.Status.CurrentRevision),
Status: string(helmApp.Status.Status),
Phase: phase,
Cpu: cpu,
SetCPU: cpu > 0,
Memory: memory,
SetMemory: memory > 0,
Readme: helmApp.Status.Readme,
Version: helmApp.Status.CurrentVersion,
Revision: int32(helmApp.Status.CurrentRevision),
Values: helmApp.Status.Values,
Overrides: helmApp.Status.Overrides,
}, nil
}
@ -772,97 +761,13 @@ func (r *RuntimeServer) convertServices(services []*corev1.Service) []*pb.AppSer
return appServices
}
func (r *RuntimeServer) ParseAppServices(ctx context.Context, req *pb.ParseAppServicesReq) (*pb.AppServices, error) {
app, err := db.GetManager().ApplicationDao().GetAppByID(req.AppID)
if err != nil {
return nil, err
}
b, err := base64.StdEncoding.DecodeString(req.Values)
if err != nil {
return nil, errors.Wrap(err, "decode values")
}
vals := map[string]interface{}{}
if err := yaml.Unmarshal(b, &vals); err != nil {
return nil, errors.Wrap(err, "parse values")
}
configFlags := genericclioptions.NewConfigFlags(true)
configFlags.Namespace = commonutil.String(app.TenantID)
kubeClient := kube.New(configFlags)
h, err := helm.NewHelm(kubeClient, configFlags, app.TenantID, r.conf.Helm.RepoFile, r.conf.Helm.RepoCache)
if err != nil {
return nil, err
}
repo := helm.NewRepo(r.conf.Helm.RepoFile, r.conf.Helm.RepoCache)
if err := repo.Add(app.AppStoreName, app.AppStoreURL, "", ""); err != nil {
logrus.Warningf("add repo: %v", err)
}
manifests, err := h.Manifests(app.AppName, app.AppStoreName+"/"+app.AppTemplateName, app.Version, vals, ioutil.Discard)
if err != nil {
return nil, err
}
// Create a local builder...
builder := resource.NewLocalBuilder().
// Configure with a scheme to get typed objects in the versions registered with the scheme.
// As an alternative, could call Unstructured() to get unstructured objects.
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
// Provide input via a Reader.
// As an alternative, could call Path(false, "/path/to/file") to read from a file.
Stream(bytes.NewBufferString(manifests), "input").
// Flatten items contained in List objects
Flatten().
// Accumulate as many items as possible
ContinueOnError()
// Run the builder
logrus.Debugf("start parse manifests: %s", manifests)
result := builder.Do()
if result.Err() != nil {
logrus.Warningf("parse manifests: %v", err)
}
items, err := result.Infos()
if err != nil {
return nil, errors.WithMessage(err, "resource infos")
}
var services []*corev1.Service
for _, item := range items {
if item.Object.GetObjectKind().GroupVersionKind().Kind != "Service" {
continue
}
svc, ok := item.Object.(*corev1.Service)
if !ok {
continue
}
services = append(services, svc)
}
appServices := r.convertServices(services)
return &pb.AppServices{
Services: appServices,
}, nil
}
func (r *RuntimeServer) ListHelmAppRelease(ctx context.Context, req *pb.AppReq) (*pb.HelmAppReleases, error) {
app, err := db.GetManager().ApplicationDao().GetAppByID(req.AppId)
if err != nil {
return nil, err
}
configFlags := genericclioptions.NewConfigFlags(true)
configFlags.Namespace = commonutil.String(app.TenantID)
kubeClient := kube.New(configFlags)
h, err := helm.NewHelm(kubeClient, configFlags, app.TenantID, r.conf.Helm.RepoFile, r.conf.Helm.RepoCache)
h, err := helm.NewHelm(app.TenantID, r.conf.Helm.RepoFile, r.conf.Helm.RepoCache)
if err != nil {
return nil, err
}