Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: modify component configuration during runtime #762

Merged
merged 37 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
5185869
docs: add design doc
seeflood Aug 10, 2022
cf6a0aa
add api
seeflood Aug 12, 2022
1847938
implement api
seeflood Aug 12, 2022
2dcaf74
Merge branch 'main' into update_config
seeflood Aug 12, 2022
1df7f6e
fix markdown issues
seeflood Aug 12, 2022
22d109d
Merge branch 'update_config' of https://github.com/seeflood/layotto i…
seeflood Aug 12, 2022
1a6254d
fix grpc_api
seeflood Aug 13, 2022
1308ba7
add licenses
seeflood Aug 13, 2022
9f4c2b4
format
seeflood Aug 13, 2022
8175986
add component
seeflood Aug 13, 2022
f603bc5
fix linter issues
seeflood Aug 15, 2022
d57a11b
Merge remote-tracking branch 'upstream/main' into update_config
seeflood Aug 17, 2022
d64b819
generate the docs
seeflood Aug 17, 2022
6a6283e
update design doc
seeflood Aug 17, 2022
db530b1
add ut
seeflood Aug 18, 2022
ecde29d
add ut
seeflood Aug 18, 2022
59daabe
make format
seeflood Aug 18, 2022
dd2dfc2
rename the demo
seeflood Aug 18, 2022
e9bc915
rename the demo
seeflood Aug 18, 2022
974a0bb
modify comments
seeflood Aug 18, 2022
a8e4b14
Merge branch 'main' into update_config
seeflood Aug 23, 2022
4e84a63
fix `Mutex` review issue
seeflood Aug 24, 2022
adcdeb0
fix review issues
seeflood Aug 24, 2022
28936fe
fix review issues
seeflood Aug 24, 2022
9b9561c
add license
seeflood Aug 24, 2022
0632706
modify notify api proto
seeflood Aug 24, 2022
0598b38
modify notify api proto
seeflood Aug 24, 2022
248c443
fix script
seeflood Aug 24, 2022
8337a3b
exclude quickstart generator
seeflood Aug 24, 2022
3edd2da
move demo client
seeflood Aug 24, 2022
96ad52b
generate docs
seeflood Aug 24, 2022
0f234be
remove java examples
seeflood Aug 24, 2022
014fb98
remove duplicate error-checking code
seeflood Aug 25, 2022
a48916d
add comments
seeflood Aug 25, 2022
f231739
modify design docs
seeflood Aug 25, 2022
2f686e2
Merge branch 'main' into update_config
seeflood Aug 25, 2022
2d8f5fd
Merge branch 'main' into update_config
seeflood Aug 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/layotto/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
"strconv"
"time"

"mosn.io/layotto/pkg/grpc/lifecycle"

"mosn.io/layotto/components/oss"

