Preparare il codice del plug-in

Il codice personalizzato che crei per i plug-in Service Extensions deve essere pacchettizzato e caricato in Artifact Registry prima che altri servizi possano accedervi. Questa pagina descrive come creare il codice del plug-in, creare il pacchetto del codice e caricarlo in un repository Artifact Registry.

Questa funzionalità è in anteprima per Media CDN.

Per informazioni su Service Extensions, consulta la panoramica di Service Extensions.

Prima di iniziare, consulta le best practice per la scrittura del codice del plug-in.

Per altri esempi, vedi Esempi di codice per i plug-in.

Prima di iniziare

  1. Accedi al tuo account Google Cloud . Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti senza costi per l'esecuzione, il test e il deployment dei workload.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Network Services, Network Actions, Artifact Registry, Cloud Build, Cloud Logging, and Cloud Monitoring APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. Installa Google Cloud CLI.

  6. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  7. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init
  8. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  9. Verify that billing is enabled for your Google Cloud project.

  10. Enable the Network Services, Network Actions, Artifact Registry, Cloud Build, Cloud Logging, and Cloud Monitoring APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  11. Installa Google Cloud CLI.

  12. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  13. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init

Configura la toolchain

C++

L'SDK Proxy-Wasm C++ consente agli sviluppatori di utilizzare C++ per implementare plug-in WebAssembly (Wasm) per Service Extensions. L'SDK utilizza la toolchain C++ WebAssembly Emscripten, nonché altre librerie, come protobuf e, facoltativamente, Abseil.

Poiché la creazione di plug-in scritti in C++ dipende da versioni specifiche di questi strumenti e librerie, ti consigliamo di utilizzare l'immagine Docker fornita dall'SDK Proxy-Wasm C++. Le istruzioni per C++ in questa pagina utilizzano il metodo Docker. Per creare plug-in C++ senza utilizzare Docker, consulta la documentazione dell'SDK Proxy-Wasm C++.

  1. Installa Docker se non è già installato. Docker è incluso in Cloud Shell, l'ambiente shell interattivo Google Cloud .

  2. Scarica una copia dell'SDK Proxy-Wasm C++. Il modo più semplice per farlo è clonare il repository Git:

    git clone https://github.com/proxy-wasm/proxy-wasm-cpp-sdk.git
    
  3. Crea l'immagine Docker dell'SDK Proxy-Wasm C++ dal Dockerfile fornito dall'SDK:

    cd proxy-wasm-cpp-sdk
    docker build -t wasmsdk:v3 -f Dockerfile-sdk .
    

    Al termine della creazione delle librerie e delle dipendenze dell'SDK, l'immagine Docker risultante viene associata al tag specificato, che in questo esempio è wasmsdk:v3.

Go

L'SDK Go Proxy-Wasm fornisce un SDK Go completo. Go offre buone prestazioni e un ricco supporto per le librerie di terze parti scritte in Go puro.

Installa la toolchain Go v1.24.0.

Ruggine

La funzionalità di personalizzazione di Service Extensions viene fornita tramite l'utilizzo di WebAssembly e Proxy-Wasm. WebAssembly supporta diversi linguaggi di programmazione. Google consiglia Rust perché offre un eccellente supporto di WebAssembly e Proxy-Wasm fornisce un SDK Rust completo. Rust offre anche buone prestazioni e una forte sicurezza dei tipi.

  1. Installa la toolchain Rust.

    Al termine della procedura di installazione, segui le istruzioni stampate sulla console per completare la procedura di configurazione.

  2. Aggiungi il supporto Wasm alla toolchain Rust:

    rustup target add wasm32-wasip1
    

Crea il pacchetto del plug-in

