Home Backend Development Golang Streamlining Access to Embedded Instruqt Labs

Streamlining Access to Embedded Instruqt Labs

Oct 03, 2024 pm 08:07 PM

Bagaimanakah anda mengajar topik yang sangat teknikal kepada prospek dan pelanggan? Bagaimanakah anda menjadikannya perjalanan yang lancar?

Di Isovalent, kami bersemangat untuk menjadikan pengalaman pembelajaran selancar mungkin untuk pengguna kami. Isovalent ialah pencipta Cilium, platform rangkaian awan de facto untuk Kubernetes. Walaupun kami suka rangkaian dan keselamatan, kami menghargai orang yang mungkin menganggapnya sebagai topik yang sukar. Kami fikir kami akan menjadikan pembelajaran rangkaian Kubernetes menyeronokkan, jadi kami menjadikannya satu titik untuk memperagakan pengalaman pembelajaran.
Instruqt menyediakan platform yang hebat untuk membina makmal praktikal yang boleh maju dari segi teknikal dan menarik untuk pengguna.

Kami juga percaya pengalaman pengguna harus lancar dan prosesnya automatik sepenuhnya.
Nasib baik, banyak perkara boleh dilakukan dengan memanfaatkan Instruqt graphQL API.
Untuk tujuan itu, kami menulis perpustakaan instruqt-go kami sendiri, yang kami telah memutuskan untuk membuka sumber. Perpustakaan ini direka bentuk untuk membantu pembangun mengautomasikan dan menyepadukan dengan platform Instruqt dengan mudah.

Salah satu isu dalam penerbitan makmal Instruqt ialah memautkan maklumat pengguna daripada Instruqt dengan pangkalan data atau CRM anda sendiri.
Dalam siaran pertama ini, kami akan membimbing anda membina proksi menggunakan instruqt-go bahawa:

  • mengumpul pengecam pengguna (cth., token HubSpot);
  • mengesahkan identiti pengguna;
  • mengubah hala pengguna ke makmal dengan token akses unik yang dijana melalui API Instruqt.

Kami kemudiannya akan menerbitkan fungsi tersebut pada Fungsi Awan Google.

Mengapa Proksi

Terdapat pelbagai sebab untuk mengumpul maklumat pengguna dalam makmal:

  • Adalah berguna untuk dapat menjana lencana (dan kami menyukai lencana) setelah selesai makmal (lebih banyak lagi akan datang pada siaran akan datang).
  • Ia membolehkan untuk menunjukkan kepada pengguna kemajuan mereka melalui makmal supaya mereka tahu yang mana yang perlu diambil (lihat sebagai contoh Peta Cilium Labs).

Streamlining Access to Embedded Instruqt Labs

Cara Lulus Data Pengguna

Terdapat beberapa kaedah untuk menghantar data pengguna ke runut Instruqt.

Parameter Tersuai

Parameter tersuai Instruqt sangat berguna untuk menghantar sebarang jenis maklumat semasa memulakan trek. Medan ini hanya ditambahkan pada URL sebagai parameter pertanyaan, diawali dengan icp_. Parameter ini juga boleh diambil dalam webhooks Instruqt serta melalui Instruqt GraphQL API, menjadikannya praktikal untuk digunakan.

Sehingga baru-baru ini, Instruqt menggalakkan pembangun jejak untuk menyampaikan maklumat pengguna (seperti nama, e-mel atau token) menggunakan parameter tersuai.

Walau bagaimanapun, terdapat beberapa kelemahan untuk menggunakan parameter tersuai:

  1. Ia tidak diseragamkan, dan Instruqt tidak menafsirkannya. Ini bermakna sesi pengguna akan dipaparkan sebagai awanama dalam laporan Instruqt (dan kiraan pengguna unik mungkin salah).
  2. Ia tidak disulitkan secara lalai. Anda sudah tentu boleh menyulitkannya untuk kunci anda sendiri, tetapi Instruqt akan menunjukkan kepada anda nilai yang disulitkan dalam laporan main.
  3. Saya telah melihat beberapa kali parameter tersuai hilang apabila pengguna memulakan semula makmal. Saya sebenarnya telah memulakan pangkalan data cache saya sendiri untuk mengatasi isu ini.

Jemputan

