該demo主要是講解本身寫一個template和一個adapter,並在本地跑起這個demo來。html
template主要用於定契約,描述三個事實, 其實第三點能夠概括到第一點:git
# terminal01, 啓動mix server服務,指定配置文件地址 mixs server --configStoreURL=fs://$(pwd)/testdata # terminal02, 啓動適配器服務grpc server ./l04 print person request data: xhj, 31, clever01 # termial03, 經過mix客戶端命令發送一個check請求給mixer server。而後就出現了terminal02打印的日誌信息 mixc check --string_attributes destination.owner=xhj,destination.container.name=clever01 --int64_attributes destination.port=31
在編寫自定義的template時,遇到了一些問題:github
在編寫自定義的adapter時,一樣也遇到了一些問題:golang
其餘問題是在發起mixc check客戶端調用或者mixs server啓動時出現的,好比:shell
* rpc error: code = Internal desc = grpc: error unmarshalling request: unexpected EOF
config does not conform to schema of template 'person': unable to encode fieldEncoder email_address: destination.container.name | "cdh_cjx@163.com". unable to build primitve encoder for:email_address destination.container.name | "cdh_cjx@163.com". unknown attribute destination.container.name
error creating instance: destination='person.template.istio-system:h1.handler.istio-system (myperson.adapter.istio-system)', error='fieldEncoder: age - lookup failed: 'destination.port''
field 'age' not found in message 'Params'
field 'age' is of type 'string' instead of expected type 'int'
panic: Unknown map type string
針對unknown attribute xxx
標籤的錯誤,通常都是在標籤屬性文件中沒有定義這類標籤,須要添加attributes.yaml文件中api
針對"expected type int"的錯誤,這裏重點介紹下:運維
咱們知道對於每個template定義,都有固定的服務種類支持,好比:check, quota, report, generate_attributes四類,那麼對於本demo實例,template是定義的check服務類型,那麼對應實現的adapter,則是對envoy proxy發過來器的grpc client請求進行check數據校驗,主要是指鑑權類的校驗. 那麼運維在寫kind爲handler的這類對針對check服務類型的配置時,其中的spec部分的params參數,則主要是鑑權類型的數據值,好比ACL、token等數據。 注意:是具體的數據,由於這會對grpc client發送過來的數據處理後,並與adapter指定的數據(kind: handler對象資源下的spec下的params數據)進行比對。 由於mixer server是動態watch配置的,因此配置是能夠動態修改的。這個就解決了check類型數據校驗的動態變化。
因此針對上面錯誤的解決方案,就是個人operator_cfg.yaml
配置kind:handler的params應該是具體數據,而不是什麼age: destination.port | 31
.tcp
針對panic: Unknown map type string
錯誤,通常都是mixc客戶端的命令寫得有錯誤。ide
其餘問題有待考究。函數
咱們建立一個person模板,用於處理全部與人相關的基本信息, 包括用戶名、年齡和email
cd $GOPATH/src/istio.io/istio/mixer/template
mkdir person && cd person cat template.proto
syntax = "proto3"; // Example config: // //```shell //apiVersion: "config.istio.io/v1alpha2" //kind: person //metadata: // name: person // namespace: istio-system //spec: // owner: destination.owner | "guest" // age: destination.port | "24" // email_address: destination.labels["email_address"] | "cdh_cjx@163.com" //``` package person; //import "policy/v1beta1/type.proto"; import "mixer/adapter/model/v1beta1/extensions.proto"; option (istio.mixer.adapter.model.v1beta1.template_variety) = TEMPLATE_VARIETY_CHECK; // The `person` template represents person info key, used to authorize API calls. message Template { // The owner being called (destination.owner). string owner = 1; // The age being called (destination.port). int64 age = 2; // The email_address being called (destination.labels["email_address"]). string email_address = 3; }
$GOPATH/src/istio.io/istio/bin/mixer_codegen.sh -t template.proto
ls
person.pb.html template_handler.gen.go template_handler_service.proto template.proto template_handler_service.descriptor_set template_proto.descriptor_set template.yaml template_handler_service.pb.go
cd ../../adapter mkdir myperson && cd myperson
下面myperson.go用於提供grpc server服務,對於該check服務類型,則主要是用戶基本信息校驗,不經過返回給mixc客戶端相應的錯誤碼和錯誤信息
而config目錄則主要用於認證校驗grpc client發送過來的數據。也就是說config中存儲的是目標數據模型
mkdir config && touch myperson.go cat myperson.go
package myperson import ( "context" "fmt" "net" google_rpc "github.com/gogo/googleapis/google/rpc" "google.golang.org/grpc" istio_mixer_adapter_model_v1beta11 "istio.io/api/mixer/adapter/model/v1beta1" "istio.io/istio/mixer/adapter/myperson/config" "istio.io/istio/mixer/template/person" ) type ( Server interface { Addr() string Close() error Run(shutdown chan error) } MyPerson struct { listener net.Listener server *grpc.Server } ) var _ person.HandlePersonServiceServer = &MyPerson{} func (m *MyPerson) Addr() string { return m.listener.Addr().String() } func (m *MyPerson) Close() error { if m.server != nil { m.server.GracefulStop() } if m.listener != nil { m.listener.Close() } return nil } func (m *MyPerson) Run(shutdown chan error) { shutdown <- m.server.Serve(m.listener) } func (m *MyPerson) HandlePerson(ctx context.Context, req *person.HandlePersonRequest) ( *istio_mixer_adapter_model_v1beta11.CheckResult, error) { fmt.Printf("print person request data: %s, %d, %s\n", req.Instance.Owner, req.Instance.Age, req.Instance.EmailAddress, ) fmt.Println("print adapter info.....") cfg := &config.Params{} if err := cfg.Unmarshal(req.AdapterConfig.Value); err != nil { panic(err.Error()) } fmt.Printf("print person adapter data: %s, %d, %s\n", cfg.Owner, cfg.Age, cfg.EmailAddress, ) if req.Instance.Owner == cfg.Owner && req.Instance.Age == cfg.Age && req.Instance.EmailAddress == cfg.EmailAddress { return &istio_mixer_adapter_model_v1beta11.CheckResult{}, nil } return &istio_mixer_adapter_model_v1beta11.CheckResult{ Status: google_rpc.Status{ Code: 40001, Message: "基本信息不匹配", }, }, nil } func NewMyPerson(addr string) (Server, error) { if addr == "" { addr = "127.0.0.1:4001" } listener, err := net.Listen("tcp", fmt.Sprintf("%s", addr)) if err != nil { return nil, err } s := &MyPerson{ listener: listener, } fmt.Printf("grpc://%s\n", addr) s.server = grpc.NewServer() person.RegisterHandlePersonServiceServer(s.server, s) return s, nil }
cd config && touch config.proto
cat config.proto
syntax="proto3"; // config for myperson package adapter.myperson.config; import "gogoproto/gogo.proto"; option go_package="config"; // config for myperson message Params { // Path of the file to save the information about runtime requests. string owner = 1; // age for person int64 age = 2; // email_address for person string email_address = 3; }
$GOPATH/src/istio.io/istio/bin/mixer_codegen.sh -a config.proto -x "-s=false -n myperson -t person"
ls
adapter.myperson.config.pb.html config.proto myperson.yaml config.pb.go config.proto_descriptor
注意事項:
cd $GOPATH/src/istio.io/istio/mixer/adapter/myperson
mkdir testdata && touch operator_cfg.yaml
cp config/myperson.yaml testdata/
cat operator_cfg.yaml
# handler for adapter myperson apiVersion: "config.istio.io/v1alpha2" kind: handler metadata: name: h1 namespace: istio-system spec: adapter: myperson connection: address: "127.0.0.1:4001" #replaces at runtime by the test params: owner: "donghai" age: 30 email_address: "cdh_cjx@163.com" --- # instance for template metric apiVersion: "config.istio.io/v1alpha2" kind: instance metadata: name: i1 namespace: istio-system spec: template: person params: owner: destination.owner | "donghai" age: destination.port | 31 email_address: destination.labels["email_address"] | "cdh_cjx@163.com" --- # rule to dispatch to handler h1 apiVersion: "config.istio.io/v1alpha2" kind: rule metadata: name: r1 namespace: istio-system spec: actions: - handler: h1.istio-system instances: - i1 ---
cp operator_cfg.yaml testdata/
cp ../../template/person/template.yaml testdata/
cp ../../testdata/config/attributes.yaml testdata/
注意須要在attributes.yaml文件中追加幾個屬性詞彙
destination.port: valueType: INT64
若是發如今啓動mixer server服務時,報其餘屬性詞彙不存在,則在該文件中繼續添加。
運行結果:
當mixc check傳輸的屬性標籤名與值不等於設定的目標值時,返回值:
mixc check --string_attributes destination.owner=donghai --stringmap_attributes "destination.labels=email_address:cdh_cjx@163.com" --int64_attributes destination.port=31
Check RPC completed successfully. Check status was Code 40001 (h1.handler.istio-system:基本信息不匹配)
代表認證不經過
mixc check --string_attributes destination.owner=donghai --stringmap_attributes "destination.labels=email_address:cdh_cjx@163.com" --int64_attributes destination.port=30
當相同時,返回值:
Check RPC completed successfully. Check status was OK
這個只是本地編寫adapter與template,並在本地測試驗證。若是要上k8s的話,這裏有一個完整的demo