aws_oss "mosn.io/layotto/components/oss/aws"
Expand Down Expand Up @@ -258,6 +260,7 @@ func NewRuntimeGrpcServer(data json.RawMessage, opts ...grpc.ServerOption) (mgrp
// register your gRPC API here
runtime.WithGrpcAPI(
default_api.NewGrpcAPI,
lifecycle.NewLifecycleAPI,
s3ext.NewS3Server,
),
// Hello
Expand Down
5 changes: 5 additions & 0 deletions cmd/layotto_multiple_api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
"strconv"
"time"

"mosn.io/layotto/pkg/grpc/lifecycle"

"mosn.io/layotto/components/oss"

aws_oss "mosn.io/layotto/components/oss/aws"
Expand Down Expand Up @@ -262,8 +264,11 @@ func NewRuntimeGrpcServer(data json.RawMessage, opts ...grpc.ServerOption) (mgrp
runtime.WithGrpcAPI(
// default GrpcAPI
default_api.NewGrpcAPI,
lifecycle.NewLifecycleAPI,

// a demo to show how to register your own gRPC API
helloworld_api.NewHelloWorldAPI,

// support Dapr API
// Currently it only support Dapr's InvokeService,secret API,state API and InvokeBinding API.
// Note: this feature is still in Alpha state and we don't recommend that you use it in your production environment.
Expand Down
5 changes: 5 additions & 0 deletions cmd/layotto_without_xds/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import (
"strconv"
"time"

s3ext "mosn.io/layotto/pkg/grpc/extension/s3"
"mosn.io/layotto/pkg/grpc/lifecycle"

"mosn.io/layotto/components/oss"

aws_oss "mosn.io/layotto/components/oss/aws"
Expand Down Expand Up @@ -241,6 +244,8 @@ func NewRuntimeGrpcServer(data json.RawMessage, opts ...grpc.ServerOption) (mgrp
// register your gRPC API here
runtime.WithGrpcAPI(
default_api.NewGrpcAPI,
lifecycle.NewLifecycleAPI,
s3ext.NewS3Server,
),
// Hello
runtime.WithHelloFactory(
Expand Down
16 changes: 13 additions & 3 deletions components/hello/helloworld/helloworld.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,22 @@ package helloworld

import (
"context"
"sync/atomic"

"mosn.io/layotto/components/hello"
)

type HelloWorld struct {
Say string
Say atomic.Value
}

func (hw *HelloWorld) ApplyConfig(ctx context.Context, metadata map[string]string) (err error) {
greetings, ok := metadata["hello"]
if !ok {
return nil
}
hw.Say.Store(greetings)
return nil
}

var _ hello.HelloService = &HelloWorld{}
Expand All @@ -33,12 +43,12 @@ func NewHelloWorld() hello.HelloService {
}

func (hw *HelloWorld) Init(config *hello.HelloConfig) error {
hw.Say = config.HelloString
hw.Say.Store(config.HelloString)
return nil
}

func (hw *HelloWorld) Hello(ctx context.Context, req *hello.HelloRequest) (*hello.HelloReponse, error) {
greetings := hw.Say
greetings, _ := hw.Say.Load().(string)
if req.Name != "" {
greetings = greetings + ", " + req.Name
}
Expand Down
22 changes: 22 additions & 0 deletions components/hello/helloworld/helloworld_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"context"
"testing"

"mosn.io/layotto/components/pkg/common"

"mosn.io/layotto/components/hello"
)

Expand All @@ -37,4 +39,24 @@ func TestHelloWorld(t *testing.T) {
if resp.HelloString != "Hi, Layotto" {
t.Fatalf("hello output failed")
}

// ApplyConfig, but nil
dc := hs.(common.DynamicComponent)
err := dc.ApplyConfig(context.Background(), nil)
if err != nil {
t.Fatalf("hello ApplyConfig failed")
}
if resp.HelloString != "Hi, Layotto" {
t.Fatalf("hello output failed")
}

// Apply new config
err = dc.ApplyConfig(context.Background(), map[string]string{"hello": "Bye"})
if err != nil {
t.Fatalf("hello ApplyConfig failed")
}
resp, _ = hs.Hello(context.Background(), req)
if resp.HelloString != "Bye, Layotto" {
t.Fatalf("hello output failed")
}
}
20 changes: 20 additions & 0 deletions components/pkg/common/dynamic_component.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2021 Layotto Authors
// 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.

package common

import "context"

type DynamicComponent interface {
ApplyConfig(ctx context.Context, metadata map[string]string) (err error)
}
60 changes: 60 additions & 0 deletions demo/lifecycle/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"context"
"fmt"

"google.golang.org/grpc"

runtimev1pb "mosn.io/layotto/spec/proto/runtime/v1"
)

func main() {
conn, err := grpc.Dial("127.0.0.1:34904", grpc.WithInsecure())
if err != nil {
panic(err)
}
// 1. invoke sayHello API
client := runtimev1pb.NewRuntimeClient(conn)
hello, err := client.SayHello(context.Background(), &runtimev1pb.SayHelloRequest{
ServiceName: "quick_start_demo",
Name: "eva",
})
if err != nil {
panic(err)
}
// validate the response value
if hello.Hello != "greeting, eva" {
panic(fmt.Errorf("Assertion failed! Result is %v", hello.Hello))
}
fmt.Println(hello.Hello)

// 2. invoke lifecycle API to modify the `sayHello` component configuration
c := runtimev1pb.NewLifecycleClient(conn)
metaData := make(map[string]string)
// change the configuration from "greeting" to "goodbye"
metaData["hello"] = "goodbye"
req := &runtimev1pb.DynamicConfiguration{ComponentConfig: &runtimev1pb.ComponentConfig{
Kind: "hellos",
Name: "quick_start_demo",
Metadata: metaData,
}}
_, err = c.ApplyConfiguration(context.Background(), req)
if err != nil {
panic(err)
}
// 3. invoke sayHello API again
client = runtimev1pb.NewRuntimeClient(conn)
hello, err = client.SayHello(context.Background(), &runtimev1pb.SayHelloRequest{
ServiceName: "quick_start_demo",
Name: "eva",
})
if err != nil {
panic(err)
}
// validate the response value. It should be different this time.
if hello.Hello != "goodbye, eva" {
panic(fmt.Errorf("Assertion failed! Result is %v", hello.Hello))
}
fmt.Println(hello.Hello)
}
167 changes: 167 additions & 0 deletions docs/api/v1/runtime.html
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,39 @@ <h2>Table of Contents</h2>
</li>


<li>
<a href="#lifecycle.proto">lifecycle.proto</a>
<ul>
<!--

<li>
<a href="#spec.proto.runtime.v1.ApplyConfigurationResponse"><span class="badge">M</span>ApplyConfigurationResponse</a>
</li>

<li>
<a href="#spec.proto.runtime.v1.ComponentConfig"><span class="badge">M</span>ComponentConfig</a>
</li>

<li>
<a href="#spec.proto.runtime.v1.ComponentConfig.MetadataEntry"><span class="badge">M</span>ComponentConfig.MetadataEntry</a>
</li>

<li>
<a href="#spec.proto.runtime.v1.DynamicConfiguration"><span class="badge">M</span>DynamicConfiguration</a>
</li>



-->

<li>
<a href="#spec.proto.runtime.v1.Lifecycle"><span class="badge">S</span>Lifecycle</a>
</li>

</ul>
</li>


<li>
<a href="#runtime.proto">runtime.proto</a>
<ul>
Expand Down Expand Up @@ -885,6 +918,140 @@ <h3 id="spec.proto.runtime.v1.TopicEventResponse.TopicEventResponseStatus">Topic



<div class="file-heading">
<h2 id="lifecycle.proto">lifecycle.proto</h2><a href="#title">Top</a>
</div>
<p></p>


<h3 id="spec.proto.runtime.v1.Lifecycle">[gRPC Service] Lifecycle</h3>
<p>Lifecycle API is used to manage the sidecar lifecycle.</p><p>For example, by invoking the lifecycle API, you can modify the components' configuration during runtime</p>
<table class="enum-table">
<thead>
<tr><td>Method Name</td><td>Request Type</td><td>Response Type</td><td>Description</td></tr>
</thead>
<tbody>

<tr>
<td>ApplyConfiguration</td>
<td><a href="#spec.proto.runtime.v1.DynamicConfiguration">DynamicConfiguration</a></td>
<td><a href="#spec.proto.runtime.v1.ApplyConfigurationResponse">ApplyConfigurationResponse</a></td>
<td><p>apply the dynamic configuration</p></td>
</tr>

</tbody>
</table>




<h3 id="spec.proto.runtime.v1.ApplyConfigurationResponse">ApplyConfigurationResponse</h3>
<p>The response of the `ApplyConfiguration` method.</p>





<h3 id="spec.proto.runtime.v1.ComponentConfig">ComponentConfig</h3>
<p>The dynamic configuration of a component</p>


<table class="field-table">
<thead>
<tr><td>Field</td><td>Type</td><td>Label</td><td>Description</td></tr>
</thead>
<tbody>

<tr>
<td>kind</td>
<td><a href="#string">string</a></td>
<td></td>
<td><p>Required. Which kind of API you are using, e.g. `lock`, `state` </p></td>
</tr>

<tr>
<td>name</td>
<td><a href="#string">string</a></td>
<td></td>
<td><p>Required. The component name, e.g. `state_demo` </p></td>
</tr>

<tr>
<td>metadata</td>
<td><a href="#spec.proto.runtime.v1.ComponentConfig.MetadataEntry">ComponentConfig.MetadataEntry</a></td>
<td>repeated</td>
<td><p>Required. The dynamic configuration of this component </p></td>
</tr>

</tbody>
</table>





<h3 id="spec.proto.runtime.v1.ComponentConfig.MetadataEntry">ComponentConfig.MetadataEntry</h3>
<p></p>


<table class="field-table">
<thead>
<tr><td>Field</td><td>Type</td><td>Label</td><td>Description</td></tr>
</thead>
<tbody>

<tr>
<td>key</td>
<td><a href="#string">string</a></td>
<td></td>
<td><p> </p></td>
</tr>

<tr>
<td>value</td>
<td><a href="#string">string</a></td>
<td></td>
<td><p> </p></td>
</tr>

</tbody>
</table>





<h3 id="spec.proto.runtime.v1.DynamicConfiguration">DynamicConfiguration</h3>
<p>The dynamic configuration of the sidecar</p>


<table class="field-table">
<thead>
<tr><td>Field</td><td>Type</td><td>Label</td><td>Description</td></tr>
</thead>
<tbody>

<tr>
<td>component_config</td>
<td><a href="#spec.proto.runtime.v1.ComponentConfig">ComponentConfig</a></td>
<td></td>
<td><p>Required. The dynamic configuration of a component </p></td>
</tr>

</tbody>
</table>












<div class="file-heading">
<h2 id="runtime.proto">runtime.proto</h2><a href="#title">Top</a>
</div>
Expand Down
Loading