Jemputan Instruqt membolehkan anda membuat senarai lagu dan menjana pautan jemputan yang boleh dikongsi dengan pengguna untuk akses mudah. Jemputan boleh ditetapkan untuk mengumpul data pengguna melalui borang.

Data pengguna ini kemudiannya ditambahkan pada butiran pengguna pada Instruqt (butiran pengguna dilampirkan pada akaun pengguna, tetapi unik bagi setiap pasukan Instruqt).

Ini sangat praktikal untuk bengkel, tetapi terdapat beberapa batasan lagi:

  1. Menggunakan jemputan untuk mengakses semua makmal bermakna jemputan itu mesti mengandungi semua makmal yang diterbitkan.
  2. Jemputan mempunyai halaman pendaratan mereka sendiri, jadi ia tidak akan berfungsi dengan peta Cilium Labs kami atau pendekatan kios lain.

Nota: Instruqt baru-baru ini memperkenalkan halaman pendaratan, yang merupakan satu bentuk jemputan dengan cara untuk menala halaman pendaratan, dengan kelebihan dan had yang sama.

Borang Pihak Ketiga

Baru-baru ini, Instruqt menambah cara lain untuk menyampaikan maklumat pengguna, yang menggabungkan faedah kedua-dua kaedah sebelumnya.

Kaedah PII yang disulitkan membenarkan untuk menghantar parameter pertanyaan pii_tpg ke URL benam. Ini bermakna:

  1. Data disulitkan, menggunakan kunci awam yang disediakan oleh Instruqt, jadi URL tidak mengandungi maklumat pengguna yang boleh dibaca.
  2. Instruqt memahami data pii_tpg dan mempunyai kunci peribadi untuk menyahsulitnya. Maklumat tersebut digunakan untuk mengisi butiran pengguna, sama seperti mereka telah menerima jemputan.
  3. Ini tidak dipautkan kepada jemputan, jadi ia boleh digunakan dengan mana-mana lagu.

Kami akan menggunakan kaedah baharu ini dalam contoh ini, kerana kaedah ini paling serba boleh hari ini untuk menyampaikan maklumat kepada Instruqt dengan cara yang selamat dan boleh dipercayai.

A Note on Embed Tokens

When you visit a track page on Instruqt, there is an option to embed the track.
This gives you a URL which contains a token unique to the track.

While it is perfectly valid to use that URL, it also means that whoever has access to this token can start the track whenever they want.

Instruqt has recently added an API call to generate one-time tokens for tracks, such that URLs using such tokens can only be used once.

The proxy we're coding will use one-time tokens, since we have access to the API and can easily generate them.

Creating the Proxy

Initial Steps

First, create a directory for your function:

mkdir instruqt-proxy
Copy after login

Move to this directory and initialize the Go environment:

# Replace example.com with the prefix of your choice
go mod init example.com/labs
Copy after login

Google Cloud Function Harnessing

For local testing, create a cmd directory:

mkdir cmd
Copy after login

Create a main.go file in that directory, with the following content:

package main

import (
    "log"
    "os"

    // Blank-import the function package so the init() runs
  // Adapt if you replaced example.com earlier
    _ "example.com/labs"

    "github.com/GoogleCloudPlatform/functions-framework-go/funcframework"
)

func main() {
    // Use PORT environment variable, or default to 8080.
    port := "8080"
    if envPort := os.Getenv("PORT"); envPort != "" {
        port = envPort
    }
    if err := funcframework.Start(port); err != nil {
        log.Fatalf("funcframework.Start: %v\n", err)
    }
}
Copy after login

Creating the Function

Back to the instruqt-proxy directory, create a proxy.go file and start by adding the init() function to it, along with the Go packages we will be using:

package labs

import (
    "fmt"
    "net/http"
    "net/url"
    "os"

    "github.com/GoogleCloudPlatform/functions-framework-go/functions"

    "github.com/isovalent/instruqt-go/instruqt"
)

func init() {
    functions.HTTP("InstruqtProxy", instruqtProxy)
}
Copy after login

This will allow Google Cloud Functions to call the instruqtProxy function when it is initialized.

Let's write that function:

const (
    // Replace team name with yours
    instruqtTeam = "isovalent"
)