C++

  1. Crea una nuova directory separata da proxy-wasm-cpp-sdk:

    mkdir myproject
    
  2. Nella directory, crea un Makefile con il seguente contenuto:

    # Express any dependencies
    PROTOBUF=     # full / lite / none
    WASM_DEPS=    # absl_base re2 ...
    
    # Include the SDK Makefile
    PROXY_WASM_CPP_SDK=/sdk
    include ${PROXY_WASM_CPP_SDK}/Makefile
    
  3. Aggiungi un file di origine C++ per il plug-in nella stessa directory. I nomi dei file di origine C++ devono corrispondere ai file Wasm a cui fa riferimento il Makefile, con il suffisso .wasm sostituito da .cc. In questo esempio, il file di origine deve essere denominato myproject.cc.

  4. Aggiungi il codice del plug-in al file di origine.

    Il seguente codice sorgente di esempio è un plug-in che riscrive l'host della richiesta ed emette un'intestazione della risposta:

    #include "proxy_wasm_intrinsics.h"
    
    class MyHttpContext : public Context {
     public:
      explicit MyHttpContext(uint32_t id, RootContext* root) : Context(id, root) {}
    
      FilterHeadersStatus onRequestHeaders(uint32_t headers,
                                           bool end_of_stream) override {
        LOG_INFO("onRequestHeaders: hello from wasm");
    
        // Route Extension example: host rewrite
        if (replaceRequestHeader(":authority", "service-extensions.com") != WasmResult::Ok) {
          LOG_ERROR("Failed to replace :authority header");
        }
        if (replaceRequestHeader(":path", "/") != WasmResult::Ok) {
          LOG_ERROR("Failed to replace :path header");
        }
        return FilterHeadersStatus::Continue;
      }
    
      FilterHeadersStatus onResponseHeaders(uint32_t headers,
                                            bool end_of_stream) override {
        LOG_INFO("onResponseHeaders: hello from wasm");
    
        // Traffic Extension example: add response header
        if (addResponseHeader("hello", "service-extensions") != WasmResult::Ok) {
          LOG_ERROR("Failed to add response header");
        }
        return FilterHeadersStatus::Continue;
      }
    };
    
    static RegisterContextFactory register_StaticContext(
        CONTEXT_FACTORY(MyHttpContext), ROOT_FACTORY(RootContext));

    Il metodo onRequestHeaders è un callback richiamato da Service Extensions.

Go

  1. Crea una nuova directory per il plug-in:

    mkdir go-plugin
    
  2. Nella directory, crea un file go.mod utilizzando lo strumento Go:

    go mod init go-plugin
    
  3. Nella stessa directory, crea un file di origine denominato main.go e aggiungi il codice del plug-in al file.

    Il seguente codice sorgente di esempio è un plug-in che riscrive l'host della richiesta ed emette un'intestazione della risposta:

    package main
    
    import (
    	"fmt"
    
    	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
    	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
    )
    
    func main() {}
    func init() {
    	proxywasm.SetVMContext(&vmContext{})
    }
    
    type vmContext struct {
    	types.DefaultVMContext
    }
    
    type pluginContext struct {
    	types.DefaultPluginContext
    }
    
    type httpContext struct {
    	types.DefaultHttpContext
    }
    
    func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
    	return &pluginContext{}
    }
    
    func (*pluginContext) NewHttpContext(uint32) types.HttpContext {
    	return &httpContext{}
    }
    
    func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
    	defer func() {
    		err := recover()
    		if err != nil {
    			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
    		}
    	}()
    	proxywasm.LogInfof("onRequestHeaders: hello from wasm")
    
    	// Route Extension example: host rewrite
    	err := proxywasm.ReplaceHttpRequestHeader(":authority", "service-extensions.com")
    	if err != nil {
    		panic(err)
    	}
    	err = proxywasm.ReplaceHttpRequestHeader(":path", "/")
    	if err != nil {
    		panic(err)
    	}
    	return types.ActionContinue
    }
    
    func (ctx *httpContext) OnHttpResponseHeaders(numHeaders int, endOfStream bool) types.Action {
    	defer func() {
    		err := recover()
    		if err != nil {
    			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
    		}
    	}()
    	proxywasm.LogInfof("onResponseHeaders: hello from wasm")
    
    	// Traffic Extension example: add response header
    	err := proxywasm.AddHttpResponseHeader("hello", "service-extensions")
    	if err != nil {
    		panic(err)
    	}
    	return types.ActionContinue
    }
    

    Il metodo OnHttpRequestHeaders è un callback richiamato da Service Extensions.

  4. Per scaricare e bloccare le dipendenze della libreria, esegui go mod tidy:

    go mod tidy
    

