#maintainers

1 messages · Page 2 of 1

bronze hollow
#

An extension is a GraphQL schema and a document, with some resolvers; right?

civic yacht
#

We have a community call in 50 minutes where we'd be happy to help, but also happy to help async here too 🙂

An extension is a GraphQL schema and a document, with some resolvers; right?
Yes, that's right

bronze hollow
#

I'm struggling to generate with graphql-codegen

#
⚠ Generate outputs
  ❯ Generate ./gen/pulumi.ts
    ✖
      Failed to load schema from schema.graphql:
      Unknown type: "FSID".
      Error: Unknown type: "FSID".
#

I have your fork and I'm using:

      - add:
          content: "import { FSID, SecretID } from '@dagger.io/dagger/dist'"
    config:
      scalars:
        FSID: FSID
        SecretID: SecretID
#

but it isn't happy with that

#

I've tried without dist too

#

Should I use Go instead of TS for now?

civic yacht
bronze hollow
#

ls

#

Oops

civic yacht
#

I always accidentally type vim keybinds into discord 🙂

#

:wq

ancient kettle
#

:q!

bronze hollow
#

😂

wild zephyr
#

haha, same

cosmic cove
#

<@&1003717314862129174> Community Call starting. See you there!

tepid nova
#

Sorry @mellow bolt we should have started with the later timezones in the call. Next time we'll do that!

tepid nova
#

Thanks @bronze hollow @round granite @untold shoal @scarlet gate for joining!

#

@civic yacht how hard would it be for the yarn extension to extend Filesystem ? Is that technically feasible today or still at the 'idea for later' phase?

civic yacht
#

Can double check it still works if you're interested

tepid nova
#

It would be really neat to do:

{
 host {
  workdir {
   read {
    yarn {
      run(script: "build") {
       output {
        id
       }
      }
     }
    }
   }
  }
 }
}
#

Instead of having to stitch 2 different calls together with filesystem(id: ...)

#