func instruqtProxy(w http.ResponseWriter, r *http.Request) {
    instruqtToken := os.Getenv("INSTRUQT_TOKEN")

    if instruqtToken == "" {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }

    instruqtClient := instruqt.NewClient(instruqtToken, instruqtTeam)

    // Get user from passed token
    utk := r.URL.Query().Get("utk")
    if utk == "" {
        w.WriteHeader(http.StatusUnauthorized)
        return
    }

    user, err := getUser(utk)
    if err != nil {
        w.WriteHeader(http.StatusUnauthorized)
        return
    }

    labSlug := r.URL.Query().Get("slug")

    url, err := getLabURL(instruqtClient, user, labSlug)
    if err != nil {
        w.WriteHeader(http.StatusNotFound)
        return
    }

    http.Redirect(w, r, url, http.StatusFound)
}
Copy after login

In this function, we:

  1. get the Instruqt token from the INSTRUQT_TOKEN environment variable
  2. initialize the Instruqt API client for the token and team
  3. retrieve a utk parameter from the URL parameters in order to authenticate the user
  4. get user information based on that UTK
  5. get the lab slug from the URL parameters
  6. retrieve the lab URL for the redirection
  7. redirect the user using an http.Redirect function

Implement getLabURL()

The getLabURL function will generate the redirect URL for the lab based on user information, the requested lab slug, and dynamic information from the Instruqt API.

Let's write it:

const (
    // Replace with your sign-up page format
    labSignupPage = "https://isovalent.com/labs/%s"

    // Adapt to your values
    finishBtnText = "Try your next Lab!"
    finishBtnURL  = "https://labs-map.isovalent.com/map?lab=%s&showInfo=true"
)

func getLabURL(instruqtClient *instruqt.Client, u user, slug string) (string, error) {
    track, err := instruqtClient.GetTrackBySlug(slug)
    if err != nil {
        return "", err
    }

    // Unknown user
    if u.Email == "" {
        url := fmt.Sprintf(labSignupPage, slug)
        return url, nil
    }

    // Get one-time token
    token, err := instruqtClient.GenerateOneTimePlayToken(track.Id)
    if err != nil {
        return "", err
    }

    labURL, err := url.Parse(fmt.Sprintf("https://play.instruqt.com/embed/%s/tracks/%s", instruqtTeam, track.Slug))
    if err != nil {
        return "", err
    }

    // Prepare the fields to encrypt
    encryptedPII, err := instruqtClient.EncryptUserPII(u.FirstName, u.LastName, u.Email)
    if err != nil {
        return "", err
    }

    // Add params
    params := map[string]string{
        "token":             token,
        "pii_tpg":           encryptedPII,
        "show_challenges":   "true",
        "finish_btn_target": "_blank",
        "finish_btn_text":   finishBtnText,
        "finish_btn_url":    fmt.Sprintf(finishBtnURL, track.Slug),
    }

    q := labURL.Query()
    for key, value := range params {
        q.Set(key, value)
    }

    // Encode the parameters
    labURL.RawQuery = q.Encode()

    return labURL.String(), nil
}
Copy after login

First, note that we have defined some new constants that you can tune:

  • labSignupPage is the URL on your website where unauthenticated users will be redirected. It contains a variable for the lab slug.
  • finishBtnText is the text shown on the finish button of the lab.
  • finishBtnURL is the action of the button at the end of the lab. It also contains a variable for the lab slug.

Now let's explain the getLabURL() function steps:

  1. Retrieve track information from the Instruqt API, error if it cannot be found.
  2. If the user is unknown, redirect to sign-up page.
  3. Generate a one-time token for the embedded track access.
  4. Generate the redirect URL.
  5. Encrypt user information using the PII key from the Instruqt API.
  6. Add all parameters (one-time token, encrypted user information, finish button options) to the redirect URL.
  7. Encode the URL.
  8. Return the resulting URL.

The getUser() Function

The last piece missing in this proxy is the getUser() function. I can't help you much here, since this part is where you plug your own logic. You might be using a CRM like Hubspot to retrieve contact information from the UTK, or another database, it's up to you!

The code I'll show you here simply returns a sample user:

/*
 * This is where you add the logic to get user information from your CRM/database.
 */
type user struct {
    FirstName string
    LastName  string
    Email     string
}