Ruggine

  1. Crea una directory del pacchetto Rust utilizzando il comando cargo new dal gestore dei pacchetti di Rust, Cargo:

    cargo new --lib my-wasm-plugin
    

    Il comando crea una directory contenente un file cargo.toml che puoi aggiornare per descrivere come creare il pacchetto Rust e una directory src in cui archiviare il codice del plug-in.

  2. Aggiorna il file cargo.toml per specificare i parametri richiesti per creare il pacchetto:

    [package]
    name = "my-wasm-plugin"
    version = "0.1.0"
    edition = "2021"
    
  3. Per registrare l'SDK Proxy-Wasm Rust e il supporto della registrazione come dipendenze, aggiungi la sezione dependencies. Ad esempio:

    [dependencies]
    proxy-wasm = "0.2"
    log = "0.4"
    
  4. Per creare una libreria dinamica come richiesto per i plug-in, aggiungi la sezione lib. Ad esempio:

    [lib]
    crate-type = ["cdylib"]
    
  5. Per ridurre le dimensioni del plug-in compilato, aggiungi la sezione profile.release. Ad esempio:

    [profile.release]
    lto = true
    opt-level = 3
    codegen-units = 1
    panic = "abort"
    strip = "debuginfo"
    
  6. Aggiungi il codice del plug-in al file lib.rs nella directory src.

    Il seguente codice sorgente di esempio è un plug-in che riscrive l'host della richiesta ed emette un'intestazione della risposta:

    use log::info;
    use proxy_wasm::traits::*;
    use proxy_wasm::types::*;
    
    proxy_wasm::main! { {
        proxy_wasm::set_log_level(LogLevel::Trace);
        proxy_wasm::set_http_context(|_, _| -> Box<dyn HttpContext> { Box::new(MyHttpContext) });
    } }
    
    struct MyHttpContext;
    
    impl Context for MyHttpContext {}
    
    impl HttpContext for MyHttpContext {
        fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
            info!("onRequestHeaders: hello from wasm");
    
            // Route extension example: host rewrite
            self.set_http_request_header(":authority", Some("service-extensions.com"));
            self.set_http_request_header(":path", Some("/"));
            return Action::Continue;
        }
    
        fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action {
            info!("onResponseHeaders: hello from wasm");
    
            // Traffic extension example: add response header
            self.add_http_response_header("hello", "service-extensions");
            return Action::Continue;
        }
    }

    Il metodo on_http_request_headers è un callback richiamato da Service Extensions.

Compila il plug-in

C++

Per compilare il plug-in, esegui questo comando dalla directory in cui si trovano i file di origine del plug-in Makefile e C++:

docker run -v $PWD:/work -w /work wasmsdk:v3 /build_wasm.sh myproject.wasm

Questo comando mappa la directory corrente alla directory work all'interno dell'immagine Docker, quindi esegue lo script build_wasm.sh fornito dall'immagine Docker per creare il codice del plug-in. Al termine dell'operazione di compilazione, viene creato un file myproject.wasm, che contiene il bytecode Wasm compilato, nella directory corrente.

La prima volta che il codice del plug-in viene compilato utilizzando l'immagine Docker, Emscripten genera le librerie standard. Per memorizzarli nella cache nell'immagine Docker in modo che non debbano essere rigenerati ogni volta, esegui il commit dell'immagine con le librerie standard dopo la prima compilazione riuscita:

docker commit `docker ps -l | grep wasmsdk:v3 | awk '{print $1}'` wasmsdk:v3

Per ulteriori informazioni sulla creazione di plug-in C++, consulta la documentazione dell'SDK Proxy-Wasm C++.

Go

Per compilare il codice del plug-in, esegui il comando go build:

env GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o main.wasm main.go

Una compilazione riuscita crea un file main.wasm nella directory corrente.

Ruggine