the chain is longer (and that's a lot of curly braces...) but easier to explain than the filesystem() thing

tepid nova
#

It opens the question of namespacing, related to the "is it ok to have empty containers" question Andrea asked yesterday

#

Same question in top-level namespace ({ git { remote(address: ...) } } and type extensions (extend type Filesystem { yarn { build } })

#

(but less urgent than @bronze hollow 's problem 🙂

wild zephyr
#

I've been told the shopify graphql docs are one of the bests out there: https://shopify.dev/api/admin-graphql. I don' think it's OSS buy maybe we can see if we know someone who works there?

tepid nova
#

Question for the JS experts: is there a way for a nodejs script to retrieve the path of its own source code?

#

(Looking for a way to get rid of the CLOAK_CONFIG= hack)

civic yacht
tepid nova
#

Perhaps it's uglier (debatable) but only you have to look at it 🙂

civic yacht
#

I just don't like it because it's unavoidable boilerplate in the code (can't really be farmed out to and hidden within the sdk), but yeah it's subjective

tepid nova
#

Actually I take that back. Either way it is visible in the demo

#

I had missed the part where you can't move it into the SDK, which makes sense

#

So far the least dirty solution is to embed it in the code with cloak generate IMO

#

OK ignoring that one for now

civic yacht
tepid nova
#

OK I have another suggestion for short-term solution

#

How about cloak generate drops an executable entrypoint, say at WORKFLOW_DIR/run.sh which just does:

export CLOAK_CONFIG=$(pwd)/cloak.yaml
node index.mjs
#

So in my package.json I only need to do "foo": "./workflows/FOO/run.sh"

#

(we could rename run.sh to just run)

#

It could be a cross-SDK convention too

#

Which you can bypass at will if you know what you're doing

#

If we switch to project-centric it may turn out to be unnecessary and we can drop it

civic yacht
#

You could also put something like #!/usr/bin/node at the top of index.mjs I think

tepid nova
#

but it may remain useful either way

tepid nova
tepid nova
#

Honestly this is the strongest argument for project-centric... Not having to deal with this stuff

civic yacht
# tepid nova Correction: not `$(pwd)` but whatever hack bash has available to find its own sc...

I see, yeah I think it would work, I'm just concerned at the complexity. cloak.yaml is loaded into buildkit as part of the workdir, so the script has to look at its workdir and find the path of cloak.yaml relative to that. Not actually hard to implement, it just makes my head hurt atm. Also, I just realized that if your cloak.yaml wasn't a subdir of your workdir, then it gets even more complicated.

#

I'll think about it some more once I finish the current fix (and after the demo at 1)

tepid nova
#

@civic yacht where can I get your modified yarn extension ? 🙂

bronze hollow
#

I always like to get the monorepo argument in early too, what about multiple build contexts in a work dir for each cloak file?

#

The cloak file might need a dependencies key. If all my cloaks are node, I can import dependant jobs- but multi language means we need a platform way to define those too?

tepid nova
#

We have two viable options for where the cloak.yaml should live, and what the scope of each file should be. We have not yet decided.

#

Either way there is definitely a dependencies key.

#

Common terminology for both options @bronze hollow :

  • You can use a Dagger SDK to write either a workflow (client code) or an extension (server code).
  • A workflow may depend on extensions
  • An extension may depend on other extensions
bronze hollow
#

If I have a Go workflow that has a file output and I need that in a TS workflow, what does that look like? Does each need named and referenced in GQL?

#

Thanks. I’ll read the links 😀

tepid nova
#

You can't integrate workflows with each other. You need at least one of them to become an extension

#

If you need to compose your Go and TS workflows, that is a sign that you need to move logic into an extension. Then composition happens via the cloak API

bronze hollow
#

Hmmm

bronze hollow
#

It’s quite common to have an isolated service to generate types from protos and consume from many services

#

I can’t think what that looks like here yet

#

Need to kick more tyres

#

With single language I wrap the generation in a function and each workflow consumes, but multi language gets weird. Maybe single language is my bet

#

Oh, the penny just dropped about your extension idea. I’d have a compileProto extension and pass it a path

#

Depending on the context that might work

tepid nova
#

HOLY 💩 @civic yacht I just copy-pasted your custom yarn extension in my cloak file, ran cloak dev, read the docs, figured out how to use, and boom. Amazing...

tepid nova
#

It shouldn't need to do any custom generation though

#

That pattern may be redundant, since cloak itself takes care of this aggregation for you

#

so maybe the need for that service just goes away @bronze hollow ? Not sure

bronze hollow
#

Perhaps if there’s a cloak.yaml with a “root” annotation (like editorconfig) and every subsequent cloak.yaml becomes its own build kit context, cloak can handle the rest for me and I never need to specify a context again?

#

If the child cloak has a dependency, both contexts are loaded

#

Maybe I’m using the wrong terminology

#

This was a nice thing with 0.2, core. Source

tepid nova
#

Yeah definitely. Extensions will get an equivalent of core.#Source I think it will not be a problem

#

Client code (workflows) are TBD because cloak doesn't run them: you run them on the host with your native tools. So we have less control (hence the discussions of various hacks to figure out where the damn files are)

#

Basically everything is simpler in an extension. But extensions have a bit of a learning curve so we need client-side scripts to have a great DX too

bronze hollow
#

If I run “ts-node workflow.ts` how does buildkit get the local source?

tepid nova
#

you have to call { host { workdir { read } } } which loads your current directory into the engine

bronze hollow
#

I haven’t gotten that to work yet. I’ll try again next week

#

Thanks for answering my questions 👍

tepid nova
#

Anytime 🙂

scarlet gate
# tepid nova Question for the JS experts: is there a way for a nodejs script to retrieve the ...
wild zephyr
#

👋 I was setting up cloak locally for the first time and I realized that performing cloak dev actually has to go through the process of building each extension. Just wondering if we thought about doing that in a lazy manner. Couldn't find any issues about that.

It kind of hurts the DX to run cloak dev and having to wait for all the extensions to be ready the first time 🙏

north jay
civic yacht
# wild zephyr 👋 I was setting up cloak locally for the first time and I realized that perform...

Yep it should be trivial to switch the current sync loading of extensions to be lazy (it might literally be a one line change actually). The tradeoff is between waiting for cloak dev to start or waiting for the extension to build once you submit a query that targets the extension. But either way, the idea is that buildkit's caching means you only have to wait when the extension actually changed and needs a rebuild (especially nice once integrated with remote caching). I went with the sync approach for now because I like knowing whether the extension build succeeds or fails before I try to invoke it, but that's particular to me as a developer and a demo-er. I think we could make the behavior configurable pretty easily too.

civic yacht
tepid nova
#

OK I'm at the deploy with go part...

civic yacht
# tepid nova OK I'm at the deploy with go part...

Awesome

  1. Implementation that works for me is here: https://github.com/sipsma/cloak/blob/07ed249a8630ad9865866ae55e56184bd1f0bbb3/examples/todoapp/app/workflows/deploy/main.go
  2. go.mod has a replace directive you'll need: https://github.com/sipsma/cloak/blob/07ed249a8630ad9865866ae55e56184bd1f0bbb3/examples/todoapp/app/go.mod#L7-L9
    • I just realized I pushed my local replace, that will work for you, but for the actual demo you'll want to use the normal github.com/dagger/cloak repo. This is a private repo though and go makes it extremely annoying to pull it. I got it to work though, I'll send the instructions after this.
  3. To generate the client stubs you can do cloak generate -p workflows/deploy/cloak.yaml --sdk=go --output-dir=workflows/deploy/ --client
    • (TODO: update cloak generate to remove the need for --sdk=go, probably can also make the output-dir flag optional)
#

When you want to specify a private git repo in your go.mod you have to:

  1. export GOPRIVATE=github.com/dagger/cloak (or whatever the repo is)
  2. Add something like this to your .gitconfig:
[url "ssh://git@github.com/sipsma/cloak"]
  insteadOf = https://github.com/sipsma/cloak

Which is incredibly annoying, and hopefully there's a better way of doing this, but that's the instructions I found on first google and that worked for me

tepid nova
#

That's going to be a huge PITA for all Go SDK devs until the cloak repo is public, right?

#

maybe we could have cloak generate drop an vendored version or something?

#

@civic yacht so for now, export GOPRIVATE=github.com/sipsma/cloak ?

tepid nova
#

btw how does it find the right branch?

civic yacht
#

maybe we could have cloak generate drop an vendored version or something?
Yep I can't think of anything better than that. It should work pretty well actually, can just run go mod edit in the sdk generate container.

civic yacht
tepid nova
#

@civic yacht what's the minimum sequence of commands to get my new go workflow to run?

#
  • cloak generate
  • go run ?
#

So far I have this:

% yarn run deploy
yarn run v1.22.19
$ GOPRIVATE=github.com/sipsma/cloak go run ./workflows/deploy
workflows/deploy/main.go:4:2: no required module provides package github.com/sipsma/cloak/engine; to add it:
        go get github.com/sipsma/cloak/engine
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
civic yacht
#

Yes, provided cloak generate takes care of all the annoying details above, then that would be it

tepid nova
#

(I stuck the GOPRIVATE=... in the package.json)

civic yacht
#

(at least until we stick this in cloak generate)

tepid nova
#

Ah ok so:

  1. cloak generate
  2. go get
  3. go run?
civic yacht
#

At this moment yeah. 2. should be merged into 1. though. I think I will have time tomorrow to work on that

tepid nova
#

cloak generate isn't doing anything:

% cloak -p ./workflows/deploy/cloak.yaml generate
#1 local://.workdir
#1 transferring .workdir: 497.59kB 0.1s
#1 transferring .workdir: 1.69MB 0.3s done
#1 DONE 0.3s

#2 copy / /
#2 DONE 0.0s
#

(no files written)

civic yacht
#

cloak generate -p workflows/deploy/cloak.yaml --sdk=go --output-dir=workflows/deploy/ --client

tepid nova
#

Feels like --sdk and --output-dir could be inferred from -p?

#

and --client should just default to true

civic yacht
#

Yep, I mentioned above (TODO: update cloak generate to remove the need for --sdk=go, probably can also make the output-dir flag optional)

twin crow
#

I did the generate and the git config, here is what I get (using the main.go from your branch Erik)

tepid nova
#

it worked though 🙂

#

(generate I mean)

twin crow
#

looks like git still does not use ssh

#

the generate works on my side as well

tepid nova
#

I have a variation of the same problem

civic yacht
#

--client defaulting to true sounds good too, that was a quick and dirty change to add --client and --impl, can clean it up more

tepid nova
#
 % go get ./workflows/deploy
github.com/dagger/todoapp/workflows/deploy imports
        github.com/sipsma/cloak/engine: cannot find module providing package github.com/sipsma/cloak/engine
civic yacht
twin crow
#

it's all good now

#

I mean, better

civic yacht
tepid nova
#

sipsma/cloak right?

#

I'm getting confused on which one

civic yacht
#

(starting thread)

wild zephyr
# civic yacht Yep it should be trivial to switch the current sync loading of extensions to be ...

Well... the counter argument against always building upon running cloak is that we're pulling in dependencies and API's that will not be used in any workflows and since there's no way to know which extensions could be potentially used like we have in Dagger Europa, I guess a "safe" default would be not to build them on-demand and let it happen upon invocation time. In any case, we can make this configurable as you suggested

wild zephyr
twin crow
#

@civic yacht @tepid nova 🥳

#

@civic yacht btw if you merge your PR #95, it will break the todoapp. If you could keep your branch on your fork, in case you merge 🙏

civic yacht
tepid nova
#

Quick demo update, we're going to tweak the demo v2 script (let's call this version 2.1 🙂 to start with a more realistic scenario. Overall structure remains the same.

  1. Write a simple deploy workflow, the hard way. Orchestrate yarn and netlify from a JS workflow.
  2. Deploy the easy way: use the yarn and netlify extensions. Massively simpler code.
  3. Write the same deploy workflow, in Go. Demonstrate multi-language + generated client stubs.
#

Steps 1 and 2 are different. Step 3 is the same.

civic yacht
#

That will probably fit into the time slot better and even though build is cool it's too meta

#

(for now)

tepid nova
#

As a bonus, we can start with a non-containerized version of the script. Hopefully it will be worse than the containerized version in some way: slower, harder to read.. something

twin crow
#

same yarn / build / netlify deploy in javascript, I am pushing the workflow now

#

(it's the easy way, using Erik's netlify extension in Go)

wild zephyr
scarlet gate
#

I created a new app in the example folder. Now I wanna execute the cloak generate command.
Here I use your command in this way: cloak generate --output-dir=examples/radar/ts context . -p examples/radar/ts/cloak.yml --sdk ts

This gives me that back

#1 transferring .projectContext: 60.72kB 0.1s
#1 transferring .projectContext: 79.51kB 0.1s done
#1 DONE 0.1s

#2 copy / /
#2 CACHED
Error: failed to solve: input:5: core.filesystem.loadExtension open /tmp/buildkit-mount2903404526/examples/radar/ts/cloak.yml: no such file or directory

exit status 1

As you can see on my screenshot everything should be there.

tepid nova
#

🤔

scarlet gate
#

@civic yacht & @tepid nova I have seen in the examples the graphql queries (in TS) which are quite straight forward. But if they become more complex it will be more difficult to write them correctly. What do you think about a little lib that helps to write queries more easily?
Something like that: https://github.com/munichbughunter/graphql-client-js
I already tested it in a easy way: https://github.com/munichbughunter/graphql-client-js/blob/main/__tests__/GqlStatement.test.ts

GitHub

Simple GraphQL Client that helps to write queries more easily - GitHub - munichbughunter/graphql-client-js: Simple GraphQL Client that helps to write queries more easily

GitHub

Simple GraphQL Client that helps to write queries more easily - graphql-client-js/GqlStatement.test.ts at main · munichbughunter/graphql-client-js

civic yacht
# scarlet gate I created a new app in the example folder. Now I wanna execute the `cloak genera...

For the cloak.yml: no such file or directory I think it's because your file is named cloak.yaml but you are specifying cloak.yml in the command line.

Another side thing: you can leave out --sdk ts from that command for now. The codegen for ts is half baked at the moment which is why it's currently left out of the instruction: https://github.com/dagger/cloak/blob/main/docs/writing_extensions_typescript.md#writing-an-api-extension-in-typescript

If you leave out --sdk ts you still will get schemas written to gen/ in the output-dir, but you'll still have to make some config files and run yarn generate yourself. Once this issue is taken care of we can make the ts codegen actually nice-to-use: https://github.com/dagger/cloak/issues/126

The codegen for go is in a much more usable state (since it's pretty much a necessity for go).

#

For the cloak.yml: no such file or directory I think it's because your file is named cloak.yaml but you are specifying cloak.yml in the command line.
For this, I think we should make it possible to have -p just point to a directory holding cloak.yaml, in which case you can leave out writing the full filename. You could specify the full filename too of course, but that tiny amount of sugar might make small typos like this harder to run into

tepid nova
#

Yes please 🙏

civic yacht
scarlet gate
wet mason
wet mason
tawny flicker
#

I've heard about a tool that can help alleviate the pain. You can install those utility into something it calls a "container". And from there, you can run your tools without polluting your host.
It's pretty fantastic if you ask me.
It's called Docker. They have been around a while.

tawny flicker
#

So FYI, @round granite demo the other made me want to test the same way.
So I did a leftpad extension instead of a ToUpper.
So, if I don't make the CI ecosystem better, at least, I can break it like any other else. Which is something, I guess. 😅

#

testing/checking @civic yacht PR for automated buildkitd start

#

no, first I'm gonna submit my typo/fix found during my dagger ramp up

mellow bolt
#

@civic yacht do I have access right if I want to use git@github.com:sipsma/cloak.git ?

#

I get the following error :

#3 0.094 Initialized empty Git repository in /var/lib/buildkit/runc-overlayfs/snapshots/snapshots/2287/fs/
#3 0.796 git@github.com: Permission denied (publickey).
#3 0.797 fatal: Could not read from remote repository.
#3 0.797 
#3 0.797 Please make sure you have the correct access rights
#3 0.797 and the repository exists.
#3 ERROR: failed to fetch remote git@github.com:sipsma/cloak.git: exit status 128
------
> git://github.com/sipsma/cloak.git#workflow-clean:
mellow bolt
#

ok It works for me know...

#

just did an eval and ssh-add

#

maybe try this @dense dust

#

eval "$(ssh-agent -s)"

#

ssh-add ~/.ssh/your_rsa_key

dense dust
wet mason
#

Oh no actually you should use npm to install yarn 🤯

Same dance as easy_install pip in Python

npm ships with node (just like easy_install ships with python). yarn is a faster (and compatible) 3rd party package manager by Facebook which you can install with npm (like pip)

I’m guessing that custom apt repo comes with its own nodejs, that’s the gigantic list of dependencies you’re seeing (yarn is a JS program)

#

Note for later: we should probably retool our demos around npm instead of yarn

yarn is much better than npm, but we shouldn’t make that decision in example code (people familiar with yarn upgraded from npm, so basically everyone knows npm)

React for instance defaults to npm but if it detects yarn is installed, it’ll use it instead

Pulumi shows both npm and yarn commands in their docs (npm first)

/cc @mellow bolt @dense dust
/cc @civic yacht @tepid nova

dense dust
#

Yep, that's the rule of thumb generally

#

I'm currently doing that with async/await and try/catch blocks in my fork

#

Right now, this is working. /todoapp/workflows/build/index.mjs. Just missing building and writing the output.

import { gql, Engine } from "@dagger.io/dagger";

new Engine({
    ConfigPath: process.env.CLOAK_CONFIG
}).run(async (client) => {
    // 1. Load app source code from working directory

  try {
    const sourceCode = await client.request(gql`
      {
        host {
          workdir {
            read {
              id
            }
          }
        }
      }
    `);

    console.log(sourceCode);

    const image = await client.request(gql`
      {
        core {
          image(ref: "index.docker.io/alpine") {
            exec(input: { args: ["apk", "add", "npm", "git", "openssh-client"] }) {
              stdout
              fs {
                id
              }
            }
          }
        }
      }
    `);

    // console.log(image.core.image.exec.fs.id);

    const installDeps = await client.request(gql`
        {
            core {
                filesystem(id: "${image.core.image.exec.fs.id}") {
                    exec(input: {
                            args: ["npm", "install"],            
                            mounts: [{path: "/src", fs: "${sourceCode.host.workdir.read.id}"}],
                            workdir: "/src"
                         }) {
                        stdout
                    }
                }
            }
        }
    `);

    console.log(installDeps.core.filesystem.exec);
  } catch (err) {
    console.log(`error: ${err}`);
  }

});
wet mason
#

Another note for later: I see there are “accepted” ways for npm packages to ship binaries

We could consider for the cloak node SDK to ship with the cloak API binary. So in order to get started you only need to add the sdk as a node dependency, no other setup required

/cc @tepid nova @civic yacht

dense dust
wet mason
dense dust
#

Yep! I joined the call yesterday, we are working on it 🤞

wet mason
mellow bolt
wet mason
#

I’m on PTO and didn’t check the latest developments 🙂

dense dust
#

No worries!

wet mason
#

I’ll be back on Monday

#

Anyway, happy to see so much progress 🙂

wet mason
mellow bolt
wet mason
#

Basically you should be able to git clone the repo from the same terminal you’re running cloak. If that works then cloak will also work

mellow bolt
tawny flicker
#

I mean, without the front-end side, dagger is nothing either

#

I mean, nobody would know about it, so close to nothing.

#

It's like the best blacksmith of the country is worth nothing if nobody knows about it.
You need both.

civic yacht
#

@tepid nova @twin crow pushed some updates, major one being automating the go.mod setup nonsense. The process now looks like:

  1. From todoapp root, run go mod init github.com/dagger/todoapp.
    • It's possible to include this as a step in cloak generate too, but it feels awkward since we can't automatically determine the name of the module. We'd need a way of passing it to cloak generate which would just transparently pass it to go mod init. Also not needed for any project that already has a go.mod. Let me know if you disagree though, it's trivial to implement either way.
  2. Run cloak generate -p workflows/deploy/cloak.yaml --workflow
    • This will run go mod edit, get, tidy , vendor etc. with GOPRIVATE env setup to get you a working go.mod. When everything is merged into main, will update this to skip the replace of github.com/dagger/cloak w/ github.com/sipsma/cloak
    • It also writes a main.go file with a skeleton implementation to be filled in.

The only caveat remaining, which I think is fine for the demo since it can be setup beforehand, is that you still have to configure .gitconfig. I could not find a way to configure that w/out editing .gitconfig and automating changes to that file would have been in "egregious, un-mergeable hack" territory for me. For the long term, this will be addressed once we move cloak generate to actually run in containerized extensions as part of the overall SDK concept: https://github.com/dagger/cloak/issues/126

Also merged a fix for the problem David run into yesterday and some other minor things (e.g. I use yaml.UnmarshalStrict now to improve that yaml indentation situation yesterday)

I think the biggest remaining wart is the CLOAK_CONFIG hack, so gonna do what it takes to squash that. Then just some other minor cosmetic issues we've brought up.

#

Also, once that's done, I'll start disentangling and merging commits from the PR (somehow have 22 in there now...). Will coordinate as needed. After skimming through it again, there's only one truly egregious hack that is so bad I have to fix it before merging into main: https://github.com/sipsma/cloak/blob/a2fc1db433542e80b197cd15cd9aef6ae17559a5/core/exec.schema.go#L159-L173

Fortunately the fix is pretty easy and just involves adding more features to Filesystem.exec that we'll want in the long-term anyways. So shouldn't be that bad to get all the new demo features main-lined soon

twin crow
tawny flicker
#

What about the dependabot PRs? Should we just merge them? They don't seem to break things we use (after reading the changelog of each of them).

tepid nova
#

Thanks @civic yacht !

#

We should consider removing the todoapp content altogether

#

(from the cloak repo)

civic yacht
civic yacht
tepid nova
#

Bonus is that’s probably what the majority of dependabot PRs are for

civic yacht
# tepid nova So in my `package.json` I only need to do `"foo": "./workflows/FOO/run.sh"`

Trying to fix CLOAK_CONFIG hack and going back to the .sh wrapper. After thinking more, I still am hesitant because this is complexity that the user has to be aware of (they have to know to invoke the .sh script). I like that right now they can just do what should be natural to them (js devs call node ..., go devs can use go run or go build if they want a standalone binary).

With the script wrapper we have to explain an extra step to users and when I imagine trying to answer the question "why do I have to use this wrapper script" I just imagine their eyes glazing over as we explain these minute technical details about workdir vs config file vs source code path, etc.

I am just going to give a shot at the project centric approach and see what it looks like. Hoping it only takes a few hours so we can decide what to do later this afternoon. Will keep the commit self-contained so it's easy to revert if we change our minds in the future too.

dense dust
#

I managed to make the "hard way" build work with npm. it's basically the same as yarn.

#

The thing is, is it normal for the npm install query to not be cached if it doesn't fail?

civic yacht
hasty basin
tepid nova
#

Since we're all collaborating on todoapp now... Maybe we should make it a standalone repo instead of a fork

#

Will make it easier for everyone to have their own forks, open PRs etc

#

@civic yacht how does project-centric remove the need for CLOAK_CONFIG=? We'll still have the fundamental problem of the code being runnable from any directory, outside of our control

#

I have a feeling the only truly clean solution is to not require reading a config file at all...

#

(at runtime I mean)

#

Otherwise there will always be a situation where we need contorsions to find the location of a config file, which is highly language-specific and just generally annoying

dense dust
#

It cached last time I ran though

#

But now I ran again and didn't cache, weird.

tepid nova
#

@civic yacht We're discussing step 4 of the demo (todoapp extension). We need to choose either JS or Go. Any thoughts on which one has a better DX at the moment?

civic yacht
tepid nova
#

Starting a demo-v2 thread to reduce noise..

bronze hollow
#

Who needs code when cloak could implement its own directives like this 😀

civic yacht
# bronze hollow Who needs code when cloak could implement its own directives like this 😀

Super interesting, they basically enable arbitrary chaining by matching resolver output fields -> resolver input args. End effect is sort of like a pipeline of functions for mapping json blobs. Requires very careful coordination of field and arg names I guess, but the general approach is intriguing nonetheless.

Directives in general are almost limitless in power (both a good and bad thing). I think we've previously briefly discussed something like being able to annotate fields as a named result (@result("foo")) that could be referenced later somehow. But it just felt like creating a sort of scripting DSL on top of graphql, at which point it becomes more like "just another language" rather than "the one language to rule them all". But that doesn't mean we should rule out neat DX things similar to this pipelining idea, especially if it could also be useful to codegen clients built on top of gql in addition to the "raw gql" experience too.

wild zephyr
# civic yacht Super interesting, they basically enable arbitrary chaining by matching resolver...

interesting indeed. One "neat" thing about the graphql ecosystem could potentially be that if cloak allows injecting/registering this crazy directive resolvers dynamically (as long as they're written in Go I guess?). This way if someone has a very specific workflow requirement (like steps in this case), they could inject or create their directives and plug them directly through the Cloak CLI.

scarlet gate
scarlet gate
#

Next step improve our Salesforce deployment with cloak...

proven rock
#

Hey folks! Much later than anticipated (life got in the way), I've done a writeup of the caching model differences between Dagger/Nix I was talking about before. I expect most of this to not be news for anyone, but IMO it is useful to write it down and straighten out any possible misunderstandings: https://github.com/dagger/cloak/discussions/135

This has huge implications for where both of the systems fit in the overall stack, and how they can interact.

cosmic cove
ancient kettle
#

Something we talked about with dagger was dagger undo. Have we given any consideration to the same idea in cloak, @wet mason @civic yacht @tepid nova?

tepid nova
#

Welcome to project cloak @hybrid widget 🙂

civic yacht
wild zephyr
# ancient kettle Something we talked about with `dagger` was `dagger undo`. Have we given any con...

👋 just some flying by feedback here. Without having any context, at a first impression reading about dagger undo gives me no idea about what the command could potentially do. Reading Erik's answer I can imagine what we're talking about but the UX still quite doesn't feel right to me. Specially since dagger doesn't have any context of state, so by doing undo each extension+action combo would have to define what undo actually is?

wild zephyr
#

@civic yacht this weekend I came across TSX (https://www.npmjs.com/package/tsx). Seems like another typescript node executer alternative to ts-node. Just bringing this up in case you haven't seen it

ancient kettle
#

It’s about undoing or destroying some thing that was created by the do cmd.

cosmic cove
#

<@&1003717314862129174> based on the notes from last week's meeting, it looks like the majority thought it would be a great idea to start recording our community calls. Therefore, I have created an official calendar invite, invited all of you, and added a zoom link that we will use from now on. The notes are also accessible to everyone through the calendar invite.

#

@hasty basin @twin crow @tepid nova I made you all alternative zoom hosts, so you can record or lead if I am not around. I did set it to record automatically though, so you shouldn't have to worry about it 🙂

tepid nova
#

In parallel to the demo we can start planning a few contribution streams that could be started in parallel to the core work

scarlet gate
# cosmic cove Keep us updated if you need anything for that evaluation! Also, would love to se...

I will not attend the next two community calls because of vacation. About what I did is pretty simple.
We have a tech-radar in our organization. It is a simple JS application which has easy commands in the package.json file.

 "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "lint": "./node_modules/.bin/eslint src"
  },

First I started with the build to get everything working. Deployment is not possible because of my rights on our kubernetes.

obsidian rover
#

As I'm ramping up on Cloak: MIND BLOWN 🤯

#

Dynamic actions on top of normal languages, GraphQL as a representation of DAGs is so intuitive.
The imports of packages in the playground, the types directly accessible, the fast feedback loop. Side effects are easy, OMG

cosmic cove
dense dust
#

TypeScript
Demo v2 is now TS compatible
https://github.com/crjm/todoapp/tree/cloak-demo-v2-ts
Run yarn run deploy-1 or yarn run deploy-2 (executes ts-node-esm) to have JIT support for /scripts/{deploy-1|deploy-2}/index.ts.
The main problem is that the Netlify package (https://github.com/netlify/js-client) does not have type definitions, so we either have to create our own types for the package or change the compiler restraints (strict: false in tsconfig.json) . The latest was chosen as it takes considerably less time to implement, but we should avoid this in the future, as it omits many checks the compiler does.
(thanks for the help @mellow bolt )

ancient kettle
#

Ok... I'm fairly confused now. I'm trying to create a new go project (dagger-classic), and attempting to use dagger/cloak: go get github.com/dagger/cloak

go: downloading github.com/dagger/cloak v0.0.0-20220829171855-01ea736a9c09
go: github.com/dagger/cloak@v0.0.0-20220829171855-01ea736a9c09: verifying module: github.com/dagger/cloak@v0.0.0-20220829171855-01ea736a9c09: reading https://sum.golang.org/lookup/github.com/dagger/cloak@v0.0.0-20220829171855-01ea736a9c09: 404 Not Found
    server response:
    not found: github.com/dagger/cloak@v0.0.0-20220829171855-01ea736a9c09: invalid version: git ls-remote -q origin in /tmp/gopath/pkg/mod/cache/vcs/b46a797880c1419bb8db03bbea7898d15401d1ab8150416524436c67cd3f4e11: exit status 128:
        fatal: could not read Username for 'https://github.com': terminal prompts disabled
    Confirm the import path was entered correctly.
    If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.
#

.netrc + .gitconfig

#

Am I missing something obvious?

ancient kettle
ancient kettle
#

This helped: go env -w GOPRIVATE=github.com/dagger/cloak

wild zephyr
tepid nova
#

Big day for Cloak tomorrow! We're showing a live demo in the expo hall at VMware Explore in Moscone Center, around 10am Pacific. We'll share links here!

tepid nova
#

Thinking about @tawny lion ‘s feedback on cloak yaml… about it being weird to have more than one extension

#

It makes sense but I couldn’t find the right field to express a single place to define your own graphql api…

#

well I think it’s just that: api 🙂

#
scripts:
 - …
 - …
dependencies:
  - …
  - …
api:
  path: …
  sdk: …
#

Welcome @tawny lion by the way 🙂

tepid nova
scarlet gate
# dense dust <:TypeScript:981923900378214401> Demo v2 is now TS compatible https://github.co...

Running yarn run deploy-2 works.
But when I run yarn run deploy-1 I get an error:

yarn run v1.22.15
$ ts-node-esm scripts/deploy-1/index.ts
Error: spawn cloak ENOENT
    at Process.ChildProcess._handle.onexit (node:internal/child_process:282:19)
    at onErrorNT (node:internal/child_process:477:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn cloak',
  path: 'cloak',
  spawnargs: [
    'dev',
    '--workdir',
    '/Users/TestLab/private/myPlayground/radarapp',
    '-p',
    './cloak.yaml',
    '--port',
    '8080'
  ]
}

I guess it comes from this line const engine = new Engine({ ConfigPath: process.env.CLOAK_CONFIG }); right?
What should I set for CLOAK_CONFIG?

tepid nova
#

you don’t need that config key anymore

#

i recommend pulling the latest cloak-demov2 branch of todoapp it has moved a LOT in the last 24h

scarlet gate
mellow bolt
#

then you can get rid of the Engine param like so: const engine = new Engine();

tepid nova
scarlet gate
obsidian rover
#

Questions:

  • the clientdir core query is not working atm ?
    I like the fact that exec is a core type directly not exposed at root, even though it surprised me at first
dense dust
wet mason
#

@obsidian rover it is, however it takes an ID and you need to map ID in localdirs when you do an engine.Start

obsidian rover
#

cloak dev -p examples/test_guigui/cloak.yaml --local-dir src="."
with query:

query {
  core {
         clientdir(id: ".") {

returns -> "NotFound: no access allowed to dir \".\""

obsidian rover
#

(all from graphQL playground)

obsidian rover
#

Ooooh, found out! So, the current way to mount in GraphQL playground is to rely on the CLI with the --local-dir, that maps the given ID to a string ID. As it shall also be a graphQL query, let's see how to do it manually

wet mason
#

@obsidian rover Yeah, there’a an option in engine.Start if using through the API

#

Local directories must be declared in advance in buildkit

obsidian rover
#

I don't see where this buildkit declaration happens in our code, exploring; Thanks 😇

obsidian rover
#

Ok, my bad. Found it: it's a config of the engine, thanks 😇

  • If i may, what is a shim ? its purpose
civic yacht
cosmic cove
#

<@&1003717314862129174> just a reminder to all that we are moving to zoom tomorrow for the community call, and will be using Google Docs for community notes. You should all have a direct invite on your calendars, which is where you will find the zoom link. Please let me know if you have any demos or topics that you'd like me to add to the agenda!

scarlet gate
#

Does it make sense to have a creation dialog similar to npm init when creating a new dagger project? What do you think?

#

@cosmic cove is it possible to get a recording from the VMExplore and Solomon’s demo?

cosmic cove
civic yacht
scarlet gate
tepid nova
#

I’m curious about Backstage and how cloak might integrate with it. Does it have an API? Does anyone have experience with it?

civic yacht
hasty basin
#

some plugins

cosmic cove
ancient kettle
#

@wet mason I'm having some more issues with dagger-classic... 😢

module github.com/dagger/dagger-classic

go 1.19

require github.com/dagger/cloak v0.0.0-20220831001332-9250e5d71e38
package main

import (
    "fmt"

    "github.com/dagger/cloak/engine"
)

func main() {
    if err := engine.Start(ctx, &engine.Config{}, func(ctx engine.Context) error {
        fmt.Println("It has begun")
    }); err != nil {
        panic(err)
    }
}
#

When I try to run go mod tidy...

$ go mod tidy
go: finding module for package github.com/docker/libnetwork/ipamutils
go: found github.com/docker/libnetwork/ipamutils in github.com/docker/libnetwork v0.5.6
go: finding module for package github.com/Sirupsen/logrus
go: found github.com/Sirupsen/logrus in github.com/Sirupsen/logrus v1.9.0
go: github.com/dagger/dagger-classic imports
    github.com/dagger/cloak/engine imports
    github.com/dagger/cloak/core imports
    github.com/moby/buildkit/frontend/dockerfile/builder imports
    github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb imports
    github.com/moby/buildkit/frontend/dockerfile/instructions imports
    github.com/docker/docker/opts imports
    github.com/docker/libnetwork/ipamutils imports
    github.com/docker/libnetwork/osl imports
    github.com/Sirupsen/logrus: github.com/Sirupsen/logrus@v1.9.0: parsing go.mod:
    module declares its path as: github.com/sirupsen/logrus
            but was required as: github.com/Sirupsen/logrus
#

It appears that isn't in github.com/dagger/cloak incorrectly...

twin crow
wild zephyr
#

@tepid nova I've spent quite some time working with backstage.

Backstage on it's core exposes a "service catalog" API which describes relationships between API's > Components > Resources (https://backstage.io/docs/features/software-catalog/system-model). On top of that core it allows anyone to extend that model and come up with new entities that can have relationships with the core entities.

My first ideas about how cloak and Backstage could play together nicely are the following:

  • Have a cloak dev cache-persistent playground embedded on my Backstage UI where I can dynamically add / remove private and public extensions and prototype queries super fast to create workflows for my organization.

  • Make Backstage be cloak aware of the services that are currently using cloak workflows and provide "Governance" about who triggered what and when. For example, I foresee a UI where I can trigger a specific workflow for a specific service and backstage stores all the transactional metadata about what outputs that workflow generated and by whom. On top of that we could leverage on the Backstage RBAC model to add/remove capabilities to users for specific Cloak workflows

ancient kettle
#

@civic yacht Question for you...

package main

import (
    "context"
    "fmt"

    "github.com/Khan/genqlient/graphql"
    "github.com/dagger/cloak/engine"
)

func main() {
    ctx := context.Background()
    if err := engine.Start(ctx, &engine.Config{}, func(ctx engine.Context) error {
        fmt.Println("It has begun")

        var resp *graphql.Response
        err := ctx.Client.MakeRequest(ctx, &graphql.Request{Query: `
            query {
                core {
                    image(ref: "alpine") {
                        exec(input: {
                            args: ["echo", "{\"hello\": \"world\"}"]
                        }) {
                            stdout
                        }
                    }
                }
            }
        `}, resp)
        fmt.Println(resp)

        if err != nil {
            return err
        }

        return nil
    }); err != nil {
        panic(err)
    }
    return
}

is giving me this error (after running everything seemingly cleanly):

#15 /_shim echo {"hello": "world"}
#15 CACHED
panic: failed to solve: json: Unmarshal(nil *graphql.Response)

goroutine 1 [running]:
main.main()
    /Users/joel/src/dagger-classic/main.go:39 +0x6c
exit status 2
#

Any idea why I'd be getting that panic?

#

Oh... I didn't initial resp 🤦🏻‍♂️

civic yacht
civic yacht
#

No worries at all, I have gotten stuck on a tooon of little things like that when trying to use the raw gql client in go. It's so verbose it's easy to overlook tiny stuff.

Just so you know, you can get autogenerated client w/ go. I'm actually updating that exact doc at this moment, but the basic idea is A) declare a dependency in cloak.yaml and B) run cloak generate (no args needed anymore) from the dir containing cloak.yaml or any subdir

ancient kettle
#

Thanks, I appreciate it. 🙂

I look forward to seeing that doc. I think I might have created one while mucking around... 🙂

civic yacht
tepid nova
#

Welcome newcomers!

tepid nova
#

I just realized a downside of keeping a runtime dependency on cloak.yaml: as it stands you can’t use the cloak SDK to produce a standalone tool (like dagger-classic)

#

That is pretty major actually

cosmic cove
#

<@&1003717314862129174> welcome newcomers! You should see a calendar invite for our Cloak community call. During the call, the community brings questions, shows demos, discusses use cases, etc. It is every Thursday at 10 am PDT. We hope to see you there!

#

@loud mica here is the channel that I was mentioning 🙂 Feel free to any questions here, and we will be sure to answer!

#

It will be interesting to see how Cloak helps your current use case

loud mica
civic yacht
# ancient kettle Thanks, I appreciate it. 🙂 I look forward to seeing that doc. I think I might...

Ran through this successfully in case it's helpful: https://github.com/dagger/cloak/pull/95/commits/61647779c41236fc5bd6965c10a390c4b33643fd
The instructions technically will only work exactly as is once the PR is merged into main (since they refer to the main branch), but hopefully the gist of it is still helpful if you haven't figured it all out on your own already.

Next up is the same for TS, then I think we can finally merge and you won't have to base off my branch anymore...

ancient kettle
tepid nova
#

Really, twitch?

#

The algorithm said "that's it. the perfect preview frame"

scarlet gate
obsidian rover
#

From yesterday, the clientdir action has disappeard. We now have the host core api. Hmm, that changes things 🤣

wet mason
#

Migrated from Playground to GraphiQL

cosmic cove
#

<@&1003717314862129174> reminder that the community call is at 10 am PDT today! I won't be there today, but you are in amazing hands with @tepid nova and @hasty basin ! Bring your questions, demos, use cases, or just come to listen in. We look forward to seeing all the new faces!

tepid nova
#

Thanks for a great call everyone

#

Here are the areas of contributions I mentioned earlier. This is not an exhaustive list:

  1. Bundling buildkit. We want cloak to be a standalone binary
  2. “Dagger classic”. Cue SDK with europa compat. We have a design. Prototyping can start.
  3. New use cases. Do something real with cloak. Real world projects are best.
  4. Bash SDK. 🙏
  5. Adding core API buildkit bindings
  6. multi-platform.
  7. Go DX. Needs a lot of polish
  8. Typescript DX. Same.

More discussions in this thread: https://discord.com/channels/707636530424053791/1014065280835661905

Areas of ongoing core design:

  1. Adapting core API to GraphQL best practices
  2. Define extension points. What can an extension do, and how are they integrated into the API?
    • Option 1: supergraph model. Each extension is a mini-API, cloak aggregates them (more flexibility; less interop)
    • Option 2: regular graph model. Cloak has its own API, extensions can extend some of the types in some ways (less flexibility; more interop)
  3. Project file layout and format (cloak.yaml)
tepid nova
#

@civic yacht @wet mason can we catch up on DX and aftermath of demo for a few minutes before Andrea logs off?

hasty basin
hasty basin
tepid nova
tepid nova
tepid nova
#

@civic yacht is workflow-clean still your primary branch?

#

I'm going to start from there for my core API proposal

civic yacht
tepid nova
#

Ah ok

#

oh right I missed type Host

#

saw type LocalDir and assumed it wasn't merged. But I guess you added Host on top o fit

#

congrats on merging btw 🙂

#

I've been reading up on type extension, I'm only now realizing that extends is part of the core graphql spec (not an apollo thing)

#

it looks like you can extend any type, including enums 🙂 Could come in handy as we explore best extension model

civic yacht
tepid nova
#

eg.

Core:

extend type Query {
  repository(namespace Namespace!, address String!): Repository
}
enum Namespace {
  Git
  HTTP
  OCI
}
interface Repository {
  artifact(name String!) Artifact
  artifacts [String!]

Debian extension:

extend enum Namespace {
  Debian
}
DebianRepository implements Repository {
  artifact(name String!) DebianPackage
}
civic yacht
tepid nova
#

I couldn't find anything about type extensions in the docs, so went looking in the specs. They're pretty readable.

civic yacht
#

Agree, much better than most specs.

Another thing to look into if you haven't already are fragments: https://graphql.org/learn/queries/#fragments

I don't have any super concrete ideas immediately, but they feel potentially useful

tepid nova
#

Yeah I was wondering about a pattern to reduce stitching overhead in the case of branching out a pipeline, using gql fragments + buildkit dedup

#

(when pipeline A branches out into pipelines B1 and B2)

#

You could define A as a fragment, then use it to make only 2 queries:

  • A + B1
  • A + B2

Buildkit deduplication takes care of the rest

obsidian rover
#

Btw, I don't know if most of you saw. But Andrea bumped the playground version to one of the latest gaphiql version, and now it's even more awesome.
-> Literally a bump in DX in 20 min

tepid nova
#

Oh cool! Trying now. What's changed?

obsidian rover
#

Autocompletion works well. We literally benefit from the web community tooling on this

tepid nova
#

Trying to understand the smallest possible change we can get away with

tepid nova
tepid nova
#

Oh! I see it

#

Designers being too clever

#

There's this thing called "text"

#

where you write down what a button does...

obsidian rover
tepid nova
#

@civic yacht what's the story with IDs, are we going to keep using "llb cookies" (as @twin crow calls them 🙂 or are switching to random IDs?

#

(could influence the core API design one way or the other)

civic yacht
#

The best we can do is compress them so they aren't stupendiously long, which is a bit silly but the only change I can see in the short term

tepid nova
#

Right sorry - llb cookie or llb hash then

#

The interesting bit is that if they are cookies, then we can rely on them as content in addition to just a content address

#

Which is perhaps useless and better left hidden as an implementation - or perhaps could be used for API design ?

#

(no idea how)

civic yacht
tepid nova
#

I think thats OK actually

#

fundamentally they are code. Code size scales with human effort which is to say: not a lot

#

("because humans are lazy and weak" my computer would say)

civic yacht
tepid nova
#

the compression doesn't fix that?

civic yacht
#

When I experimented quickly the other day

tepid nova
#

I see. yeah that's not great

#

OK so I will assume that it could be changed to a hash at any time

civic yacht
obsidian rover
#

There's a use-case I don't understand (in types imbrication) ->

client: host {
    workdir {
      read {
        exec(input: {args: ["ls", "-a"]}){
          stdout
          stderr
        }
      }
    }
  }

In that context, read returns a Filesystem. We have access to the exec, which will inevitably fail because it's not running in a real image (am I right?)

Btw, I have this issue:

"message": "process \"/_shim /bin/ls -a\" did not complete successfully: exit code: 1",

But truth is, I don't know how to debug (change verbosity)

tepid nova
#

@obsidian rover correct unless you happen to be sitting in an unpacked linux rootfs as your workidr on the host machine

#

I think it will make more sense to move exec to a Container type (I'm drafting a proposal for that right now)

obsidian rover
tepid nova
#

More graphql noob questions (sorry). Do we want to give everything an ID? That seems like a very common pattern, in the github API for example

civic yacht
tepid nova
ancient kettle
civic yacht
tepid nova
#

Right

civic yacht
#

I don't know if we need a hard rule that "all objects must have an id" though. E.g. we'll probably have an ImageConfig object at some point, not sure if that needs an ID

#

But maybe it could?

tepid nova
#

In my proposal of having a Container type which has a rootfs: Filesystem field, would Container need an ID? I suppose so (to retrieve the rootfs)

civic yacht
tepid nova
#

Right, I was thinking 2 (since 1 would be a major architecture change it seems)

#

How much work is option 1 if I wanted to try? 🙂

civic yacht
# tepid nova How much work is option 1 if I wanted to try? 🙂

You will run into the same problem I ran into where I tried to change fsid to be a hash I think. Doesn't work when you get cached values from previous executions. The only thing I can think of is to have our own persisted DB (or re-use buildkit's/containerd's boltdb somehow).

tepid nova
#

Sorry I meant option 2!

#

If I wanted to try option 2 (assuming it's the easiest), how much work?

hasty basin
#

qq on tags and docs for dagger/cloak repo
is the current demov2 tag stuff going to remain as is for now?
or are we bringing that content to a branch?

Are the most current general docs on main branch?

civic yacht
civic yacht
tepid nova
#

actually I should be able to use the same IDs for container and fs, si ce everything I need is in tbe llb state

#

unlike in Europa we don’t need to disable parts of the llb state, we can use it all the way

#

might make multi arch easier too

#

and of course no need for the docker/core split for push, pull etc

#

no more ImageConfig either, just individual resolvers for each field that would query the llb state

civic yacht
# tepid nova actually I should be able to use the same IDs for container and fs, si ce everyt...

I thought this too, but for some reason when you serialize llb.State to LLB protobuf, all the image config meta fields are dropped and not thus honored if you deserialize. Discovered this after I told @twin crow the other day it would be super easy to add support for honoring image config values in exec and then soon realized it was not so easy after all.

However, we can fix this by slightly modifying FSID to have both the LLB protobuf and image config metadata and serializing all that instead of just the protobuf. So we can still achieve what you're describing relatively easily (just not as easy as it seems like it should be).

tepid nova
#

Ok I see. I guess it would make sense to eventually just serialize everything into our own polyfill format, which would be a strict superset of llb

tawny flicker
#

I'm hitting some blocking today in trying to create an extension:

dolanor@eastpeak:~/src/cloak/example/test$ cloak generate -p ./example/test/cloak.yml --workdir ../../
#1 local://__cloak_workdir
#1 transferring __cloak_workdir: 7.76MB 0.1s
#1 transferring __cloak_workdir: 17.63MB 0.2s done
#1 DONE 0.2s

#2 copy / /
#2 DONE 0.1s
Error: failed to solve: input:5: core.filesystem.loadProject yaml: unmarshal errors:
  line 2: field sources not found in type project.Config
tepid nova
#

but conceptually what you are proposing is the same

civic yacht
tepid nova
#

@tawny flicker your cloak.yaml is probably different than what the latest version of cloak supports

civic yacht
#

Yeah what Solomon said

tawny flicker
#

ok, I guess we need to update the examples as well

civic yacht
tepid nova
#

@tawny flicker look at that you just discovered a useful PR to make 🙂

tawny flicker
#

(and dogfood test so we detect that on CI)

tawny flicker
tepid nova
#

Any ideas on how to express docker push, git push, netlify deploy in a graphql-friendly way?

#

I see how to design a graphql-ey schema for downloads that doesn't have verbs, but uploads are harder

tawny flicker
civic yacht
# tepid nova I see how to design a graphql-ey schema for downloads that doesn't have verbs, b...

If there is data to select on the pushed/uploaded/deployed noun (i.e. select the url of the deployed site), then that's one path. I guess we may run into cases where we are just triggering a side-effect and nothing else, in which case it's kind of awkward. I saw people saying they just use Boolean as return types in those cases. But they were random github commenters, so not sure if it qualifies as a best practice

wet mason
#

But I don’t know how we’d want to translate them into cloak

tepid nova
#

OK. Do you think we should pursue that? Are there mutations in our future?

#

Or is there an immutable implementation problem that prevents their use

#

(I know you guys have researched that but I'm not up-to-date on that)

wet mason
#

I think mutations make sense for things that have side effects in the API (like addSecret, loadExtension)

For “uploads” (netlify deploy, git push, …) I don’t know

On the one hand it would make sense for them to be mutations, in a graphql-friendly way. On the other hand, we lose chainability by doing so

civic yacht
#

Which is just meant to handle race conditions when updating state

tepid nova
#

Does addSecret really have side effects? Secret IDs are handled differently than FS IDs (ie no cookie)?

#

So there's a global lookup table I guess

#

For extensions I was thinking we could borrow llb's with... pattern to remove the side effects. Could be an extension of Query?

extend type Query {
  withExtension(input: ExtensionInput) Query!
}
wet mason
#

Also the other difference is mutations are “flat”

#

mutation { foo { bar } }

Foo is the mutation. Bar is a query against the return type of foo

tepid nova
#

If we use mutations, and we want extensions to create their own, we will need a good way to namespace them both between extensions, and within each extension

wet mason
#

And semantically speaking, queries are nouns (data), mutations are verbs (actions)

(typically — not in the spec but that’s how virtually all APIs around do it)

tepid nova
#

Right

#
query Example {
  withExtension(input: {
    git: {
      remote: "github.com/dagger/cloak"
      ref: "main"
      path: "examples/yarn"
    }
  }) {
       ...
     }
   }
}
civic yacht
tepid nova
#

Ah right

#

Forgot about that

#

Mutation is fine for loading an extension since it's kind of a special case

#

For adding a secret it feels more awkward to me, but I can't express why quite yet

civic yacht
civic yacht
tepid nova
#

Yeah, no opinion on that

#

Basically I'm going to ignore the loading of extensions as a special case, as far as my core API proposal is concerned

civic yacht
#

I think that's my main hangup overall here, like the semantics of mutation vs query make perfect sense and we shouldn't ignore that aspect, it just feels awkward that we could be imposing arbitrary limitations (serial execution of top level selection set) when they don't need to be imposed. We are just different than other graphql use cases in that our "database" (buildkit) is highly optimized to handle parallelization, so our higher level API has less of a need to be specialized for that. Overall, still not sure

Edit: actually, it's more that our core api doesn't really have the equivalent of "incrementCounter" where the return value of queries are impacted by past mutations. We are just querying immutable content-addressable content. My words are failing me here, but something along these lines

tepid nova
#

Can gql input types be composed of other input types?

civic yacht
tepid nova
# civic yacht I think that's my main hangup overall here, like the semantics of mutation vs qu...

We could organize the extension API around these constraints. For example, I'm assuming serializing extension loading is only a problem because we build them on the fly (which can take time and could be serialized). What if we separated the build part into a graphql-ey query, and it returns an extension ID. Then the mutation to load takes that ID as input. The loading itself would be quasi instant, and serialized mutations are no longer a problem. Could even be a good thing since we can predict the order in which extensions are loaded

civic yacht
tepid nova
#

I just learned that you can't pass a union type as input type 😭

civic yacht
#

I had the same sad realization a while back

tepid nova
#

That?

wet mason
civic yacht
tepid nova
wet mason
tepid nova
#

In the case of secrets, doesn't it depend a lot on how we implement them under the hood?

civic yacht
wet mason
#

Basically our “exec” for instance is not exec-ing— it’s querying buildkit for immutable content

addSecret and loadExtension are kinda different as they will impact future queries

wet mason
tepid nova
#

Right but in the case of addSecret, in practice queries are only affected once they know the secret's ID. So there is no risk of race conditions etc

#

Even though technically the secret can be looked up by any query as soon as it's added... in practice no query will know what ID to lookup until the addsecret returns

#

so if we wanted, we could present it as a querying immutable content

#

(I think?)

wet mason
#

True. Because we have no hypothetical updateSecret (which would love alongside addSecret in a typical gql api)

#

But even our secrets are immutable by nature

tepid nova
#

we could also scope the secret to the query, if we found a way to make the with.. pattern work

wet mason
#

But let’s say we do have removeSecret

tepid nova
#

For example

type Filesystem {
  WithSecret(name: String!, cleartext: String!): Filesystem
}
#

I guess in that case you coud dispense with secret IDs altogether. Caller passes a scoped name

wet mason
tepid nova
civic yacht
#

I guess if we had listSecrets that would also mean the addSecret should be a mutation (since now there's a query that is impacted by addSecret)

tepid nova
#

After all the llb API is a masterclass in chaining 🙂

#
extend type Query {
  "Load an existing environment or create a new one"
  environment(id: EnvID): Environment
}

type Environment {
  id: EnvID!
  withSecret(name: String!, cleartext: String!) Environment
  secrets: [String!]!
  image(...): Filesystem
  git(...): Filesystem
}
civic yacht
tepid nova
#

Well the difference is that secrets work that way in buildkit

civic yacht
#

I mean the way graphql execution works is that the parent object is passed to all child field resolvers, so I think you can put whatever you want in that object. Each resolver can just update its state and then pass it along to the next one. So I don't think we are limited to secrets and filesystems

#

I may be misunderstanding the suggestion though

tepid nova
#

To rewind, my understanding of the problem:

  • We need a way to reference Secrets and Filesystems by ID (to mount them, copy them etc)
  • Filesystems can be created, then referenced, in the context of a chained query, because no global state is mutated
  • Secrets do mutate global state when created (the engine's global secret lookup table), so in theory we should use a graphql mutation to do so
  • But I argue that maybe a mutation is not the right fit, and instead we can manage secret IDs in a way more similar to filesystem IDs
  • I then explore various options for doing so.
  • One option is the with.. pattern. Possibly a bad idea, I don't know.
wet mason
#

addSecret is a weird one btw. We put it there in a rush but I don’t know if it makes sense to be an API call

tepid nova
#

@civic yacht I think this pattern:

type Universe {
 nouns
 withNoun
}

Actually makes sense for every value of "noun" that 1) needs to be referenced by ID , 2) we want to manage those IDs in a way similar to Filesystem IDs (ie. either global or mutable, but not both), and 3) they're only used in one type

wet mason
#

The reason it’s there is just so we can use SecretIDs everywhere, so that when we have a better solution we don’t have to rewrite everything that touches secrets as we’re already using the ID indirection

civic yacht
civic yacht
#

But doesn't want that stored in buildkit cache

tepid nova
#

It could be stored in the engine's own cache in memory?

#

via the polyfill cookie serialization format (or PCSF as I like to call it)

#

yes I just made that up

civic yacht
wet mason
#

I think ideally, long term, we should follow bk’s pattern and somehow have extensions be secrets providers

civic yacht
tepid nova
#

@wet mason even with secrets providers (which would be awesome to have) scripts will still want to load secrets from plaintext themselves

#

I mean, sometimes

wet mason
#

Yeah

#

True

civic yacht
#

Yeah I agree that we should have secret providers, I just don't know if it covers every case. Like the one I mentioned where you have an extension that creates a new secret and wants to pass it around or return it. We could force users into the secret provider pattern there, and maybe we should, but it would be more awkward for some use cases than others

tepid nova
#

@civic yacht here's what I mean by "we could cache it in the engine memory"

  • Encode a json-serialized description of how to retrieve that secret (maybe "here's the plaintext", maybe "get it from this provider with those settings")
  • Return a "hash" of that description as secret ID
  • When buildkit calls for a secret, look up the description, retrieve the plaintext, return to buildkit
#

In that case the "hash" better be a real hash, otherwise you might be copy-pasting base64-encoded, gzip-compressed secrets around...

wet mason
civic yacht
#

I mean today if you call addSecret(plaintext:"shh") from an extension, the plaintext is never written to a file and thus not the cache. It goes over the unix socket to the cloak engine but is only stored in memory there. Then you get back the hash of the plaintext and that's what you actually pass around (and what gets stored in buildkit cache)

#

So I think even the current system is better than just directly passing around plaintext secret everywhere, IIUC

wet mason
#

Right, because of input caching

wet mason
tepid nova
#

Hard to say how secret providers will work until we have more clarity on the rest of the API IMO

#

Would it be crazy if IDs were hashes of graphql queries?

wet mason
#

I was looking at 1password yesterday and saw they had some cool that would have made our life easier in the past (invite script for instance)

Basically you can set environment variables as GH_TOKEN=op://daggerinc/github/token, then you run your programs with “op run — myscript.sh” and it translates those env variables with plain text secrets

civic yacht
tepid nova
#

Or if IDs were actually just string-encoded graphql queries??

wet mason
tepid nova
#

would spare us the trouble of inventing a polyfill on top of llb serialization... just use our gql schema as the polyfill

tepid nova
wet mason
#

I don’t know if 1password copied but they definitely came out later

tepid nova
wet mason
#

They’re getting into b2b, with GH actions etc

civic yacht
tepid nova
#

embedding ftw!

wet mason
#

Internally

#

Like everyone on the team could run yarn deploy

#

Without having to cruft a bunch of API tokens in env variables

wet mason
#

The thing I like about 1password is we’ve been talking about using aws-vault for a while, but it’s such a pita to set up AWS infra that we procrastinated and ended up with the mess of copying/pasting tokens manually until now

#

1password I could see myself using it in minutes for our CI/dev (especially since we already have a corp account to share e.g. typeform logins)

tepid nova
#

what if you sent several queries in the doc, and you could reference another query in the doc as an id?

#

basically nested queries

#

(orthogonal to secret providers)

civic yacht
tepid nova
#

todoapp deploy would be just one request

tepid nova
#

just the name of the query in the current graphql doc

civic yacht
#

I feel like @wild zephyr mentioned something like that recently, but I could be misremembering

#

Everything is becoming a blur

tepid nova
#

I'm going at it in small digestible pieces... This one is not too blurry @civic yacht 👆 , the scope is intentionally limited

wild zephyr
tepid nova
#

It's similar but not exactly the same

#

From what I understand, Sangria is trying to make that pattern usable for any graphql schema, using directives. In our case we only need it for our own schema, so we can probably do it without directives (I think)

#

I'm staring at this from their example, to make sure I understand it right:

query NewsFeed {
  feed {
    stories {
      id @export(as: "ids")
      actor
      message
    }
  }
}

query StoryComments {
  stories(ids: $ids) {
    comments {
      actor
      message
    }
  }
}
wild zephyr
#

I guess Sangria gets away with it since they also have an additional argument for operationNames where you need to specify the multiple nested opreations separately.

tepid nova
#

What I'm imagining we could do:

query Base {
  image("alpine") {
    exec(input: {
      args: ["apk", "add", "yarn"]
    }) {
      fs
    }
  }
}

query Install {
  filesystem(contents: "Base") {
    exec(input: {
      args: ["yarn", "install"]
    })
  }
}
wild zephyr
tepid nova
#

Way less manual stitching in code. Same benefit as chaining, but in cases where chaining isn’t possible

wild zephyr
tepid nova
#

I wouldn't call it fiddling with the spec (it doesn't require any deviation from the spec) but that doesn't mean it's a good idea 🙂

#

Generally graphql seems to be very OK with relying on introspection, so it wouldn't go against the spirit of the spec either IMO

#

I'm more worried about the additional implemetnation complexity on our end: you'd need to compute the graph of queries to resolve them in the correct sequence (sounds familiar? 🙂

wild zephyr
tepid nova
#

I don't think so but could be wrong

#

again there are many other reasons why this could be a terrible idea anyway

wild zephyr
tepid nova
#

Yes it's part of a wider conversation about core API design, how to make it as "graphql-ey" as possible, how to manage IDs, etc

#

Like @civic yacht said it's all becoming a blur 🙂

wild zephyr
#

let's grab a graphl gurus/gurvis without any context and ask them "how'd you express this in grahpql?". Done, ship it 😄

tepid nova
#

lol 🙂

#

"you want to express WHAT?"

tepid nova
#

welcome @vagrant goblet 🙂 The rest of your early access should arrive shortly but let's start with the discord channel!

vagrant goblet
#

hello friends! 👋
excited to play with cloak!

tepid nova
#

Welcome to the blur 🙂

#

Does buildkit getMount work only on regular mounts, or also on cache, tmp and secret mounts?

tepid nova
#

TIL graphql has an ID type

tepid nova
astral widget
#

👋 thanks for adding me

tepid nova
tawny flicker
wet mason
# wet mason Typically, yes

For different reasons:

  • There's more not just a SINGLE edge to reach a node (e.g. you can query the same object using different paths)

  • un-chaining: You might want to split a query into smaller ones. Let's say both "users" and "organizations" have Todo edges. You might craft one query each to get Todo IDs and have another query that goes Todo ID -> Todo item, so you can re-use generic code

  • It's part of the relay spec, which goes a notch beyond: you should have a top-level node and nodes query where you can pass ANY id in the system to retrieve a node (e.g. can retrieve a user or a todo using query { node(id: $id) }). Relay spec standardizes a few things on top of graphql to help with some usage patterns (e.g. if you follow it, you can re-use UI paginators etc that expect that spec). GitHub, buildkite, facebook implement the relay spec

  • It's required for caching / synchronization. Apollo client (and I'm sure other libraries) use a combination of id and __typename as a synchronization/cache key. Again with point 1), there's multiple paths to reach the same node. So you can't cache a query, that's pointless (the user "Andrea" might have been retrieved by user(name: "andrea") but also through workspace(name: "dagger") { members { ... } } -- if you cache by query you'd have 2 cache entries for the same object. If I change my name to al and you have multiple entries on screen for the same object, that may display conflicting information). Instead caching/sync is keyed by id+__typename

wild zephyr
vagrant goblet
#

@wet mason your mention of the Relay spec immediately makes me think that some iOS engineer is going to put a deploy button on some iPad for the office

#

@invariantly Taking a deeper look this morning -- I like how having this API machinery in front of buildkit creates both a multi language interface and runtime

I do wonder how verbose the primitives will get and what sorts of fragmentation might come out of language specific abstractions

vagrant goblet
obsidian rover
#

It may be a dumb question, but our router has a graphQL schema ? I mean, there is some graphql schemas there ?

#

Oooh, so it's the communication schema. There's a layer I don't get yet then

wild zephyr
obsidian rover
wild zephyr
civic yacht
tepid nova
#

@civic yacht @wet mason I am getting a little obsessed with the potential of multi-op documents + directives to help us handle the remaining API design issues, specifically:

  • Secrets
  • Uploads (push, deploy, publish etc)
  • Proper use of mutations
  • Unintuitive "stitch by ID" pattern (per @tawny lion feedback)
  • Dependencies
civic yacht
tepid nova
#

My brain kept spinning its wheels on this topic last night since the discussion. As I'm writing down the more straightforward parts of the API in https://github.com/dagger/cloak/pull/163, the blur is expanding to other areas 🙂

#

I'm finishing up some polish on 163 then will open a separate PR on top for the more "blurry" stuff

#

Let's just say when I look at a multi-op document, I'm having a hard time not seeing the stages of a Dockerfile 🙂

civic yacht
tepid nova
#

I think there's huge potential. If we could give a special role to your graphql document in the DX, that could simplify things in the SDK too, for example make it a standard practice to write your graphql document for a given extension and even script.

#

Add the right directives to express dependencies, and you have perhaps a way out of the dilemna of A) dependencies in yaml, dragging a weird runtime dependency along, or B) dependency in native code, making it harder to share and collaborate. Now maybe there is option C: everyone write a graphql document, that's where dependencies are expressed.

#

Secrets:

query netlifyToken @secret {
  host {
    variable(name: "NETLIFY_API_TOKEN")
  }
}

query run {
  container(address: "index.docker.io/alpine") {
    afterCommand(args: ["apk", "add", "yarn"] {
      withSecretVariable(name: "TOKEN", secret: "netlifyToken") {
        afterCommand(args: ["yarn", "install"]) {
          // ...
        }
      }
    }
  }
}

EDIT: simplified further by using op name as secret

#

I'm wondering if we could do the same thing with named volumes to facilitate passing Directories around

#
query appSource @volume {
  host {
    workdir(exclude: ["node_modules"]) {
      id // FIXME: can we simplify further and not need ID?
    }
  }
}

query run {
  container(address: "index.docker.io/alpine") {
    afterCommand(args: ["apk", "add", "yarn"] {
      withVolume(path: "/src", volume: "appSource") {
        withWorkdir(path: "/src") {
          afterCommand(args: ["yarn", "install"]) {
              afterCommand(args: ["yarn", "run", "build"]) {
                // ...
              }
          }
        }
      }
    }
  }
}

EDIT: simplified further by just using operation name as volume name

tawny flicker
#

Can somebody do a live with me to see what's wrong with my config? I don't quite get it

#

Error: failed to solve: input:5: core.filesystem.loadProject open /tmp/buildkit-mount2407612308/hugo/cloak.yml: no such file or directory

tepid nova
#

Loading an extension:

query netlify @extension {
  git(url: "ssh://git@github.com/dagger/cloak") {
    branch(name: "main") {
      contents {
        directory(path: "examples/netlify") {
          id
        }
      }
    }
  }
}

query run {
  netlify {
    // go about my business here...
  }
}
civic yacht
# tepid nova Secrets: ``` query netlifyToken @secret { host { variable(name: "NETLIFY_...

I like @secret and @volume but I also can't tell yet if this would be a better experience for, e.g., a js dev who just wants to write a script. Before we asked them to write a yaml file and then their code. Yaml file is annoying I completely agree and there has to be a way to make it optional or swappable for other formats. But if the change is just "write a graphql operation document with these custom directives" instead of yaml, then I don't know yet whether that's going to make them happier or sadder. Also, with the query run you have, does that entirely invalidate the need to write a script in e.g. js at all? What would the native code be doing?

Overall, I like the general idea a lot, I just am always hung up on whether we should be trying to find the "one correct format" or finding a way to support multiple possible formats. But I also don't have concrete suggestions at this point, so I think it's worth it to keep going down this operation document path

tepid nova
# tepid nova ``` query appSource @volume { host { workdir(exclude: ["node_modules"]) { ...

One step further, perhaps the resulting build is stored back into a volume?

query appSource @artifact {
  host {
    workdir(exclude: ["node_modules"]) {
      id // FIXME: can we simplify further and not need ID?
    }
  }
}

query appBuild @artifact {
  container(address: "index.docker.io/alpine") {
    afterCommand(args: ["apk", "add", "yarn"] {
      withArtifact(path: "/src", artifact: "appSource") {
        withWorkdir(path: "/src") {
          afterCommand(args: ["yarn", "install"]) {
              afterCommand(args: ["yarn", "run", "build"]) {
                directory(path: "/src/build") {
                  id
                }
              }
          }
        }
      }
    }
  }
}

EDIT: simplified further by just using operation name as volume name
EDIT: renamed "volume" to "artifact"

#

Mmm maybe "volume" is really "artifact

tepid nova
#

Another benefit is that it facilitates the transition from script to extension

#

Since that document is the first step towards defining an API of your own

tepid nova
#

It also opens the way to a manageable set of mutations, if you can reference named artifacts in a local namespace

#

eg.

mutation export(artifact: ArtifactName!, remote: RemoteName!)
wild zephyr
cosmic cove
#

If anyone missed the community call yesterday, you can watch the recording here or check out the notes in the community call invite 🙂

https://dagger-io.zoom.us/rec/share/DbsMFjH4FNoPr_Bk8e2w2c9ZXvs6-B-nyy8qHw5hGCMpFkCIGfWtpgVqsl3xj0X5.DkytfISEcgFjVQr2

Passcode: kgSc.9z9

wild zephyr
tepid nova
#
query netlifySite($name: String!) @remote {
  container(address: "samalba/netlify-cli") {
    withArtifact(path: "/site", artifact: "appBuild") {
      withWorkdir(path: "/site") {
        withSecretVariable(name: "NETLIFY_API_TOKEN", secret: "netlifyToken") {
          afterCommand(args: ["netlify", "deploy", "--site", $name]) {
            lastCommand { stdout } // FIXME return URL instead
          }
        }
      }
    }
  }
}
mutation push("netlifySite")
#
# Push to a remote
$ cloak push netlifySite

# Export the contents of an artifact
$ cloak export appBuild -o ./build
wild zephyr
tepid nova
#

It's a target for a push/upload

wild zephyr
tepid nova
#
  • @secret: create a named secret backed by the annotated query
  • @extension: load an extension backed by the annotated query
  • @artifact: create a named artifact backed by the annotated query
  • @remote create a named upload target backed by the annotated query
wild zephyr
#

thinking if push should be a mutation since the operation seems idempotent to me. If nothing changes from the remote and the cache is used, it should return the same site URL?

wild zephyr
tepid nova
#

We won't be able to force all remote implementations to guarantee that

#

Even our own implementation doesn't (we just force to always: true)

#

Separately from that, I don't know how to express a deployment / docker push / upload without using a verb... And the only accepted place to use a verb in graphql, apparently is a mutation

wild zephyr
tepid nova
#

One alternative is to skip the explicit push mutation altogether, and just auto-execute all @remotes in the document

#

This rigid classification (which implies a rigid sequence of execution: extensions first; then secrets and artirfacts; remotes last) reminds me of Bazel @tawny lion 🙂

wild zephyr
#

cries in Bazel

tepid nova
#

OK I'm really liking the direction of this draft. The examples feel fun to write and graphql-compliant

#

Taking a quick break then joining the fun in audio 🙂

civic yacht
tepid nova
#

OK I pushed a bunch of updates. I'm feeling pretty good about it. Whenever you have a few minutes to go over it and share your impressions:

#

Another good reason for JS to embrace a DX where they write a graphql document then interact with it from their code : it’s a graphql best practice which they will benefit from adopting even outside of cloak

#

Allows for various optimizations which are considered good in graphqlistan

hasty basin
#

@civic yacht @tepid nova love a 👍 on the docs website PR. https://github.com/dagger/cloak/pull/103 I just caught it up to current. Can go over it briefly at next community meeting if we merge it. Makes our Cloak docs website the first class way to consume the Cloak docs. Consistent with the current Dagger docs. Incremental revolution of the docs! 😄 (since it takes more time than you would think to get everything in the right spots).

tepid nova
#

How do I browse the docs? are they hosted somewhere?

hasty basin
civic yacht
# hasty basin Have an issue for hosting them open. Today you can browse the markdown in GitHub...

I did just realize that when one markdown file links to another on github the links are broken (also just saw that this is mentioned "The links in the docs assume you are viewing via the website.", so that's my bad for not noticing before).

The links in the main README still work, which is good, but is there any fix to that issue of links between markdown docs? Just to hold us over until we have them hosted

tepid nova
#

That would be nice. Also browsing via the repo is pretty useful even in parallel to the docs

hasty basin
#

I did a look around before and didn't see a well-trodden path, but will look again.

#

Looks like we can go to relative file links: https://docusaurus.io/docs/markdown-features/links, which are the kind we had before. Means files are less move-around-able, which is prob not as much of an issue for now. seems the slug in each page will take care of us. I'm learning 😄

civic yacht
tepid nova
civic yacht
tepid nova
#

Looks like github is down?

hasty basin
tepid nova
#

how cool would it be if cloak.yaml became cloak.gql 🙂

#

Could even include a query marked @source to make it completely standalone, this making the API sandbox way more useful (just copy paste the file’s contents into the web editor and you’re good to go)

#

With perhaps the exception of extension loading, unless we find voodoo incantations to bootstrap the full schema at runtime 😇

#

Otherwise that would require patching the playground with a hook to send extension queries before introspecting the schema

#

Logging off for now, enjoy tbe weekend everyone

tepid nova
hybrid widget
#

I was able to access graphql from PHP (using ext/curl) and build an image for my PHP webapp via cloak and a PHP build script. The "build" includes installing deps via composer and configuring apache docroot. Attaching the code in case anyone is interested in having a look

#

Now I'm wondering: if I have my PHP app code + above build/deploy script in gitlab and I normally deploy to heroku on every commit - could I do that with cloak? how?

tepid nova
tepid nova
#

Ideally there would be a heroku extension and you would be able to use that with a very small query

north jay
#

Building out some stuff in cue (classic dagger). Everywhere I need a utility to do something I either need to hardcode an image to use (yuck) or pass through a ref or docker.#Image.
It makes the API for these packages kind of messy.

I think the approach with cloak with extensions compiled from source as needed may be really nice.
Hoping to play soon.

tepid nova
dense haven
#

been playing with cloak a bit coming from classic dagger. I'm trying to build some binaries in my extension (all good), and then write some output from that to the host fs. seems like my best bet is writing a script and manually chaining the action output between the two? is there an easier way to chain queries like that in graphql? I saw https://github.com/dagger/cloak/issues/58 for example but I don't think this quite works for writing back to the host, since I need a LocalDir not a Filesystem.

seems related to https://github.com/dagger/cloak/issues/41 as well, but I assume that would look more like LLB / buildkit changes instead of trying to find a way with LocalDir

tepid nova
#

Note: you can use the interactive API playground with cloak dev to explore everything available under query { host } : all interactions with the host system go there

dense haven
#

So right now I've got something similar to go.#Build, but as an extension -- this might be more illustrative:

query ($source: FSID!) {
    gomod {
        build(source: $source) {
            # sanity: binary is there!
            exec(input: { args: ["/_out/bin/main"]}) {
                stdout
                stderr
            }
            # now I have a Filesystem
            # TODO: how to write the binary back to host?
        }
    }
}
#

seems like I could write a script, and then have the script take the output FSID and run the query you shared, but i'm mostly playing with cloak dev/do so far

tepid nova
#

Yes that's how you'd do it at the moment. You need to "stitch" multiple queries together in your code, by retrieving a FSID from query 1 then passing it as parameter to query 2

#

This particular script doesn't write to the host filesystem, but there's the same idea of stitching queries together in code. Pretty unavoidable as soon as you want to do something "real"

dense haven
#

the todo v2 demo was super helpful, thanks for that! I'll take a crack at scripting the queries together. the ability to chain things off of Filesystem with e.g. extend type Filesystem was pretty neat to get a lot done in one query (although maybe not an explicit goal) it looks like the approach with afterCommand/lastCommand is similar, will keep an eye on that 👀

tepid nova
#

@dense haven in case you're using the Go SDK, there's also a Go example in that same branch

#

As well as an example of wrapping your pipelines in an API extension

#

To recap, that branch has 3 examples:

  1. Script (gql client) in Javascript
  2. Script (gql client) in Go
  3. Extension (gql server + client) in Typescript
hybrid widget
hybrid widget
dense haven
dense haven
# tepid nova This particular script doesn't write to the host filesystem, but there's the sam...

I figured something out for my copying binaries out of Filesystem but not without some minor core changes. I has issues with core { workdir { write } } because it copies the entire FS, so I got a full FHS tree output to my workdir each time. I ended up changing localDirWrite to take an include: [String!] parameter just for testing, and did llb.Copy() into scratch before the export with the IncludePatterns set.

this is pretty well covered with cue classic since you can do that sort of thing already, so I expect it'll get sorted out 🙂

tepid nova
# dense haven from my own experimentation the scripts like https://github.com/dagger/todoapp/b...

Unfortunately the Go SDK is a special case, since it benefits from the engine itself being written in Go: that makes it easy to embed without requiring the cloak binary.

The Javascript/Typescript SDK however does require the cloak binary to be installed. A php SDK will require this too. @hybrid widget since a php sdk is not yet available, you will need to do that part yourself. It involves running cloak from your php code, then connecting to its socket

tepid nova
tawny flicker
#

Oh the irony.
I got throttled while I was searching for some message about ratelimiting in buildkit, and how to deal with authentication.
And for the life of me, I'm pretty sure @civic yacht talked about it last week, but I can't find the message/issue, etc.
So if anyone would be so kind to find it again, @stray heron needs it.
And if no such thing existed, I'm gonna do therapy about pretend issues that exists in my head.

stray heron
hybrid widget
# tepid nova Unfortunately the Go SDK is a special case, since it benefits from the engine it...

Thanks. I have tried the approach you suggested using the following .gitlab-ci.yml

image: docker:20.10-git
services:
  - docker:20.10-dind

stages:          
  - build

build:
  stage: build
  before_script:
    - |
      apk add go
      apk add php8
      cd /tmp
      git clone https://$GITHUB_USER:$GITHUB_TOKEN@github.com/dagger/cloak.git
      cd /tmp/cloak
      go build -v ./cmd/cloak
      mv cloak /usr/local/bin/
      cloak dev
  script:
    - php scripts/build.php```
#

However it fails at the go build stage with exit code 1. There's no further info. I've attached the build log for reference. Could you please see if there is some mistake or something I should be doing differently? Or any way to get more detailed debug messages?

wild zephyr
#

However it fails at the go build stage

wild zephyr
#

interesting to see what Netlify is doing with their Graph UI experience (https://youtu.be/t8FIcX2UyXg?t=702) . I can see some ideas we could take for how extensions are loaded in cloak's graph...

Integrating your site with different APIs can get complicated, and so Netlify launched Netlify Graph to help smooth that process. Phil doesn't know this very well yet and Netlify Graph is getting some impressive updates. So he asked Sean Grove, Principal Architect at Netlify and original creator of the Netlify Graph integration to give him a gui...

▶ Play video
wild zephyr
tawny flicker
#

Does input:5: core.filesystem.exec failed to unmarshal result: unexpected end of JSON input: ring a bell to you?
It's an error from graphql.Client.MakeRequest or at least from the code we generate. I don't want to dig into this if it's something somebody already faced it.

tepid nova
tepid nova
#

FYI I have pushed a major simplification of the Core API proposal. Thank you @civic yacht for the detailed feedback and notes. I think you're right that I pushed too far with custom directives, creating the risk of diverging from vanilla graphql.

I do have a few add-on proposals in store, but will leave them for future PRs to keep scope narrower. This proposal stands alone in its current form.

https://github.com/dagger/cloak/pull/163

README: https://github.com/shykes/cloak/blob/gql-builtins/builtins/README.md

Feedback, notes and questions welcome!

tawny flicker
tawny flicker
#

I'm getting some docker issues with my repro

dolanor@eastpeak:~/src/io/ci/repro$ curl -I https://registry-1.docker.io/v2/library/golang/manifests/1.18.2-alpine
HTTP/1.1 401 Unauthorized
content-type: application/json
docker-distribution-api-version: registry/2.0
www-authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/golang:pull"
date: Tue, 06 Sep 2022 12:34:52 GMT
content-length: 157
strict-transport-security: max-age=31536000
docker-ratelimit-source: 92.148.192.56
#
dolanor@eastpeak:~/src/io/ci/repro$ go run .
#1 local://__cloak_workdir
#1 transferring __cloak_workdir: 4.68kB done
#1 DONE 0.0s

#2 copy / /
#2 CACHED

#3 resolve image config for docker.io/library/golang:1.18.2-alpine
#3 ERROR: failed to do request: Head "https://registry-1.docker.io/v2/library/golang/manifests/1.18.2-alpine": dial tcp: i/o timeout
------
> resolve image config for docker.io/library/golang:1.18.2-alpine:
------
panic: failed to solve: input:24: core.filesystem.loadProject.install failed to do request: Head "https://registry-1.docker.io/v2/library/golang/manifests/1.18.2-alpine": dial tcp: i/o timeout
#

is it related with the authentication from buildkit?

#

Tried from my original example, same problem. It seems to be a docker issue

#

There is a shutdown from the hub? Is that the problem? It seems it was just a test

#

Ok, so the test was on the 2nd of september, to prepare for the real shutdown of the hub v1 API.
But the curl that fails is on the registry API, it seems somewhat unrelated.

wet mason
tawny flicker
#

I can't believe it

#

On my tethered phone, it works. But on my brand new kick ass fiber connection, I get a timeout…

mellow bolt
#

I'm deploying dagger.io with cloak. It works (except for some images issue that I need to figure). However, it's deploying to my own Team on Netlify. I want to be able to choose Netlify account dagger. I remember we use to have this for Europa:

env: {
  NETLIFY_SITE_NAME: site
  if (create) {
    NETLIFY_SITE_CREATE: "1"
  }
  if domain != null {
    NETLIFY_DOMAIN: domain
  }
  NETLIFY_ACCOUNT: team <------- HERE ----------
}
tawny flicker
#

It's even weirder, my phone is actually connected to my wifi router, to which my computer is connected. So it's actually the same router in the end…

mellow bolt
#

I guess we should implement it for cloak cc @wet mason @civic yacht

wet mason
#

yep, that's just some example code

wet mason
civic yacht
civic yacht
wet mason
#

@civic yacht Hey are you aware of the netlify setup? Not sure where it came from and all PRs are red

civic yacht
hasty basin
#

@civic yacht @wet mason I'm guessing it's from the team working on getting the Cloak website to deploy.

#

@mellow bolt @dense dust ☝️

#

Could we only run those checks on PRs to /website or /docs?

mellow bolt
#

yes error are coming from cloak docs (sorry about that)

hasty basin
mellow bolt
dense dust
#

I'm looking at it too, will update if I find something

mellow bolt
#

Ok I've just updated the branch with Github and it seems to fix the problem

#

I'm means for docs deployment at least

dense dust
#

Yep, seems to work! Thx

tepid nova
#

@civic yacht want to talk live about DX? The core API proposal shrank back to a pretty reasonable scope, nothing too surprising in there I think (still plenty of bikeshedding opportunities of course)

However we need to talk about doc-centric DX and all the ramifications of that

#

I allude to it in 163 README but it deserves a whole discussion on its own

civic yacht
tepid nova
wild zephyr
#

https://youtu.be/t8FIcX2UyXg?t=3084

^ @tepid nova encourages to watch a few mins of this for inspiration. Particularly how we could start approaching a doc-centric DX

Integrating your site with different APIs can get complicated, and so Netlify launched Netlify Graph to help smooth that process. Phil doesn't know this very well yet and Netlify Graph is getting some impressive updates. So he asked Sean Grove, Principal Architect at Netlify and original creator of the Netlify Graph integration to give him a gui...

▶ Play video
civic yacht
#

@twin crow lemme know if I can help with the question you were asking before the meeting started

twin crow
#

so not really a question anymore 😛

civic yacht
hasty basin
#

👋 @radiant vortex

radiant vortex
#

Hey yall thanks so much for the invite!

hasty basin
radiant vortex
#

Really like the non-yaml ness of dagger, imports, and ability to run local. Trying to read through the docs here on cloak.. seems the non yaml bit may have changed 😱

hasty basin
hasty basin
#

We're constantly interating on better DX.

civic yacht
#

^ Yes it's just holding us over until we have something better 🙂

hasty basin
#

Welcome back to YAML hell! 👿 jk 😇

radiant vortex
#

gotcha hah. yeah, some guys on the team are pretty anti yaml (at least for controlling execution flow) . one of the main reasons we're still in jenkins.

I'm actually a tekton fan, but implementing any kind of looping/conditional logic in yaml gets ugly quick, and thus we're still on the 50 year old jenkins train

#

I'll have to tune into the talk!

tepid nova
#

@civic yacht @wild zephyr @hasty basin we tried writing a mock dagger.gql for todoapp… And were surprised to discover that in this particular example, an extension is not actually needed. Backend and frontend team can just reuse the operations file

#

i find that very promising because it would push the creation of extension further down the onboarding path, which probably would make the learning curve less daunting

#

basically extensions would be a power user feature

#

Not necessarily needed for team collaboration. Perhaps more of a “scale collaboration to hundreds of engineers” feature

#

Extensions could still ship operation files as examples -> which plugs into the workflow @wild zephyr described

civic yacht
# tepid nova Not necessarily needed for team collaboration. Perhaps more of a “scale collabor...

Also needed if you are trying to do something like import a library in some language. Can't import a go library into graphql code. But that very well may end up being a power user feature, hard to say right now.

But yeah I think that's very promising. From my perspective, if you squint this is almost like being able to author an extension with the GraphQL SDK 🙂 And that's a good thing since in the current extension authoring DX you have to write graphql anyways, why not just write the whole thing in graphql when possible. Like I said before, my dream is that we can abstract graphql away from the extension author DX, at which point you'd still have this GraphQL SDK but also equally nice ones in other languages like Go where you can ignore graphql entirely. But if that dream doesn't pan out, then the graphql sdk grows even more in importance. Point being that either way I think we should keep going down this route.

#

Interested to see the mock dagger.gql whenever you have time to push it somewhere

civic yacht
wild zephyr
twin crow
#

there are many ways to expose the Engine, I started copying the Javascript implem with a callback, but ended up using a context, more python-native to my taste... Anyhow, if anyone wants to join the fun, I opened the draft PR to avoid duplication of effort.

tepid nova
median charm
#

Hey 🙂 Thx for the invite - excited to take a closer look

tepid nova
#

Welcome @median charm ! Fair warning the docs are still quite rough and partially out of date, as the code is moving fast. Please don't hesitate to ask any question here at any time. No such thing as a dumb question here!

median charm
#

Thx @tepid nova - and thanks for the heads up 🙂 I will dig in and see what's there

tepid nova
#

Do you have a use case in mind for testing it? Maybe an existing pipeline, or a tool you'd like to integrate with?

tepid nova
#
"Load netlify API token from host environment"
query netlifyToken {
  host {
    secretVariable(name: "NETLIFY_API_TOKEN") {
      id
    }
  }
}

"Load source code from host working directory"
query source {
  host {
    workdir(exclude: ["node_modules"]) {
        id
    }
  }
}

"A builder container with the app mounted"
query builder {
  container(id: "index.docker.io/alpine") {
    afterExec(args: ["apk", "add", "yarn", "openssh", "git"] {
      withMountedDirectory(source: "source", path: "/src") {
        withWorkdir(path: "/src") {
          withMountedCache(path: "/var/cache/yarn") {
            withVariable(name: "YARN_CACHE_FOLDER", value: "/var/cache/yarn") {
              id
            }
          }
        }
      }
    }
  }   
}

"Build the app"
query build {
  container(id: "builder") {
     afterExec(args: ["yarn", "install"]) {
      afterExec(args: ["yarn", "run", "build"]) {
        directory(path: "./build") {
          id
        }
      }
    }
  }
}

"A container setup to deploy the app"
query deployer($contents: DirectoryID!) {
  container(id: "index.docker.io/alpine:latest") {
    afterExec(args: ["apk", "add", "npm"]) {
      afterExec(args: ["npm", "-g" "install", "netlify-cli@8.6.21"]) {
        withMountedDirectory(source: $contents, path: "/site") {
          withWorkdir(path: "/site") {
            withSecretVariable(name: "NETLIFY_API_TOKEN", secret: "netlifyToken") {
              id
            }
          }
        }
      }
    }
  }
}

query deploy($siteName: String!) {
  container(id: "deployer") {
    afterExec(args: ["netlify", "deploy", "--site", $siteName]) {
      stdout // FIXME: return URL instead
    }
  }
}
#

In-document stitching in action 🙂

obsidian rover
tepid nova
#

Yes it's all in that PR. With one small detail...

#

There is no implementation 🙂 I'm just writing mockup queries that I hope to run one day soon! But first I want to get feedback on the DX. wdyt?

#

There's a detailed README in PR 163 where I go over design highlights and the rationale behind them

#
  • full graphql schema with comments
#

This example above is in the README, along with a few more

obsidian rover
#

Thanks, will look more closely today 😇

mellow bolt
#

same

tepid nova
#

Note that if we copied the ideas from Netlify Graph re: shareable and runnable examples, then soon all those examples could be runnable in one click from your Dagger Cloud account 🙂

mellow bolt
#

that would be awesome

tepid nova
#

I really think the in-doc stitching (query can reference other query) is a gamechanger. It's like multi-stage dockerfiles... but cleaner

#

And all graphql spec-compliant and supported out of the box by GraphiQL playground

obsidian rover
#

Btw, I had in interest into building an SDK/seing how to make one. I saw Sam's draft PR on Python. Shall we focus on helping him or making a parallel one (ruby?) [bash seems to ambitious for me, as no type system]

tepid nova
#

That would be a fun project, as long as you consider it to be a throwaway prototype

obsidian rover
tepid nova
#

DX will most likely keep moving in the next few weeks, in a way that will change how SDKs work and integrate with the core

tepid nova
#

Personally I recommend using it first, before writing a SDK (unless you write the SDK and use it for something)

#

Just using cloak to do something

#

Now that kids are finally sleeping, I should go to sleep but I'm too excited 🙂

mellow bolt
#

I've used cloak to deploy dagger.io. Now I would love to get a preview URL on github (like Netlify)

#

ok

#

have a good sleep

tepid nova
obsidian rover
obsidian rover
mellow bolt
#

Do we have cloak implementation for Github action ?

#

Naive question: Is the current dagger-for-github repo can just use the cloak binary ?

tidal spire
#

Maybe someone more familiar with genqlient can help me out, I'm probably overlooking something simple here. How come gen/core/generated.go does not have an implementation for addSecret(plaintext: String!): SecretID!?

tawny flicker
mellow bolt
civic yacht
# tidal spire Maybe someone more familiar with genqlient can help me out, I'm probably overloo...

At the moment, generated clients only include methods for operations that have been explicitly defined (operations are different than the schema). For extensions under examples, you'll see the operations defined in operations.graphql. core is special because it's builtin to cloak, so the operations are found here: https://github.com/dagger/cloak/blob/a3aad6f11e994def546a954ccc238877d1e4b56b/core/core.schema.go#L65-L91

If we want AddSecret to be included in the generated stubs for core, we'd need to just add an operation for it there.

To be very very clear, this is all unnecessarily convoluted and just an artifact of how we could quickly get things going in the earlier prototyping phase. The approach outlined here should be our saving grace and let us skip defining custom operations that are just wrappers around really simple calls to schema: https://github.com/dagger/cloak/pull/174

tidal spire
wild zephyr
hasty basin
#

@stray heron @wild zephyr @hybrid widget @tidal spire @twin crow any of y'all considering demos/mini-demos for tomorrow's Cloak community call? Anyone else? 🙂 Even if you don't have a demo, we'd love to hear use cases, wishlists, half-baked project ideas, etc.
https://docs.google.com/document/d/1-6RSWHwFoZr588kftPLVvT1RCHUrOrnmURldBRrP1Ak/edit#

hasty basin
stray heron
hasty basin
tepid nova
#

@hasty basin sign me up for a demo of my demoV3 mock-up featuring doc-centric DX 🙂

hybrid widget
#

Hi guys, I have a graphql query running in PHP

        query {
          core {
            image(ref: "php:8.1-apache") {
              exec(
                input: {mounts: [{fs: "{$workdirFsid}", path: "/mnt"}], workdir: "/var/www", args: ["sh", "-c", "cp -R /mnt/* /var/www/ && rm -rf /var/www/vendor"]}
              ) {
                fs {
                  exec(
                    input: {args: ["sh", "-c", "apt-get update && apt-get install -y curl git zip"], workdir: "/var/www"}
                  ) {
                    fs {
                      composer: exec(
                        input: {workdir: "/var/www", args: ["sh", "-c", "curl -sS https://getcomposer.org/installer | php && php composer.phar install --no-scripts"]}
                      ) {
                        exitCode
                        stderr
                        stdout
                      }
                      apache: exec(
                        input: {workdir: "/var/www", args: ["sh", "-c", "sed -ri -e 's!/var/www/html!/var/www/public!g' /etc/apache2/sites-available/*.conf && sed -ri -e 's!/var/www/!/var/www/public!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf && a2enmod rewrite"]}
                      ) {
                        exitCode
                        stderr
                        stdout
                      }
                    }
                  }
                }
              }
            }
          }        
        }

It fails with this error dump

                    [message] => process "sh -c curl -sS https://getcomposer.org/installer | php && php composer.phar install --no-scripts" did not complete successfully: exit code: 1

Any suggestions for why?

twin crow
twin crow
tawny flicker
#

for me, it must be because I don't have any FS var set up

#

(I actually don't know how to read from workdir from a graphiql instance, is it possible?)

civic yacht
#

@hybrid widget @twin crow Right now if an execop fails the output will not be included with the graphql error returned to you. You currently have to look at the buildkit progress logs from cloak, which will have output from the command that failed

#

So if you are using cloak dev you have to look at the output of that binary

hybrid widget
#

@tawny flicker I have obtained the FSID in a separate query

    public function buildContainerWithDeps() {

        $workdirFsid = $this->getWorkdirFsid();
        $containerWithDepsQuery = <<<EOF
        query {
          core {
            image(ref: "php:8.1-apache") {
              exec(
                input: {mounts: [{fs: "{$workdirFsid}", path: "/mnt"}], workdir: "/var/www", args: ["sh", "-c", "cp -R /mnt/* /var/www/ && rm -rf /var/www/vendor"]}
              ) {
                fs {
                  exec(
                    input: {args: ["sh", "-c", "apt-get update && apt-get install -y curl git zip"], workdir: "/var/www"}
                  ) {
                    fs {
                      composer: exec(
                        input: {workdir: "/var/www", args: ["sh", "-c", "curl -sS https://getcomposer.org/installer | php && php composer.phar install --no-scripts"]}
                      ) {
                        exitCode
                        stderr
                        stdout
                      }
                      apache: exec(
                        input: {workdir: "/var/www", args: ["sh", "-c", "sed -ri -e 's!/var/www/html!/var/www/public!g' /etc/apache2/sites-available/*.conf && sed -ri -e 's!/var/www/!/var/www/public!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf && a2enmod rewrite"]}
                      ) {
                        exitCode
                        stderr
                        stdout
                      }
                    }
                  }
                }
              }
            }
          }        
        }
        EOF;
        
        $response = $this->query($containerWithDepsQuery);
        return json_decode($response);
    }
civic yacht
#

It is possible to include the output w/ the graphql error, but actually trickier than it may seem. I'll create an issue describing how we could do it since it's clearly needed once someone has time to implement it

hybrid widget
civic yacht
hybrid widget
#

In case it helps, this is the output I see in the gitlab output

#30 sh -c curl -sS https://getcomposer.org/installer | php && php composer.phar install --no-scripts
#30 0.813 All settings correct for using Composer
#30 0.814 Downloading...
#30 2.842 
#30 2.842 Composer (version 2.4.1) successfully installed to: /var/www/composer.phar
#30 2.842 Use it: php composer.phar
#30 2.842 
stdClass Object
(
    [data] => 
    [errors] => Array
        (
            [0] => stdClass Object
                (
                    [message] => process "sh -c curl -sS https://getcomposer.org/installer | php && php composer.phar install --no-scripts" did not complete successfully: exit code: 1
                    [locations] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [line] => 12
                                    [column] => 15
                                )
                        )
                    [path] => Array
                        (
                            [0] => core
                            [1] => image
                            [2] => exec
                            [3] => fs
                            [4] => exec
                            [5] => fs
                            [6] => composer
                        )
                )
        )
)```
tepid nova
#

Looks like we're still need Dagger Cloud to debug even with cloak 🙂

hybrid widget
#

The weird thing is that it says

#30 2.842 Composer (version 2.4.1) successfully installed to: /var/www/composer.phar
#30 2.842 Use it: php composer.phar```
which is the expected output for a successful command, yet it indicates failure
civic yacht
#

This is how we can fix it: https://github.com/dagger/cloak/issues/182

which is the expected output for a successful command, yet it indicates failure
@hybrid widget Yeah that's odd, is the command exiting non-zero even though it succeeded? I'd try seeing if you do || echo $? if you get any output. Could also split the commands combined with && up into separate steps just temporarily to make it more clear which one is exiting non-zero

hybrid widget
#

Using ||true gave me some clues

[stderr] => Do not run Composer as root/super user! See https://getcomposer.org/root for details
Composer could not find a composer.json file in /var/www
To initialize a project, please create a composer.json file. See https://getcomposer.org/basic-usage

Again the weird thing is that the file composer.json should be there as it's part of the source repo. However it looks like it's not being found. I'm now checking further to see if I can figure out what's going wrong

civic yacht
#

The other thing we should do to help here is add the ability to drop into a shell on any execop (even failed ones) so you can poke around manually, run commands, etc. for debugging. If we do it right, should work both from command line and cloud.

tawny flicker
civic yacht
hybrid widget
tepid nova
#

This reminds me that we should remove the use of cloak dev to run the embedded engine. IMO part of the "bundle buildkit" contribution thread.

/cc @civic yacht @wet mason

civic yacht
tepid nova
#

Yeah I just mean it should be different subcommands

#

(at the very least)

#

(also the port conflict you mentioned)

#

Longer term (but not that long term, launch horizon) there is the possibility that one moves into the user-facing client tool (dagger) and the other remains in a separate engine binary (cloak) to be embedded and instrumented by dagger. Not sure we'll end up doing that but it's plausible and would have advantages

hybrid widget
#

Just for context, my use case is: build the app container on Gitlab with cloak (done), then push to registry (pending) and deploy from registry on heroku (pending)

civic yacht
# hybrid widget I read this and it looks like you can export to a local directory, though not an...

If you export a Filesystem to a local directory it just means the contents of the FS will be unpacked into that local dir. At the moment, we only support exporting to the root of your project workdir, so I suppose in your case that would mean to the place where you are running cloak on the gitlab runner, which is not really very convenient I'm guessing. Until we add the image export support, that's really all you can do though unfortunately. It's very easy to add support, we just haven't had time yet.

tepid nova
#

cc @tawny flicker 😇 👆

hybrid widget
#

I'm running cloak dev in the root directory of the cloned repo. So if I understood correctly, exporting the FS would unpack the entire image filesystem contents into that location?

civic yacht
hybrid widget
#

OK I see

tepid nova
#

Speaking of which @civic yacht did you see the tweaked version of container push in 163?

civic yacht
hybrid widget
#

After preparing and building the container image with cloak, what would be the next step I can take (with the currently available functions)?

tepid nova
#

FYI in latest iteration of new core API proposal, @hybrid widget 's query would look like this:

query($workdir: DirectoryID!, $repository: String!) {
 container(id: "php:8.1-apache") {
  withMountedDirectory(source: $workdir, path: "/mnt") {
   withWorkdir(path: "/var/www") {
    afterExec(args: ["sh", "-c", "cp -R /mnt/* /var/www/"]) {
     withoutDirectory(path: "/var/www/vendor") {
      afterExec(args: ["sh", "-c","apt-get update && apt-get install -y curl git zip"]) {
       composer: afterExec(args:["sh", "-c",
        """
        set -e
        curl -sS https://getcomposer.org/installer | php
        php composer.phar install --no-scripts
        """]) {
         afterPush(repository: $repository, tag: "composer") {
          ref
         }
        }
       }
      }
      apache: afterExec(args: ["sh", "-c", """
        set -e
        sed -ri -e 's!/var/www/html!/var/www/public!g' /etc/apache2/sites-available/*.conf
        sed -ri -e 's!/var/www/!/var/www/public!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
        a2enmod rewrite
        """]) {
       afterPush(repository: $repository, tag: "apache") {
        ref
       }
      }
     }
    }
   }
  }
 }
}
hybrid widget
#

I believe that even the rm -rf /var/www/vendor could be replaced with withoutDirectory(path: "vendor")?

tepid nova
#

Ah true 🙂

#

Maybe we could add afterCopy or something like that?

civic yacht
tepid nova
#

I didn't think of the case where you want to copy a directory to a new location on the same root dir

#

@civic yacht might be worth adding a binding to llb.shexpr given the prevalance of args: ["sh", "-c", ...] ?

hybrid widget
# civic yacht Until we have image export, I'm not there's any good options for your use case (...

The reason I am trying to have this flow working is that I think it would be a great topic for a tutorial eg. "build/deploy your [language] app from gitlab to heroku with cloak". Once the image is pushed, then I can probably use the heroku cli to pull the image from docker hub and deploy it - but as you say, this is blocked until the image push function is available. In the meanwhile, I might try to replicate in github actions what I have done so far in gitlab CI...expect more questions soon! 🙂

#

In the meanwhile I'd appreciate any suggestions to improve this Gitlab CI script. It works but could probably be better

image: docker:20.10.16-git
services:
  - docker:20.10.16-dind
variables:
  DOCKER_HOST: tcp://docker:2376
  DOCKER_TLS_VERIFY: "1"
  DOCKER_TLS_CERTDIR: "/certs"
  DOCKER_CERT_PATH: "/certs/client"
stages:
  - build

setup:
  stage: build
  script:
    - |
      apk add go wget php8 php8-curl php8-iconv php8-openssl php8-phar curl
      DIR=`pwd`
      cd /tmp
      git clone https://$GITHUB_USER:$GITHUB_TOKEN@github.com/dagger/cloak.git
      cd /tmp/cloak
      go build ./cmd/cloak
      mv cloak /usr/local/bin/
      cd $DIR
      cloak dev &
      wget -qO- https://raw.githubusercontent.com/eficode/wait-for/v2.2.3/wait-for | sh -s -- --timeout 200 localhost:8080 -- echo 'cloak is up'
      php scripts/build.php
civic yacht
# hybrid widget The reason I am trying to have this flow working is that I think it would be a g...

Yeah, to be clear the feature you're asking for, image export, is not some strange exotic thing at all, it's a really really basic feature that we just happen to have not had an explicit request for until now. That sounds like a great tutorial to have. But good to hear you have something else to look at while blocked. Please keep asking questions and requesting features for all the basic things we're still missing 🙂

tepid nova
#

If I understand correctly the state of the art in gql client generation... there is no way currently to "flatten" the response by skipping intermediary structs and returning only the "bottom" of the query (the part with the scalar fields I want).

For example from this query:

query deploy {
  container {
    afterExec {
      file {
       contents
      }
    }
  }
}

I would ideally get this generated response type:

type DeployResponse struct {
  Contents string
}

And retrieve my value with resp.Contents

But instead I will get this:

type DeployResponse struct {
  Container struct {
    AfterExec struct {
      File struct {
        Contents string
      }
    }
  }
}

And I must retrieve my value with resp.Container.AfterExec.File.Contents.

This has 2 downsides:

  1. It's verbose
  2. It leaks implementation detail of the underlying gql query, which I may not have authored

Do I understand the situation correctly? And if so, is there hope? 🙂

#

I looked through the genqlient custom directive bud sadly, I didn't see any mention of this problem

civic yacht
tepid nova
#

genqlient has a @genqlient(flatten: true) but it seems unrelated sadly

tepid nova
#

Or more like the Hasura style "create your own go types on the fly" ?

#

(I don't know anything about that PR sorry)

civic yacht
#

There are still cases where predefined operations are nice, just much less often

tepid nova
#

I believe that's how our blocklayer API client worked back from before we open-sourced dagger

#

I have memories of using that pattern and that was my only gql project

#

We need to go over the pros and cons of each generation method, and decide together which path to take. Doc-centric and query builder seem mutually exclusive and they have vastly different implications for the entire DX. I'd say that decision is in the critical path and should be next on the docket.

#

(looks abandoned, js only and pretty invasive syntax)

civic yacht
tepid nova
# civic yacht I don’t think they are mutually exclusive at all, they are probably very complem...

I guess you're right that a doc-centric DX doesn't necessarily entail using only generated types. But it does assume your queries are already written, and don't need to be created in code. You could still reference the pre-written query by name but build your response type in code with the builder pattern. But it would still suffer from lack of flattening: verbosity and abstraction leak would still be there, no?

#

Or maybe you meant that "flattening magic" can always be implemented as a convenience in either generated clients or a query builder?

civic yacht
hasty basin
fickle sedge
#

hi everyone, I was wondering if Cloak is released to public in the future and success, what will be the plan for the dagger/dagger?

wet mason
#

@fickle sedge dagger/dagger will still be the main thing. Plan still TBD on whether cloak code is ported inside dagger/dagger, or if cloak is a component of dagger/dagger

hasty basin
#

@here In about 15 minutes we have our next Cloak Community Meeting! Last week folks indicated that they wanted to see more Cloak demos and we've got 6 or 7 this week!! daggerfire 🚀

See you at 10am PT! Agenda here: https://docs.google.com/document/d/1-6RSWHwFoZr588kftPLVvT1RCHUrOrnmURldBRrP1Ak/edit#

wet mason
# hasty basin @here In about 15 minutes we have our next Cloak Community Meeting! Last week fo...
tepid nova
#

That demo app @tidal spire 😂

tidal spire
wet mason
tepid nova
#

Thank you for the amazing demos @tidal spire @wild zephyr @twin crow @stray heron

tawny flicker
#

That was an INTENSE session!

stray heron
tawny flicker
tepid nova
wild zephyr
#

@civic yacht @wet mason we should sync to align about the code generation / debug containers thing so we can keep adding more useful things to the playground for rapid extension / workflow prototyping

#

specially if the stitching proposal is going to be under review few a bit more time

#

also @dense dust tomorrow talk about the possibilities about embedding that in graphiql

dense dust
civic yacht
tepid nova
wild zephyr
tight socket
#

Where can I view some of the demo apps?

tepid nova
tepid nova
tight socket
tepid nova
dense dust
fickle sedge
#

Hey guys, i tried the cloak-demo-v2-extension and got this error:

yarn run v1.22.17
$ node scripts/deploy/index.mjs

                Netlify site name not specified in $NETLIFY_SITE_NAME.
                Defaulting to "tuongaz-dagger-todoapp".
        
node:internal/errors:465
    ErrorCaptureStackTrace(err);
    ^

Error: spawn cloak ENOENT
    at Process.ChildProcess._handle.onexit (node:internal/child_process:283:19)
    at onErrorNT (node:internal/child_process:478:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn cloak',
  path: 'cloak',
  spawnargs: [
    'dev',
    '--workdir',
    '/Users/tuongaz/dev/cloak-demo',
    '-p',
    './cloak.yaml',
    '--port',
    '8080'
  ]
}

any idea why? I have started the cloak dev and confirmed it's working

dense dust
bronze hollow
#

Is there a recording? I've been having some airport issues and missed the call

tepid nova
#

either that or can’t find cloak.yaml maybe?

civic yacht
tepid nova
#

Ah! Glad you figured it out 🙂

#

Adding the cloak binary to our npm package would solve it neatly

#

Also will proactively avoid the inevitable version mismatches (sdk should bundle a specific version and update it on its own schedule)

civic yacht
#

Agree that's the right way. I think python has similar abilities to include binaries. If we ever encounter a language w/out it I guess the fallback is to just put a URL+hash in the language's SDK to download the binary from, but can avoid that for as long as possible

hasty basin
tepid nova
#

@wild zephyr @dense dust there is no scenario where having a cloud playground with graphiql + an interactive console ala chrome devtools is not AWESOME

#

I would use that all day every day

hasty basin
rancid turret
rancid turret
#

Is cloak handling image metadata? Just see Filesystem.

tepid nova
rancid turret
#

I see the potential in query chaining, but for anything past basic you can get very deeply nested which feels a bit icky to me. "Flat is batter than nested" and all. Has anyone said anything about it?

tepid nova
#

No there has been no bikeshedding whatsoever

#

(that’s a joke of course)

tepid nova
#

So it maps directly to the llb api itself (chaining function calls). Feels weird in the beginning because of all the curly braces but actually works well

rancid turret
#

Yeah, makes sense.

tepid nova
#

Then when the query gets too long -> you collapse it with a graph extension. Literally a shortcut edge in the graph 🙂

rancid turret
#

Good point!

#

Cloak is turning out more powerful than I imagined, before July.

tepid nova
#

graphql started out as an implementation detail but has turned into a major design win

rancid turret
#

Yes, who thought it would be useful to have a QL for a DAG? 😆

wild zephyr
tawny flicker
#

Question about extension transitive dependencies: if an extension requires a dependency, does an extension or a cloak app requires to declare that transitive dependency as well?
(my hunch would be no, as it's mostly for code generation, and that code would only be required on the extension, not on the user of the extension itself)

cosmic cove
tepid nova
civic yacht
tepid nova
#

What!!

tawny flicker
#

Oh, let me take that back, then :p

tepid nova
#

how, when

tawny flicker
#

yesterday, in 5mn when Erik took a break

civic yacht
#

I gotta go do the demo in a minute, but I did that week or two ago, can find the commit after

tawny flicker
#

(jk)

tepid nova
#

me trying to keep up with cloak development pace 👆

tawny flicker
#

Yep, that's my feeling as weel

strong coral
#

What passes arguments from cloak to extensions?

strong coral
#

I think

#

where does go build -o /entrypoint -ldflags -s -d -w come from?

#

found it