func getUser(utk string) (u user, err error) {
    // Implement the logic to get your user information from UTK

    u = user{
        FirstName: "John",
        LastName:  "Doe",
        Email:     "john@doe.com",
    }

    return u, err
}
Copy after login

Testing the code

Now that we have our whole proxy.go function, let's test it!

First, update your go.mod and go.sum files with:

go get ./...
go mod tidy
Copy after login

In your Instruqt dashboard, go to "API keys" and get the value of your API key. Export it as a variable in your shell:

export INSTRUQT_TOKEN=<your_instruqt_token>
Copy after login

Next, launch the function on your local machine:

FUNCTION_TARGET=InstruqtProxy go run ./cmd/main.go
Copy after login

Finally, in another terminal, make test requests to localhost:8080 where your function will be running (you can pass a PORT environment variable above to change the port if necessary):

curl  -i "localhost:8080/?slug=cilium-getting-started&utk=someUtkValue"
Copy after login

Adapt to use a track slug that exists in your Instruqt organization. If the track exists, you should get a 302 response with the redirect URL containing a one-time token for access, as well as John Doe's information encrypted with the PII key, and a one-time token (starting with ott_)!

Alternative testing: using Docker

If you'd like to use Docker to test your function locally, you can create a Dockerfile in your current directory:

FROM golang:1.23

WORKDIR /app

COPY . .

RUN go build -o myapp ./cmd/main.go

ENV DEV=true
ENV PORT=8080

EXPOSE $PORT

CMD ["./myapp"]
Copy after login

Add a docker-compose.yaml file:

version: '3'
services:
  proxy:
    build: ./
    ports:
      - "8080:8080"
    environment:
      INSTRUQT_TOKEN: ${INSTRUQT_TOKEN}
      FUNCTION_TARGET: InstruqtProxy
Copy after login

Finally, build and launch your container:

docker-compose up --build
Copy after login

And you can send requests to localhost:8080 just the same as before!

Hosting the Proxy on Google Cloud Functions

In order to deploy to Google Cloud, first make sure you are logged in to your Google Cloud project:

gcloud auth application-default login
Copy after login

Create a Secret for the API Token

Next, let's create a new secret for the Instruqt token:

echo -n "$INSTRUQT_TOKEN" | gcloud secrets create instruqt-token --data-file=-
Copy after login

In order to adjust the permissions on this secret, you will need to get your project ID:

PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)")
Copy after login

Then, add the "Secret Manager Secret Accessor" role for the default Compute Engine service account for the project:

gcloud secrets add-iam-policy-binding instruqt-token \
    --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
    --role="roles/secretmanager.secretAccessor"
Copy after login

Your secret is now ready to be used by the function!

Deploy the Function

You can then deploy the function (adapt the region if needed):

gcloud functions deploy "instruqt-proxy" \
  --gen2 --runtime=go122 --region=europe-west1 --source=. \
  --entry-point="InstruqtProxy" --trigger-http --allow-unauthenticated \
  --set-secrets="INSTRUQT_TOKEN=instruqt-token:latest"
Copy after login

This will upload and build your project, and return the URL to access the function.

This URL will look something like https://europe-west1-.cloudfunctions.net/instruqt-proxy.
You can then test the function using that URL instead of localhost:8080!

Further Considerations

This is a simplified approach to the lab proxy we use at Isovalent. There are things you might want to consider with this implementation:

  • If you have actual user (instead of marketing contact), switch to a proper authentication system (e.g. JWT) instead of UTK.
  • The current implementation will give access to any lab in your collection if you know its slug. You might want to filter them out (using for example track tags).
  • This implementation manages errors but is very basic in logging. We would recommend using Google Cloud logging to easily audit function runs.
  • You might want to pass extra information as custom parameters. For example, we like to pass some form of even or campaign ID. These can then be retrieved via the API as part or the Track structure.
  • If you're using a custom form and redirecting to the proxy, you might want to be sure your CRM/database has already gotten the user information. You can for example implement a retry logic in the proxy function.
  • Invite embed URLs contain the invite ID. If you want to support invites, the proxy could take an optional invite parameter and add it to the URL.

Using the Proxy

This proxy can typically be used to give access to authenticated users in a safe way, while preserving user information in Instruqt reports and making sure embed URLs are not reusable.