Per compilare il codice del plug-in, esegui il comando cargo build:

cargo build --release --target wasm32-wasip1

Quando la build viene completata correttamente, viene visualizzato un messaggio Finished release [optimized] target(s). Se hai familiarità con Envoy, potresti voler caricare il plug-in in Envoy e verificarne il comportamento.

Carica il codice del plug-in compilato in Artifact Registry

Carica il codice del plug-in compilato in un repository Artifact Registry in modo che i servizi Google Cloud possano accedervi.

Se utilizzi Service Extensions con un bilanciatore del carico globale, utilizza un repository in una posizione multiregionale us. Se utilizzi un bilanciatore del carico regionale, utilizza un repository nella stessa regione o in una località multiregionale sullo stesso continente.

Quando colleghi un plug-in a un bilanciatore del carico globale, Service Extensions copia il modulo Wasm dal repository Artifact Registry nel proprio spazio di archiviazione in località di tutto il mondo. Pertanto, la posizione del repository non influisce sulla latenza delle richieste inviate al bilanciatore del carico. Per i bilanciatori del carico regionali, il plug-in viene copiato nelle località della stessa regione in cui si trova il bilanciatore del carico.

I plug-in di Service Extensions possono essere caricati nei repository generici o Docker di Artifact Registry.

Per un approccio più diretto alla gestione dei file binari autonomi, ti consigliamo di utilizzare un repository generico per archiviare i file Wasm. Questa opzione è in anteprima.

Repository generico

  1. Crea una directory locale package/ e copia il modulo del plug-in pubblicabile. L'artefatto del plug-in deve essere denominato plugin.wasm Il seguente comando di esempio copia l'artefatto del plug-in creato da Rust:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  2. Crea un repository Artifact Registry con --repository-format impostato su generic.

  3. Verifica di disporre delle autorizzazioni necessarie per il repository.

  4. Per caricare il modulo Wasm come artefatto generico nel repository, utilizza il comando gcloud artifacts generic upload.

    gcloud artifacts generic upload \
        --project=PROJECT_ID \
        --location=LOCATION \
        --repository=REPOSITORY \
        --source=package/plugin.wasm \
        --package=PACKAGE \
        --version=VERSION
    

    Sostituisci quanto segue:

    • PROJECT_ID: il tuo Google Cloud ID progetto
    • LOCATION: la posizione regionale o multiregionale del repository
    • REPOSITORY: il nome del repository in cui vuoi caricare il modulo Wasm
    • PACKAGE: il nome del pacchetto del file
    • VERSION: la versione del modulo Wasm

    Al termine del caricamento, prendi nota del nome dell'artefatto generico come indicato con l'etichetta name, ad esempio add_header_plugin:v4 nel seguente esempio. Specifica questo nome quando crei un plug-in o una versione del plug-in.

    Uploading file: plugin.wasm...done.
    '@type': type.googleapis.com/google.devtools.artifactregistry.v1.GenericArtifact
    createTime: '2025-06-16T11:02:25.080248Z'
    name: projects/my-project/locations/us/repositories/my-generic-repo/genericArtifacts/add_header_plugin:v4
    updateTime: '2025-06-16T11:02:25.080248Z'
    version: v4
    
  5. Per verificare che l'artefatto sia stato caricato correttamente in Artifact Registry, esegui il comando gcloud artifacts files list e verifica che l'elenco contenga un file denominato PACKAGE:VERSION:plugin.wasm.

     gcloud artifacts files list \
         --project=PROJECT_ID \
         --location=LOCATION \
         --repository=REPOSITORY
    