Here is an example of usage of this proxy:

  1. Set up lab sign-up pages with the form system of your choice (e.g. using Hubspot forms).
  2. Retrieve a user identifier from the page context (e.g. a Hubspot cookie token).
  3. Redirect users to the proxy, passing the user identifier and lab slug as parameters.

This can allow you to build a series of public sign-up pages for your labs, similar to what we have built on the Isovalent website. It can also be used to build a Kiosk interface, or even a more creative landing page such as the Cilium Labs map, where clicks on the map redirect to the lab proxy.

By making a complex networking technology like Cilium fun with our labs, we have made it the experience for users less intimidating and more approachable. Using our proxy can help you provide a similar user experience to your prospects. Please get in touch if you have any questions.

The above is the detailed content of Streamlining Access to Embedded Instruqt Labs. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Roblox: Bubble Gum Simulator Infinity - How To Get And Use Royal Keys
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusion System, Explained
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers Of The Witch Tree - How To Unlock The Grappling Hook
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1677
14
PHP Tutorial
1279
29
C# Tutorial
1257
24
Golang vs. Python: Performance and Scalability Golang vs. Python: Performance and Scalability Apr 19, 2025 am 12:18 AM

Golang is better than Python in terms of performance and scalability. 1) Golang's compilation-type characteristics and efficient concurrency model make it perform well in high concurrency scenarios. 2) Python, as an interpreted language, executes slowly, but can optimize performance through tools such as Cython.

Golang and C  : Concurrency vs. Raw Speed Golang and C : Concurrency vs. Raw Speed Apr 21, 2025 am 12:16 AM

Golang is better than C in concurrency, while C is better than Golang in raw speed. 1) Golang achieves efficient concurrency through goroutine and channel, which is suitable for handling a large number of concurrent tasks. 2)C Through compiler optimization and standard library, it provides high performance close to hardware, suitable for applications that require extreme optimization.

Getting Started with Go: A Beginner's Guide Getting Started with Go: A Beginner's Guide Apr 26, 2025 am 12:21 AM

Goisidealforbeginnersandsuitableforcloudandnetworkservicesduetoitssimplicity,efficiency,andconcurrencyfeatures.1)InstallGofromtheofficialwebsiteandverifywith'goversion'.2)Createandrunyourfirstprogramwith'gorunhello.go'.3)Exploreconcurrencyusinggorout

Golang vs. C  : Performance and Speed Comparison Golang vs. C : Performance and Speed Comparison Apr 21, 2025 am 12:13 AM

Golang is suitable for rapid development and concurrent scenarios, and C is suitable for scenarios where extreme performance and low-level control are required. 1) Golang improves performance through garbage collection and concurrency mechanisms, and is suitable for high-concurrency Web service development. 2) C achieves the ultimate performance through manual memory management and compiler optimization, and is suitable for embedded system development.

Golang vs. Python: Key Differences and Similarities Golang vs. Python: Key Differences and Similarities Apr 17, 2025 am 12:15 AM

Golang and Python each have their own advantages: Golang is suitable for high performance and concurrent programming, while Python is suitable for data science and web development. Golang is known for its concurrency model and efficient performance, while Python is known for its concise syntax and rich library ecosystem.

Golang and C  : The Trade-offs in Performance Golang and C : The Trade-offs in Performance Apr 17, 2025 am 12:18 AM

The performance differences between Golang and C are mainly reflected in memory management, compilation optimization and runtime efficiency. 1) Golang's garbage collection mechanism is convenient but may affect performance, 2) C's manual memory management and compiler optimization are more efficient in recursive computing.

The Performance Race: Golang vs. C The Performance Race: Golang vs. C Apr 16, 2025 am 12:07 AM

Golang and C each have their own advantages in performance competitions: 1) Golang is suitable for high concurrency and rapid development, and 2) C provides higher performance and fine-grained control. The selection should be based on project requirements and team technology stack.

Golang vs. Python: The Pros and Cons Golang vs. Python: The Pros and Cons Apr 21, 2025 am 12:17 AM

Golangisidealforbuildingscalablesystemsduetoitsefficiencyandconcurrency,whilePythonexcelsinquickscriptinganddataanalysisduetoitssimplicityandvastecosystem.Golang'sdesignencouragesclean,readablecodeanditsgoroutinesenableefficientconcurrentoperations,t

See all articles