Repository Docker

  1. Crea un repository Artifact Registry con --repository-format impostato su docker.

  2. Verifica di disporre delle autorizzazioni necessarie per il repository.

  3. Crea una directory locale package/ e copia l'artefatto del plug-in pubblicabile. L'esempio seguente copia l'artefatto del plug-in creato da Rust:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  4. Crea un file package/Dockerfile con il seguente contenuto:

    FROM scratch
    COPY plugin.wasm plugin.wasm
    
  5. Pacchettizza il codice del plug-in utilizzando Cloud Build o Docker.

    Cloud Build

    1. Crea un file di configurazione della build package/cloudbuild.yaml con il seguente contenuto:

      steps:
        - name: 'gcr.io/cloud-builders/docker'
          args: [ 'build', '--no-cache', '--platform', 'wasm',
                '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG', '.' ]
      images: [ 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG' ]
      

      Il percorso in cui memorizzi il plug-in deve avere il seguente formato:

      LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      

      Sostituisci quanto segue:

      • LOCATION: la posizione regionale o multiregionale del repository
      • PROJECT_ID: l'ID progetto della console Google Cloud
      • REPOSITORY: il nome del repository in cui intendi archiviare l'immagine
      • IMAGE: il nome dell'immagine container nel repository, ad esempio us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin
      • IMAGE_TAG: il tag immagine da assegnare al container, ad esempio production
    2. Attiva l'operazione per creare il container del plug-in e caricarlo in Artifact Registry:

      gcloud builds submit --config package/cloudbuild.yaml package/
      

    Docker

    1. Installa Docker se non è già installato. Docker è incluso in Cloud Shell, l'ambiente shell interattivo Google Cloud .

    2. Configura Docker per l'autenticazione in Artifact Registry. Ad esempio:

      gcloud auth login
      gcloud auth configure-docker LOCATION-docker.pkg.dev
      gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://LOCATION-docker.pkg.dev
      
    3. Crea l'immagine container:

      docker build --no-cache --platform wasm -t my-wasm-plugin package/
      
    4. Per taggare l'immagine locale con il nome dell'immagine del repository, utilizza i tag immagine:

      docker tag my-wasm-plugin LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      

      Sostituisci quanto segue:

      • LOCATION: la posizione regionale o multiregionale del repository
      • PROJECT_ID: l'ID progetto della console Google Cloud
      • REPOSITORY: il nome del repository in cui intendi archiviare l'immagine
      • IMAGE: il nome dell'immagine container nel repository, ad esempio us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin.
      • IMAGE_TAG: il tag immagine da assegnare al container, ad esempio production
    5. Carica l'immagine container taggata in Artifact Registry.

      docker push LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      
  6. Per verificare che l'immagine sia stata caricata correttamente in Artifact Registry, esegui il comando gcloud artifacts docker images list.

    gcloud artifacts docker images list LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE \
        --include-tags
    

Prepara e carica il file di configurazione

I plug-in possono ricevere facoltativamente dati di configurazione, che possono influire sul comportamento del plug-in in fase di runtime. I dati di configurazione possono essere di tipo testo o binario e in qualsiasi formato accettato dal plug-in. Se le dimensioni dei dati di configurazione sono elevate, potresti dover caricare il file di configurazione in Artifact Registry.

Scrivi il codice del plug-in per leggere i dati di configurazione

C++

I dati di configurazione vengono passati al metodo onConfigure dell'oggetto contesto radice, che viene istanziato una volta all'avvio del plug-in e rimane attivo per la durata del runtime Wasm che ospita il plug-in. L'oggetto contesto radice è un'istanza della classe RootContext o di una sottoclasse di RootContext.

Il codice del plug-in può controllare la classe utilizzata per il contesto radice tramite il valore RegisterContextFactory. Ad esempio, il seguente codice del plug-in registra MyRootContext e MyHttpContext come classi da utilizzare per le istanze di contesto radice e di stream. Quindi legge un valore secret dai dati di configurazione del plug-in, a cui le istanze del contesto di flusso possono accedere tramite l'oggetto contesto radice.

#include <string>
#include <string_view>

#include "proxy_wasm_intrinsics.h"

class MyRootContext : public RootContext {
 public:
  explicit MyRootContext(uint32_t id, std::string_view root_id)
      : RootContext(id, root_id) {}

  bool onConfigure(size_t config_len) override {
    auto buffer = getBufferBytes(WasmBufferType::PluginConfiguration, 0, config_len);
    if (!buffer) {
      LOG_ERROR("Failed to retrieve plugin configuration");
      return false;
    }
    secret_ = buffer->toString();
    return true;
  }

  const std::string& secret() const { return secret_; }

 private:
  std::string secret_;
};

class MyHttpContext : public Context {
 public:
  explicit MyHttpContext(uint32_t id, RootContext* root)
      : Context(id, root),
        secret_(static_cast<MyRootContext*>(root)->secret()) {}

  FilterHeadersStatus onRequestHeaders(uint32_t headers,
                                       bool end_of_stream) override {
    // Use secret here...
    LOG_INFO("secret: " + secret_);
    return FilterHeadersStatus::Continue;
  }

 private:
  const std::string& secret_;
};

static RegisterContextFactory register_MyHttpContext(
    CONTEXT_FACTORY(MyHttpContext), ROOT_FACTORY(MyRootContext));

Go

I dati di configurazione vengono letti durante l'esecuzione di OnPluginStart, un ricevitore di metodi che il runtime esegue sulla struct PluginContext una volta all'avvio del plug-in. I dati di configurazione non cambiano durante il ciclo di vita del runtime Wasm che ospita il plug-in. PluginContext è utile per eseguire la logica di inizializzazione e mantenere lo stato in molte richieste.

Il codice del plug-in può controllare il contesto utilizzato per PluginContext implementando il metodo NewPluginContext su VMContext, che crea un'istanza di PluginContext. PluginContext quindi crea istanze dei contesti HttpContext.

Ad esempio, il seguente codice del plug-in registra VMContext, che istanzia PluginContext, il contesto responsabile della lettura dei dati di configurazione e dell'istanza dei contesti HttpContext in base alle necessità. PluginContext legge un valore segreto dai dati di configurazione del plug-in, lo memorizza nel contesto PluginContext e lo passa a HttpContext in NewHttpContext.

package main

import (
	"fmt"

	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
)

func main() {}
func init() {
	proxywasm.SetVMContext(&vmContext{})
}

type vmContext struct {
	types.DefaultVMContext
}

type pluginContext struct {
	types.DefaultPluginContext
	secret string
}

type httpContext struct {
	types.DefaultHttpContext
	pluginContext *pluginContext
}

func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
	return &pluginContext{}
}

func (ctx *pluginContext) OnPluginStart(int) types.OnPluginStartStatus {
	config, err := proxywasm.GetPluginConfiguration()
	if err != nil {
		proxywasm.LogErrorf("Error reading the configuration: %v", err)
		return types.OnPluginStartStatusFailed
	}
	if config == nil {
		proxywasm.LogError("Configuration is nil")
		return types.OnPluginStartStatusFailed
	}
	ctx.secret = string(config)
	return types.OnPluginStartStatusOK
}

func (ctx *pluginContext) NewHttpContext(uint32) types.HttpContext {
	return &httpContext{pluginContext: ctx}
}

func (ctx *pluginContext) Secret() string {
	return ctx.secret
}

func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
	defer func() {
		err := recover()
		if err != nil {
			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
		}
	}()
	// Use secret here...
	proxywasm.LogInfof("secret: %v", ctx.pluginContext.Secret())
	return types.ActionContinue
}

Ruggine

I dati di configurazione vengono letti da un tratto RootContext, che viene istanziato una volta all'avvio del plug-in e rimane attivo per tutta la durata del runtime Wasm che ospita il plug-in. Gli attributi RootContext sono utili per eseguire operazioni o mantenere lo stato in molte richieste.

Il codice del plug-in può controllare quale classe viene utilizzata per il contesto radice tramite il metodo set_root_context e il contesto radice crea istanze dei contesti di stream. Ad esempio, il seguente codice del plug-in registra MyRootContext, che crea un'istanza di MyHttpContext in base alle necessità. Il contesto radice legge un valore segreto dai dati di configurazione del plug-in e lo passa ai contesti dello stream.

use log::info;
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
use std::rc::Rc;

proxy_wasm::main! { {
    proxy_wasm::set_log_level(LogLevel::Trace);
    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
        Box::new(MyRootContext { secret: Rc::new("missing".to_string()) })
    });
} }

struct MyRootContext {
    secret: Rc<String>,
}

impl Context for MyRootContext {}

impl RootContext for MyRootContext {
    fn on_configure(&mut self, _: usize) -> bool {
        if let Some(config_bytes) = self.get_plugin_configuration() {
            self.secret = Rc::new(String::from_utf8(config_bytes).unwrap())
        }
        true
    }

    fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(MyHttpContext {
            secret: self.secret.clone(), // shallow copy, ref count only
        }))
    }

    fn get_type(&self) -> Option<ContextType> {
        Some(ContextType::HttpContext)
    }
}

struct MyHttpContext {
    secret: Rc<String>,
}

impl Context for MyHttpContext {}

impl HttpContext for MyHttpContext {
    fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
        // Use secret here...
        info!("secret: {}", self.secret);
        Action::Continue
    }
}

Carica il file di configurazione

Se le dimensioni dei dati da inviare al plug-in in on_configure superano i 900 KiB, caricali in Artifact Registry seguendo il metodo descritto in Caricare il codice del plug-in compilato in Artifact Registry. In questo caso, salva il file di configurazione con il nome plugin.config (e non plugin.wasm).

Il passaggio successivo consiste nel creare un plug-in.

Durante la creazione del plug-in, devi fornire l'URI del modulo o dell'immagine Wasm caricati.

Crea una nuova versione del codice del plug-in

Per creare una nuova versione del codice del plug-in, modifica il file del plug-in. Poi, come descritto nelle sezioni precedenti, compila il codice del plug-in, ricompattalo e caricalo su Artifact Registry.

Callback

Il codice che compili in Wasm può definire metodi o funzioni arbitrari, ma alcuni di questi hanno un significato speciale. Questi sono i metodi definiti nell'SDK Proxy-Wasm per il linguaggio che preferisci e mappati alle specifiche dell'Application Binary Interface (ABI) Proxy-Wasm. Service Extensions richiama questi callback in risposta alle richieste degli utenti o agli eventi del ciclo di vita del plug-in.

Questi callback sono elencati nella tabella seguente nell'ordine in cui vengono generalmente richiamati:

Nome e descrizione del callback Nome del metodo C++ Nome del metodo Go Nome del metodo Rust
START_PLUGIN: Richiamato all'avvio di un plug-in. RootContext::onStart VMContext.OnVmStart RootContext::on_vm_start
CONFIGURE_PLUGIN: Richiamato dopo l'avvio di un plug-in per fornire i dati di configurazione al plug-in. RootContext::onConfigure PluginContext.OnPluginStart RootContext::on_configure
CREATE_CONTEXT: Richiamato quando viene creato un nuovo contesto di stream. Ogni flusso corrisponde a una richiesta HTTP del client. Context::onCreate PluginContext.NewHttpContext RootContext::create_http_context
HTTP_REQUEST_HEADERS: Richiamato per elaborare le intestazioni delle richieste HTTP. Context::onRequestHeaders HttpContext.OnHttpRequestHeaders HttpContext::on_http_request_headers
HTTP_REQUEST_BODY: Richiamato ripetutamente per elaborare i blocchi del corpo della richiesta HTTP. Context::onRequestBody HttpContext.OnHttpRequestBody HttpContext::on_http_request_body
HTTP_RESPONSE_HEADERS: richiamato per elaborare le intestazioni della risposta HTTP. Context::onResponseHeaders HttpContext.OnHttpResponseHeaders HttpContext::on_http_response_headers
HTTP_RESPONSE_BODY: Richiamato ripetutamente per elaborare i blocchi del corpo della risposta HTTP. Context::onResponseBody HttpContext.OnHttpResponseBody HttpContext::on_http_response_body
DONE: Richiamato al termine dell'elaborazione di un plug-in. Context::onDone HttpContext.OnHttpStreamDone Context::on_done
DELETE: viene richiamato quando l'oggetto contesto dello stream corrispondente a una richiesta HTTP del client viene eliminato. Context::onDelete (nessun callback) (nessun callback)

Passaggi successivi