Support for host names with wildcards

When looking up for an AuthConfig by host name (authorization request), the longest host name match in the cache wins.
E.g., given the following host -> authconfig relation:
*.io                          -> auth-1
talker-api.nip.io, *.pets.com -> auth-2
api.acme.com                  -> auth-3
*.acme.com                    -> auth-4

Expect the following lookup results:
dogs.pets.com     -> auth-2 (matches *.pets.com)
api.acme.com      -> auth-3 (matches api.acme.com)
www.acme.com      -> auth-4 (matches *.acme.com)
talker-api.nip.io -> auth-2 (matches talker-api.nip.io)
foo.nip.io        -> auth-1 (matches *.io)
foo.org           -> 404

Without support for wildcards:
dogs.pets.com     -> 404
api.acme.com      -> auth-3 (matches api.acme.com)
www.acme.com      -> 404
talker-api.nip.io -> auth-2 (matches talker-api.nip.io)
foo.nip.io        -> 404
foo.org           -> 404

~Support for wildcards can be enabled/disabled at the level of the Authorino instance by setting WILDCARDS_ENABLED=true|false (default: false)~

[x] ~Open issue in kuadrant/authorino-operator for exposing WILDCARDS_ENABLED in the Authorino CR~ - https://github.com/Kuadrant/authorino-operator/pull/78

Prevention of host name collisions between k8s namespaces is still subject to the order that the AuthConfigs are reconciled and host names ared listed within each AuthConfig. E.g. if talker-api.nip.io is accepted first, other user can still define *.io second; on the other hand, if one defines *.io first, talker-api.nip.io will be considered are taken host name and it will NOT be accepted second.

#317

Closes #306
Verification steps
Build, deploy, setup:
make local-setup FF=1

Apply the AuthConfigs:
kubectl apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: auth-1
spec:
  hosts:
  - "*.io"
  response:
  - name: x-auth-data
    json:
      properties:
      - name: authconfig
        value: auth-1
---
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: auth-2
spec:
  hosts:
  - "*.pets.com"
  - talker-api.nip.io
  response:
  - name: x-auth-data
    json:
      properties:
      - name: authconfig
        value: auth-2
---
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: auth-3
spec:
  hosts:
  - api.acme.com
  response:
  - name: x-auth-data
    json:
      properties:
      - name: authconfig
        value: auth-3
---
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: auth-4
spec:
  hosts:
  - "*.acme.com"
  response:
  - name: x-auth-data
    json:
      properties:
      - name: authconfig
        value: auth-4
EOF

It will produce the following tree:
                   ┌───┐
         ┌─────────┤ . ├──────────┐
         │         └───┘          │
         │                        │
         │                        │
      ┌──┴─┐                   ┌──┴──┐
  ┌───┤ io ├───┐           ┌───┤ com ├───┐
  │   └────┘   │           │   └─────┘   │
  │            │           │             │
  │            │           │             │
  │            │           │             │
┌─┴─┐       ┌──┴──┐    ┌───┴──┐      ┌───┴──┐
│ * │       │ nip │    │ pets │    ┌─┤ acme ├─┐
└───┘       └──┬──┘    └───┬──┘    │ └──────┘ │
  ▲            │           │       │          │
  │            │           │       │          │
  │            │           │       │          │
  │      ┌─────┴──────┐  ┌─┴─┐  ┌──┴──┐     ┌─┴─┐
auth-1   │ talker-api │  │ * │  │ api │     │ * │
         └────────────┘  └───┘  └─────┘     └───┘
               ▲           ▲       ▲          ▲
               │           │       │          │
               │           │       │          │
               └───auth-2──┘     auth-3     auth-4

Send requests:
curl -H 'Host: dogs.pets.com' http://localhost:8000 -i     # x-auth-data.authconfig == auth-2
curl -H 'Host: api.acme.com' http://localhost:8000 -i      # x-auth-data.authconfig == auth-3
curl -H 'Host: www.acme.com' http://localhost:8000 -i      # x-auth-data.authconfig == auth-4
curl -H 'Host: talker-api.nip.io' http://localhost:8000 -i # x-auth-data.authconfig == auth-2
curl -H 'Host: foo.nip.io' http://localhost:8000 -i        # x-auth-data.authconfig == auth-1
curl -H 'Host: foo.org' http://localhost:8000 -i           # 404

Extra: Make things weird by overriding a host name:
kubectl apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: auth-5
spec:
  hosts:
  - talker-api.nip.io
  response:
  - name: x-auth-data
    json:
      properties:
      - name: authconfig
        value: auth-5
EOF

curl -H 'Host: talker-api.nip.io' http://localhost:8000 -i # x-auth-data.authconfig == auth-5
curl -H 'Host: dogs.pets.com' http://localhost:8000 -i     # x-auth-data.authconfig == auth-2

kubectl delete authconfig/auth-5

curl -H 'Host: talker-api.nip.io' http://localhost:8000 -i # x-auth-data.authconfig == auth-1
curl -H 'Host: dogs.pets.com' http://localhost:8000 -i     # x-auth-data.authconfig == auth-2

I think it would be best if we also allowed this order of creation. I would say having a wildcard host as a fallback would be a quite common use case and having it depend on the order of creation doesn't seem like a great user experience.

We need some heuristic to decide on when a particular host is taken, otherwise users can freely override each other's AuthConfigs. If you somehow also control the routing or in the case of Authorino being used on direct app integration, or as validating webhook service, this can be a serious issue.
Nowadays, host name ownership is pretty straightforward with the lookup based on a simple hash table with no support for wildcards. With wildcards, on the other hand, overriding  some else's AuthConfig (entirely or parts of it for portions of the overall range of related host names) – either by sneaking in a specific host name under an existing bigger wildcard config or, the other way around, by adding an umbrella wildcard on top of specific ones – gets harder to handle and to track. (Think: sets and subsets between the host names, with and without wildcards, to better visualize it.)
In the end, what matters is: Who owns the domain? Who owns each subdomain? Making assumption about those question and therefore deciding about which AuthConfigs to accept and which to reject is not easy.

How would this work with predefined AuthConfigs (one for *.io, one for talker-api.nip.io) and deploy new Authorino that should reconcile that (e.g. redeploy of Authorino), will it always reconcile the same way?

I'm afraid no particular order can be guaranteed in the reconciliation loop. This problem already exists today without support for wildcards, BTW.

I'm afraid no particular order can be guaranteed in the reconciliation loop. This problem already exists today without support for wildcards, BTW.

In this case, the use-case of having wildcard domain (*.io) and then the concrete domain (talker-api.nip.io) in its current state, will be inherently unstable and might work for a week and then out of nothing start randomly failing, because redeploying caused it to load in a different order.

In the end, what matters is: Who owns the domain? Who owns each subdomain? Making assumption about those question and therefore deciding about which AuthConfigs to accept and which to reject is not easy.

I though that there aren't any permission levels in Authorino. If the user can create AuthConfig he can control Authorino and any of those users can manipulate other AuthConfigs, right? If you want more granularity you would have to setup ValidatingWebhook to limit who can create AuthConfig with specific limitations (e.g. domain locking).
I don't know the exact design and philosophy of Authorino, but from my point-of-view, the question of Who owns the domain? is not one that Authorino should resolve instead administrators should with their specific setup as I think Authorino doesn't have tools to do that.

E.g., given the following host -> authconfig relation:
*.io              -> auth-1
talker-api.nip.io -> auth-2
api.acme.com      -> auth-3
*.acme.com        -> auth-4

Expect the following lookup results:
dogs.pets.com     -> auth-2 (matches *.pets.com)
api.acme.com      -> auth-3 (matches api.acme.com)
www.acme.com      -> auth-4 (matches *.acme.com)
talker-api.nip.io -> auth-2 (matches talker-api.nip.io)
foo.nip.io        -> auth-1 (matches *.io)
foo.org           -> 404

I didn't understand this example until I read the AuthConfig auth-2, which enumerates 2 hosts, including the missing *.pets.com from the original example.
Regarding the "longest host name match wins”  in trivial examples make sense, but when we have many levels of subdomains, which equal n subdivision... it gets tricky to get it right... Maybe we could introduce a precedence param into this equation?

I didn't understand this example until I read the AuthConfig auth-2, which enumerates 2 hosts, including the missing *.pets.com from the original example.

Well spotted, @didierofrivia. I missed that when writing the description of the PR. Fixed.

Regarding the "longest host name match wins” in trivial examples make sense, but when we have many levels of subdomains, which equal n subdivision... it gets tricky to get it right... Maybe we could introduce a precedence param into this equation?

I would like to avoid one AuthConfig having direct links with another. How do you see the this precedence param working on exactly?

This points to removing the host name collision prevention mechanism from Authorino altogether (or IOW making Authorino to work in cluster-wide mode the same way it does in namespaced mode regarding host names). Not sure how this would be seen.

It could be preserved by allowing wildcard and concrete domain to be only in one namespace (e.g. creating *.io in a different namespace than the already existing test.io would be rejected and vice versa) could be a partial solution but I can definitely see a use-case where top-level is wildcard domain with defaults set up by the administrator and in the individual namespaces the users could only use only concrete rules, which would not be possible with that limitation. Maybe the host enforcement could be configurable?

This points to removing the host name collision prevention mechanism from Authorino altogether (or IOW making Authorino to work in cluster-wide mode the same way it does in namespaced mode regarding host names). Not sure how this would be seen.

It could be preserved by allowing wildcard and concrete domain to be only in one namespace (e.g. creating *.io in a different namespace than the already existing test.io would be rejected and vice versa) could be a partial

That's how it works already. Avoiding host name collision is only across k8s namespaces. Within the same k8s namespace, Authorino considers the owner of the conflicting AuthConfigs to be the same and accepts both.

I think what we trying to figure is whether or not there is a way to deliver all the following 3 requirements:

Authorino is safe against users defining AuthConfigs that virtually override one another (partially or totally)
Users can to define AuthConfigs for sets and subsets of domains with support for wildcards
AuthConfigs are simple, without explicit dependencies (references) between them, so Authorino (and users!) can read an AuthConfig alone and know exactly what to expect, without having to refer to who knows how many CRs to figure what applies and what doesn't

I would like to avoid one AuthConfig having direct links with another. How do you see the this precedence param working on exactly?

I'd avoid linking to keep it simple, and what I imagine would be an integer representing the AuthConfig " weight ". Say, the higher the number, the higher the precedence. Does it make sense? I know it'd be almost impossible to manage specific rules attached to hundreds of wildcard domains, but I reckon I'd love to have my very specific and most important AuthConfigweighted with a 9999

[...] an integer representing the AuthConfig " weight ". Say, the higher the number, the higher the precedence. Does it make sense? I know it'd be almost impossible to manage specific rules attached to hundreds of wildcard domains, but I reckon I'd love to have my very specific and most important AuthConfigweighted with a 9999

Yes, it could be a solution for accepting all CRs regardless of overlapping host names, and yet to have a way to decide which AuthConfig to enforce in case multiple apply.
Implementation would need to change a little – we'd need to keep track of the weights associated with each AuthConfig (each matching host) while traversing the tree, to prioritize the one with higher value. Validating webhooks could be used to limit the values users can set for the weight, according to the level of privilege (e.g. higher values kept for admins).
The only remaining issue I see is visibility. A user can still get an AuthConfig accepted but that will never apply, and the user will never know why. E.g.: user A owns *.pets.com with weight 100, user B owns dogs.pets.com with weight 50; *.pets.com will always have precedence. As user B who knows nothing about the AuthConfig for *.pets.com, I'd rather have my AuthConfig for dogs.pets.com rejected at the moment I try to define it, then having to figure out why it's never enforced.
I know the status of the CR could try to reflect that a config is superseded by another. That would mean tracking this in the status updater as well, which could be nightmare given the concurrency. 🤔

Should wildcards be opt-in (and Authorino defaults to old and simple, more efficient, map-based lookup without wildcards), or should we go all in with host name wildcards, remove the old lookup system, and obviously drop https://github.com/Kuadrant/authorino-operator/pull/78? (Users could still disable wildcards in AuthConfigs by defining a control-plane AuthConfig triggered by a validating webhook request.) 🤔

I agree with this being a temporary solution until we properly discuss and decide on the issues, however, I would consider changing the behaviour of the current host name collision so that overlaps are prohibited in both directions e.g. if *.io exists we don't allow test.io and if test.io exists we do not allow *.io, due to the instabilities it would bring with each reload.

That would mean no support for special AuthConfigs on specific subdomains, falling back to more generic ones covering the complement. I.e. once you use a wildcard, you wouldn't be able to append anything below that.
Instead, I think I prefer enhancing feedback to the user with better status subresource, so for any AuthConfig we should be able to tell which requested hosts will be served and which will not.

I don't think we need to care about the relationship between different policies at different levels.

Exactly. That's why we understand it should be only in Kuadrant.

Having a straightforward policy of applying all the AuthConfigs while traversing the radix tree seems simple for the user.

The way we implement it should be transparent to the user anyway. In fact, users (of Kuadrant) should know nothing about AuthConfigs, only about AuthPolicies.

Without the ability to use multiple AuthConfigs per request means there is no value for AuthPolicy to target a Gateway resource unless the Kuadrant controller compiles different AuthConfigs into one (which I don't see how).

That is the general idea. Kuadrant controller compiles different ~AuthConfigs~ AuthPolicies into one single AuthConfig. That is because Kuadrant controller, with the knowledge it has about Gateway API and policy attachment is the only component capable of inferring all the rules from the different kinds of relationships between policies (default, override, merge) attached to the different levels of the tree (Gateway, HTTPRoutes).

Even if we don't include Kuadrant into the picture, I still see value in authorino giving the ability to take one general AuthConfig and 'x' specific AuthConfigs and apply both for a single request.

Authorino standalone does not need that. It already has a way to represent conditional authorization rules (policies) in one single AuthConfig. In fact, that way is precisely how Kuadrant can compile an AuthConfig out of one or more AuthPolicies.

Thanks for sharing your thoughts, @rahulanand16nov. Let's keep the conversation going.
Leaving here a few of my own, so the line of thought don't get lost before the next iteration.

Considering we have literally embedded the AuthConfig into the AuthPolicy, I don't know how users will know nothing about AuthConfig.

I mean what the user sees and owns is a Kuadrant AuthPolicy. The AuthConfig is owned by the Kuadrant controller. The user does not have to be granted permissions of any kind over Authorino AuthConfigs, not even read them.

Each AuthPolicy creates an AuthConfig so essentially we are compiling multiple AuthConfgs (from Authpolicies) into one AuthConfig (when there is an overlap of hostname).

This is how it works today and would continue to for many use cases. Only for the uses cases where the intent is for policies A and B (or A or B) to be enforced in the same authorization request, where A and B are declared in separate AuthPolicies, we're suggesting translating the two policies into one AuthConfig instead of two.

I am failing to see how Kuadrant will compile different AuthConfigs into one?

I will stop using "compiling" (because I don't think that's what it is), to favour "merging". The general procedure is: get the auth scheme of AuthPolicy A (it's composed of a few arrays – identity, metadata, authorization, response); get auth scheme of AuthPolicy B (same arrays); unite each pair of compatible arrays together; use the 'name' of each element in the arrays (required field in all the cases) to merge; use the directives 'default' and 'override' to decide which side of the pair takes precedence; use the rules of the AuthPolicies to inject 'when' conditions in the elements.
Again, the procedure above is when we want two policies evaluated in the same authorization request; only to give more granularity for users (possibly different users) to own and apply policies at a different level, yet targeting the same requests to the protected service.

Policy attachment puts a guard rail around AuthConfigs to avoid overlapping policies and that's it.

I think it is (can be?) more than that. Once you add the knowledge it has about the policy 'rules' (i.e. the scope where the spec should apply) and the kind of relationship that dictates behaviour in case of overlap (default/override, either to an entire group of rules or partial), it opens up for more things IMO. It can go beyond deciding which nodes of the routing tree to just enable or disable the call to the external authorization/RL service. It can add more context, it can decide to throw parts of the spec away to favour others.

Even in the case of RLP, compiling is done by Limitador and not Kuadrant.

I see it differently. Kuadrant controller builds one Limitador CR (or maybe one RL config file these days?) with all the rate limit definitions gathered from all RateLimitPolicy CRs. So it's already a merge. Then, how do we tell Limitador when a limit is to be treated as a default or as an override? I suppose we don't. Instead, Kuadrant controller has to decide which limit goes to the Limitador config, which doesn't.
Because Limitador does not work in terms of 'hosts' as groupings of rules – and neither Authorino BTW(*) – we might perceive an AuthConfig as too different from configuring Limitador. I believe that, in the end, they are not that different.
(*) only reason for hosts to be so important in Authorino is lack of access to context extensions via Istio AuthorizationPolicy

If we solve this at the Authorino level, it becomes a tree traversal problem but if at the Kuadrant level, it becomes a compiler problem. I feel I don't have enough understanding of AuthConfig to combine multiple of them into one. So to make sure I don't push for something that is easy for me, can you please describe a way to compile AuthConfigs?

How to achieve multiple AuthConfigs per authz request was never a concern to me – wrap evaluation in a loop, trigger workloads in parallel, shove all GW API stuff about defaults, overrides, merges, etc into the AuthConfig (so Authorino knows the intended behaviour on the overlaps), some channels to control and sync, etc.
My concern is why doing all that in Authorino and in Limitador as well? Apart from neither of those components needing that today to support the use case behind, to me it all points to Kuadrant controller to be the right place to solve the issue. Kuadrant controller is the first common node in the tree of components that we own and where the info needed to solve occasional conflicts passes through, it knows about the wheres, whens and ifs (from the policy rules and different types resources targeted by the policies), and most importantly it is where our Kuadrant implementation of GW API is.
So I guess my point here is, IMO, even if solving the issue in Kuadrant controller is harder than handing it over to each component (Authorino, Limitador), something yet to be proven BTW, it is where it belongs nonetheless.


add labels to images, networks and volumes

This adds label support for images (build), networks and volumes.
Refs: https://github.com/docker/engine-api/pull/156

Note: I'm still working on getting this tested against docker/docker master but I wanted to get it opened to make sure we have it.

Ping @dongluochen

LGTM

LGTM


bugpoint: add timeout option

*nix systems appear to have the timeout command available in general. I confirmed that with the recent zero-width chunk fix reverted, the following script
read_rtlil <<EOF
module \top
  wire output 1 \a
  wire width 0 $dummy
  cell \abc \abc
    connect \a \a
    connect \b $dummy
  end
  wire width 1 \foo
  wire width 2 \bar
end
EOF

bugpoint -yosys ./yosys -command opt_clean -timeout 5

correctly runs and produces
autoidx 5
module \top
  wire width 0 $delete_wire$2
  wire $delete_wire$4
  cell \abc \abc
    connect \a $delete_wire$4
    connect \b $delete_wire$2
  end
end

Fixes #2629

Looks good, but something should be done about non-UNIX platforms (in particular, windows) — possibly just a message of "timeout is currently not supported on this platform" if no easy solution is found

If prefixing the command with something is the only option on the table, does -yosys "timeout n yosys" work?

@whitequark The quotes around the command aren't stripped, so that will yield something like "timeout 5 ./yosys" is not a command.

Should we strip those, then?

Although that will probably break under Program Files (x86) or something. -runner?

I can get behind the more general variant. I suppose we'd just drop the quotes if present for that arg. What other runners did you imagine?

What other runners did you imagine?

valgrind for example

I rebased and force-pushed to re-run CI, which appears to have experienced a spurious failure installing some dependencies.


🦇 move to cop-action once pr is merged

track the github-actions repo for conftestbats so we don't need to use @garethahealy 's dodgy repo/branch

PRs required before moving back to main:

https://github.com/redhat-cop/github-actions/pull/15
https://github.com/redhat-cop/github-actions/pull/14

@garethahealy @springdo These two have been merged.

closing as @garethahealy has updated the action here


msglist: Simplify safe-area handling; fix a small bug

This addresses Greg's TODO in 88f3b73a6:
// TODO have MessageListPage adjust the MediaQuery so we don't
//   have to worry about this here
with a bugfix beforehand, so that resolving the TODO is NFC (or at least seems to be, experimentally).

Revision pushed, with
11a4b15 widgets/app [nfc]: Smoothen a wrinkle about MediaQuery.removePadding

Thanks for the review! Revision pushed.

Thanks! Looks good; merging.


Propagate bindings to depending crate

Hello,
For my project I use two crates A and B. Crate B contains functions that are marked with #[wasm_bindgen]. Crate A is built into a wasm-library using wasm-bindgen, and it depends on crate B.
When I build crate B on its own, the JavaScript bindings are correctly generated. But when I build crate A, the annotations for the functions in crate B seem to be ignored.
What do I need to do to build crate A, but still get the JavaScript bindings for the functions in crate B for my library?

Thanks for the report! I think this is an unfortunate limitation of how LLD works (the linker for wasm code).
Currently if you're linking to a library LLD doesn't actually load the library unless you use something from it. If you're exporting functionality from B there's likely nothing else pulling it in to link to it, so LLD doesn't end up pulling in the functionality.
You can see a longer explanation here along with the workaround this crate uses. Perhaps something like that could work for you?

Ah thank you very much for the hint. That might work for me, but for now I have decided to just include the exported functions also in the depending crate. Seemed to be the easiest and least hacky solution, and also makes the structure of my project actually nicer.


Update set-protocol-oracles with new version

Bumps oracles to new version with smaller package size

Pull Request Test Coverage Report for Build 7792

0 of 0   changed or added relevant lines in 0 files are covered.
No unchanged relevant lines lost coverage.
Overall coverage remained the same at 100.0%

Totals

Change from base Build 7790:
0.0%

Covered Lines:
1714

Relevant Lines:
1714

💛  - Coveralls


Brother Foster code and testing

Three-way testing:
Talk to Brother Big and see about Brother Foster. Un-talk. Hi-bye brother soul/blood and verify it's there. Talk to Big about Foster. Hi-bye BS and BB and verify Foster is not there.
Repeat for BF and BS.

Bad ending: BF: "of course they let them through." <- in bad ending.  They almost like it there."
Good ending: BM and BF arguing about keeping them in line or getting a bum deal as led away.


Make it possible to serve built pages while the site is reloading

Currently, when a re-build is happening, it is not possible to serve any of the already-built HTML pages from the last build. This is a pain because it can be useful to continue browsing your docs preview while a build is happening.

If not run asynchronously it would be nice if it at least queued up requests, so that if you click a link on the built site it eventually loaded it. Right now if you click a link while the build is happening nothing happens, and you have to wait for the build to happen and click the link again.

Done in fda9582a10a80f2a68f11453449d82ec4e86bb13.
A


Add $ObjReduce destructor

$ObjReduce<
  {| a: 1, b: 2 |},
  <Acc, Key, Value>(Acc, Key, Value) => Acc | Key,
  empty
> // 'a' | 'b'

$ObjReduce<
  {| a: 1, b: 2 |},
  <Acc, Key, Value>(Acc, Key, Value) => {|
     ...Acc,
     [K in Key]: Value // hypothetical computed key
  |},
  empty
> // {| a: 1, b: 2 |}

We're moving away from adding more such utility types. I think some of these use cases can be accomplished with our upcoming version of mapped types.


Question on MicrophoneManagerManual.java ...

Can I copy all source from MicrophoneManager.java into MicrophoneManagerManual.java except thread handling related codes?

in MicrophoneManagerManual.java, it have very simple works in there.
I like to do set all mircrophonemanager things in maual.java too.
I want to that manual.java do the same thing as manager in a sync mode.
Am I wrong ?


Do not reinitialize mirage config during each test

During each acceptance test, the initializer creates a new pretender server and adds all the config, even if a window.server exists.
Actually, I faced an issue in my work app, where each acceptance test would add a new server with listeners and eventually hang. I am not able to isolate it into a reproduction.
I believe it is okay to skip doing all the work in subsequent tests, after the initializer has booted the mirage server once.

Im on vacation and can't look at this now, as a stop gap you can add
server.shutdown() to each tests afterEach
On Tue, Nov 24, 2015 at 12:02 AM Kamalakannan<EMAIL_ADDRESS>wrote:

During each acceptance test, the initializer creates a new pretender
server and adds all the config, even if a window.server exists.
Actually, I faced an issue in my work app, where each acceptance test
would add a new server with listeners and eventually hang. I am not able to
isolate it into a reproduction.
I believe it is okay to skip doing all the work in subsequent tests, after
the initializer has booted the mirage server once.
You can view, comment on, or merge this pull request online at:
https://github.com/samselikoff/ember-cli-mirage/pull/402
Commit Summary

do not reinitialize mirage config during tests

File Changes

M app/initializers/ember-cli-mirage.js
https://github.com/samselikoff/ember-cli-mirage/pull/402/files#diff-0
(10)

Patch Links:

https://github.com/samselikoff/ember-cli-mirage/pull/402.patch
https://github.com/samselikoff/ember-cli-mirage/pull/402.diff

—
Reply to this email directly or view it on GitHub
https://github.com/samselikoff/ember-cli-mirage/pull/402.

Thanks @samselikoff , I did try your stop gap solution first. Then wondered if this non-intrusive solution would work.
No problem, I'll wait till you have time to look at this. Enjoy your vacation :smile:

Thanks for the PR! The problem is, the Mirage db is expected to be fresh at the beginning of each test, so we can't just keep it around, I think.
I believe https://github.com/samselikoff/ember-cli-mirage/pull/281 will solve this problem, but I'll leave this PR open until we get that one merged in.

The problem is, the Mirage db is expected to be fresh at the beginning of each test

Ah, I get it.

I believe #281 will solve this problem, but I'll leave this PR open until we get that one merged in.

Thanks :+1:

I think #281 closes this now, in a way consistent with other addons. Let me know if you still think there's a problem! Thank you for pointing this out.

I think this will do it. Thank you for the update.


Add a handler to every route adding response header

... if $HSTS is set at startup

I'm a bit unsure how good this solution really is.
It seems a bit cumbersome to iterate over each route to add N handlers that will add the response headers, but I couldn't find a more central place to take care of it in caddy's docs.


Fix large 99 percentile match latency in Monitor during concurrent commits and purges

Description
Within Lucene Monitor, there is a thread contention issue that manifests as multi-second latencies in the Monitor.match function when it is called concurrently with Monitor.register/Monitor.deleteById and QueryIndex.purgeCache. The source of the issue is the usage of purgeLock, a ReentrantReadWriteLock.
Within the QueryIndex, there are 3 usages of the purgeLock. They are commit (called by Monitor.register/Monitor.deleteById), ‘search’ (called by Monitor.match), and purgeCache (called by a background thread at a consistent interval). Within commit and search, the read lock is acquired, and within purgeCache, the write lock is acquired. search calls are very fast and only hold the purgeLock for short durations. However, commit calls are quite long and will hold the purgeLock for multi-second durations. Ostensibly because both commit and search only need the read lock, they should be able to execute concurrently and the long duration of commit should not impact search. However, when purgeCache attempts to acquire the write lock this no longer holds true. This is because once purgeCache is waiting to acquire the write lock, attempts to acquire the read lock probabilistically might wait for the write lock to be acquired + released (otherwise attempts to acquire the write lock would be starved). What this means is that if commit is holding the read lock, and then purgeCache attempts to acquire the write lock, some amount of calls to match that want to acquire the read lock will be queued behind the purgeCache attempt to acquire the write lock. Because purgeCache cannot acquire the write lock until commit releases the read lock, and because those search calls cannot acquire the read lock until purgeCache acquires + releases the write lock, those search calls end up having to wait for commit to complete. This makes it possible for search calls to take as long as commit to complete (multi-second rather than millisecond).
Diagrams
For illustration purposes I have the following 2 diagrams of the problem. The first diagram demonstrates the wait order for the ReentrantReadWriteLock in the high latency match scenario. For the purpose of the diagram I am assuming that commit takes 3 seconds, purgeCache takes 3 milliseconds, and search takes 3 milliseconds as well. Most of the calls to search will not end up in this scenario, but without the fix included in this PR some of the calls to search will end up in this scenario and be slow.

The way in which the calls to search end up being slow is more clearly shown in the second diagram which shows a timeline that has a multisecond delayed search call - making the same assumptions about the runtime of the 3 operations as the first diagram. In the below diagram, Search Thread A avoids the problem and has expected latency, but Search Thread B runs into the problem and has very high latency.

Solution
This issue can be resolved by ensuring that purgeCache never attempts to acquire the write lock when commit is holding the read lock. This can be done by  simply using a mutual exclusion lock between the two since:

purgeCache is not time-sensitive so it can afford to wait until commit completes.
commit is arguably time sensitive but purgeCache is a very quick operation so sometimes having to wait on it won’t make a meaningful difference in the time it takes for commit to complete by itself.

Test Case / Demo
To demonstrate the problem I have this gist that runs commit and search concurrently while recording the durations of the calls to search. Then it runs commit, search and purgeCache concurrently while recording the durations of search. Comparing the p99 - p100 durations between when purgeCache wasn’t run concurrently vs when it was run concurrently shows the high latency behavior for combining all 3 operations.
Without this change, running the gist on my laptop gives:

No purgeCache - mean of p99 thru p100 is 20ms
Yes purgeCache - mean of p99 thru p100 is 651ms

With this change, running the gist on my laptop gives:

No purgeCache - mean of p99 thru p100 is 16ms
Yes purgeCache - mean of p99 thru p100 is 9ms

Even though the latencies in this test are noisy, the order of magnitude difference in the mean p99 thru p100 when using this change with commit, search and purgeCache run concurrently is statistically significant. This issue is important to fix because it prevents Lucene Monitor from having reliable low latency match performance.
Merge Request
If this PR gets merged, can you please use my<EMAIL_ADDRESS>email address for the squash+merge. Thank you.

Thank you for taking a look!


Increase min coverage back to 90 when enough tests available

Due to the small amount of code in the app the minimum code coverage needed to be reduced below 90%. This should be increased at the earliest opportunity.

Fixed by #67


fix: add ls part for iac ignore button

Description
This is the LS logic needed for adding the IaC ignore button in IntelliJ, this button is hidden by default.
A file path was also added to the template for enabling to execute the ignore issue comand which also needs file path.
Checklist

[ ] Tests added and all succeed
[ ] Linted
[ ] README.md updated, if user-facing
[ ] License file updated, if new 3rd-party dependency is introduced

 Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.You have signed the CLA already but the status is still pending? Let us recheck it.

Consider testing that the template is filled correctly for the ignores stuff ;)


Add rz decomposition routine

When solving large linear systems, it's nice to be able to use parts of a QR decomposition without forming the Q matrix.  Suitesparse allows a Q-less decomposition, which forms R and Z such that z=Q^Td.  The modifications I made to the code let PySPQR return Q and Z for sparse systems.

I am trying to decide if I like the function name. I looked to MATLAB for inspiration, but they don't have a different name. They decide what to compute based on the output arguments.
Some alternatives:

zr(), since z is returned first. e is never mentioned for some reason.

a keyword argument to qr() to specify what should be returned (compute_Q = False)

I'd be happy either way.  Thanks!
On Thu, Aug 9, 2018 at 2:10 PM, Yotam Gingold<EMAIL_ADDRESS>wrote:

I am trying to decide if I like the function name. I looked to MATLAB for
inspiration, but they don't have a different name. They decide what to
compute based on the output arguments.
Some alternatives:

zr(), since z is returned first. e is never mentioned for some reason.
a keyword argument to qr() to specify what should be returned
(compute_Q = False)
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/yig/PySPQR/pull/10#issuecomment-411898311, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ACLG6F8YNma55h5CNc4t59sZ-_6GIEQmks5uPKVIgaJpZM4V2WTz
.

Sorry about the delay. Can you clarify what R and z are? Is it the "[C,R,p] = qr(A,B,'vector')" version on this MATLAB page: https://www.mathworks.com/help/symbolic/qr.html


[SPARK-39331][PYTHON][TESTS][SS] Check None for offsets in SourceProgress

What changes were proposed in this pull request?
This PR fixes the flaky test (https://github.com/apache/spark/runs/6643112037):
Traceback (most recent call last):
  File "/__w/spark/spark/python/pyspark/sql/tests/test_streaming_listener.py", line 121, in test_listener_events
    self.check_progress_event(progress_event)
  File "/__w/spark/spark/python/pyspark/sql/tests/test_streaming_listener.py", line 140, in check_progress_event
    self.check_streaming_query_progress(event.progress)
  File "/__w/spark/spark/python/pyspark/sql/tests/test_streaming_listener.py", line 198, in check_streaming_query_progress
    self.check_source_progress(so)
  File "/__w/spark/spark/python/pyspark/sql/tests/test_streaming_listener.py", line 248, in check_source_progress
    self.assertTrue(isinstance(progress.startOffset, str))
AssertionError: False is not true

startOffset, endOffset and latestOffset can be None, and this PR changes the possible types in the tests.
Why are the changes needed?
To fix the flakiness.
Does this PR introduce any user-facing change?
No, dev-only.
How was this patch tested?
This PR fixes the test. We should monitor if it fixes the flakiness after it gets merged.

cc @HeartSaVioR mind taking a quick look please when you find some time?

Thanks @dongjoon-hyun !

Merged to master.


DataLoader worker (pid xxx) is killed by signal when parameter nw > 0

First I'd like to thank you for the great project.
I met a strange error when setting nw > 0 (e.g., 1, 2, 3...) training vgg16/resnet50 on pascal-voc 2007 dataset (or any other dataset I can find). For example, we I run
python trainval_net.py --dataset pascal_voc --net res50 --bs 4 --nw 1 --cuda

I get the following error:
RuntimeError: DataLoader worker (pid 893) is killed by signal: Unknown signal: 0. Details are lost due to multiprocessing. Rerunning with num_workers=0 may give better error trace.

When I set nw = 0, however, everything works smoothly.
I googled and somebody said that it may be caused by:

Insufficient memory. I'm pretty sure I have sufficient memory (32 GB).
Dataset may not prefer multiprocessing.

Any suggestions are welcome!
Running on:

pytorch 0.4.1
torchvision 0.2.1
Mac OS X 10.12.6
CUDA 9.0
CUDNN 7.0

@TomHeaven Have you solved this problem?

No. However, I didn't met the problem on another PC with Mac OS 10.13. So I guess there is something related to the operating system environment.

@TomHeaven Check whether your PC has enough share memory. This problem is solved when I double the memory(in my server).


atom 1.45.0 crashes too much on osx

Prerequisites

[ ] Put an X between the brackets on this line if you have done all of the following:

Reproduced the problem in Safe Mode: https://flight-manual.atom.io/hacking-atom/sections/debugging/#using-safe-mode
Followed all applicable steps in the debugging guide: https://flight-manual.atom.io/hacking-atom/sections/debugging/
Checked the FAQs on the message board for common solutions: https://discuss.atom.io/c/faq
Checked that your issue isn't already filed: https://github.com/issues?utf8=✓&q=is%3Aissue+user%3Aatom
Checked that there is not already an Atom package that provides the described functionality: https://atom.io/packages

Description
I tried the latest version on osx, and I'm only stopping by to comment because:

I like this one better than vscode or webstorm !!

If I didn't like it I wouldn't spend the time letting you know:

It crashes and locks up and I spent a couple hours googling and so ok the ~/.atom can get corrupted so I deleted that, and yes, that allowed it to start but then 15 minutes later it's locking up again
I mouse over the editor file thumbnail at the top and it's gone!
I notice there's an atom process that the osx activity monitor cannot stop, red and nonresponsive
restart the system, same thing
this is a 2019 macbook pro they gave me at work, it's not like it's got a problem running other stuff I have to run

I'm in the middle of a project and I can't get all the repro steps and stuff, but I feel like anyone could repro who isn't on the project team and so has to keep trying to work with the release version instead of their fork where they have some fixes.
Wish I could pay the seat fee to an imaginary commercialized atom which works like this one but without the crashing, instead of paying for webstorm which is ... it's an alternative to vscode I guess.
Steps to Reproduce

. install osx release on recent model fully updated macbook pro

. dive into the dev cycle, import a big existing package, try to learn the shortcuts

 intermittent crashing becomes more frequent until it devolves into cannot start, and from there proceeds to cannot stop

Expected behavior:
crash not more than once per month during heavy continuous use
Actual behavior:
crash harder than any other app I've seen on osx, requiring reboot to clear the unresponsive process
Reproduces how often:
never upon installation, escalating to constantly by day 2
Versions
latest installer, um. atom-mac.zip osx says I got it from:
https://github.com/atom/atom/releases/tag/v1.45.0
https://github-production-release-asset-2e65be.s3.amazonaws.com/3228505/e28afd00-6304-11ea-8ac4-8b3de4863926?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-
Credential=AKIAIWNJYAX4CSVEH53A%2F20200413%2Fus-east-1%2Fs3%2F
   aws4_request&X-Amz-Date=20200413T132201Z&X-Amz-Expires=300&
   X-Amz-Signature=
     47d003ac42a165dda54708feb74fd8f902f2039a8cc95cec2d5ae24d233fe6fd&
   X-Amz-SignedHeaders=host&actor_id=50930812&repo_id=3228505&
   response-content-disposition=attachment%3B%20
   filename%3Datom-mac.zip&response-content-type=application%2Foctet-stream

Additional Information

thank you & stay safe!

I second this issue. It increasingly crashes a lot these days on my Macbook, and I'm starting to get worried about losing work due to the crash.
Today it happened when I discarded changes of a file on the git tab.

Feb 15, 2020 820 AM.txt

This issue has been addressed on atom-nightly


For Windows

Hi Team,
First of all, Congrats and Thanks for this excellent project.
I am looking to compile this for the windows machine. Is there any possibilities for that?

go get -u github.com/zhaojh329/rtty

I am not able to do go get -u github.com/zhaojh329/rtty. It is saying no go files in ../github.com/zhaojh329/rtty.  I hope client is not a go project.

Sorry, I thought you were talking about the rttys project.
The client rtty does not support Windows, only Linux. But you can use it in wsl for Windows.


HopSkipJumpAttack notebook with TF 2.2.0

Describe the bug
After modifying the notebook to work with tensorflow==2.2.0 and keras==2.3.1, as shown below, I get the error
ValueError: The shape of mean and the standard deviation must be identical.
To Reproduce

install requirements with pip install -r requirements.txt
run pip install -U tensorflow==2.2.0 keras==2.3.1
run the following cell inside a jupyter notebook:

import sys
!{sys.executable} -m pip install git+https://github.com/nottombrown/imagenet_stubs
sys.path.append("..")

%matplotlib inline
import tensorflow as tf

tf.compat.v1.disable_eager_execution()

import imagenet_stubs
import numpy as np
import tensorflow.keras
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.models import Model
import tensorflow.keras.backend as k
from matplotlib import pyplot as plt
from IPython.display import clear_output

from art.estimators.classification import KerasClassifier
from art.attacks.evasion import HopSkipJump
from art.utils import to_categorical

mean_imagenet = np.zeros([224, 224, 3])
mean_imagenet[...,0].fill(103.939)
mean_imagenet[...,1].fill(116.779)
mean_imagenet[...,2].fill(123.68)
model = ResNet50(weights='imagenet')
classifier = KerasClassifier(clip_values=(0, 255), model=model, preprocessing=(mean_imagenet, 1))

target_image_name = 'koala.jpg'
init_image_name = 'tractor.jpg'
for image_path in imagenet_stubs.get_image_paths():
    if image_path.endswith(target_image_name):
        target_image = image.load_img(image_path, target_size=(224, 224))
        target_image = image.img_to_array(target_image)
    if image_path.endswith(init_image_name):
        init_image = image.load_img(image_path, target_size=(224, 224))
        init_image = image.img_to_array(init_image)

print("Target image is: ", np.argmax(classifier.predict(np.array([target_image]))[0]))

**Expected behavior**
The class of koala.jpg will be predicted.

**System information (please complete the following information):**
 - OS: Ubuntu 20.04
 - Python version: 3.8.5
 - ART: 1.6.2 commit: 031ffe4426678487de0cbcec5ad13f355e570bc8
 - tensorflow: 2.2.0
 - keras: 2.3.1

**Stack Trace**
```---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-6-c80f03df9fbe> in <module>
      9         init_image = image.img_to_array(init_image)
     10
---> 11 print("Target image is: ", np.argmax(classifier.predict(np.array([init_image]))[0]))

~/Desktop/thinkdeeply/other_repos/adversarial-robustness-toolbox/art/estimators/classification/classifier.py in replacement_function(self, *args, **kwargs)
     69                 if len(args) > 0:
     70                     args = tuple(lst)
---> 71                 return fdict[func_name](self, *args, **kwargs)
     72
     73             replacement_function.__doc__ = fdict[func_name].__doc__

~/Desktop/thinkdeeply/other_repos/adversarial-robustness-toolbox/art/estimators/classification/keras.py in predict(self, x, batch_size, training_mode, **kwargs)
    532         """
    533         # Apply preprocessing
--> 534         x_preprocessed, _ = self._apply_preprocessing(x, y=None, fit=False)
    535
    536         # Run predictions with batching

~/Desktop/thinkdeeply/other_repos/adversarial-robustness-toolbox/art/estimators/estimator.py in _apply_preprocessing(self, x, y, fit)
    298                 else:
    299                     if preprocess.apply_predict:
--> 300                         x, y = preprocess(x, y)
    301
    302         return x, y

~/Desktop/thinkdeeply/other_repos/adversarial-robustness-toolbox/art/preprocessing/standardisation_mean_std/numpy.py in __call__(self, x, y)
     80
     81         if self._broadcastable_mean is None:
---> 82             self._broadcastable_mean, self._broadcastable_std = broadcastable_mean_std(x, self.mean, self.std)
     83
     84         x_norm = x - self._broadcastable_mean

~/Desktop/thinkdeeply/other_repos/adversarial-robustness-toolbox/art/preprocessing/standardisation_mean_std/utils.py in broadcastable_mean_std(x, mean, std)
     34     """
     35     if mean.shape != std.shape:
---> 36         raise ValueError("The shape of mean and the standard deviation must be identical.")
     37
     38     # catch non-broadcastable input, when mean and std are vectors

ValueError: The shape of mean and the standard deviation must be identical.```

Hi @aaronrmm Thank you very much for using ART! The observed ValueError actually explains the solution, you have to provide mean and std for preprocessing in arrays of the same shape.

I also had same error with non-modified "attack_adversarial_patch_TensorFlowV2.ipynb "

Hi @0jaehunny0 Thank you very much for noticing and sharing! Does it work work if you change to  preprocessing=(np.array([mean_b, mean_g, mean_r]), np.array([1.0, 1.0, 1.0]))? If yes, could you open a pull request?

Yes, this works.
On Tue, Jun 15, 2021, 12:53 PM Beat Buesser @.***>
wrote:

Hi @0jaehunny0 https://github.com/0jaehunny0 Thank you very much for
noticing and sharing! Does it work work if you change to preprocessing=(np.array([mean_b,
mean_g, mean_r]), np.array([1.0, 1.0, 1.0]))? If yes, could you open a
pull request?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Trusted-AI/adversarial-robustness-toolbox/issues/1137#issuecomment-861665929,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AANJQH7FYZ5HCLHCABMBTR3TS6ARPANCNFSM454ST6TA
.

Hi @beat-buesser
Thank you so much for your correct and quick reply!
I just opend a pull request.

Hi @0jaehunny0 That's great, thank you very much for the pull request!


Job gets admitted, but is never un-suspended.

What happened:
Job submitted, workload got created and admitted that job. Job was never un-suspended. I tried to patch Job to suspend: false, but it immediately got suspended again.
There are multiple identical errors from kueue:
{
  "level": "error",
  "ts": "2024-02-12T08:30:42.026624587Z",
  "caller": "jobframework/reconciler.go:335",
  "msg": "Handling job with no workload",
  "controller": "job",
  "controllerGroup": "batch",
  "controllerKind": "Job",
  "Job": {
    "name": "ml-job-annotator-gt-webface-gpu",
    "namespace": "pgrunt"
  },
  "namespace": "pgrunt",
  "name": "ml-job-annotator-gt-webface-gpu",
  "reconcileID": "edba044d-1ece-4364-8c6a-c0dc66907553",
  "job": "pgrunt/ml-job-annotator-gt-webface-gpu",
  "gvk": "batch/v1, Kind=Job",
  "error": "workloads.kueue.x-k8s.io \"job-ml-job-annotator-gt-webface-gpu-ff6d8\" already exists",
  "stacktrace": "sigs.k8s.io/kueue/pkg/controller/jobframework.(*JobReconciler).ReconcileGenericJob\n\t/workspace/pkg/controller/jobframework/reconciler.go:335\nsigs.k8s.io/kueue/pkg/controller/jobframework.(*genericReconciler).Reconcile\n\t/workspace/pkg/controller/jobframework/reconciler.go:1007\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Reconcile\n\t/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.17.0/pkg/internal/controller/controller.go:119\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.17.0/pkg/internal/controller/controller.go:316\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.17.0/pkg/internal/controller/controller.go:266\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func2.2\n\t/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.17.0/pkg/internal/controller/controller.go:227"
}

Cluster, local queue
NapiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"kueue.x-k8s.io/v1beta1","kind":"ClusterQueue","metadata":{"annotations":{},"name":"cq-all-resources"},"spec":{"flavorFungibility":{"whenCanBorrow":"Borrow","whenCanPreempt":"TryNextFlavor"},"namespaceSelector":{},"preemption":{"reclaimWithinCohort":"Never","withinClusterQueue":"Never"},"queueingStrategy":"StrictFIFO","resourceGroups":[{"coveredResources":["nvidia.com/gpu"],"flavors":[{"name":"gpu-a40","resources":[{"name":"nvidia.com/gpu","nominalQuota":8}]},{"name":"gpu-a100","resources":[{"name":"nvidia.com/gpu","nominalQuota":4}]}]},{"coveredResources":["cpu","memory","ephemeral-storage","github.com/fuse","pods"],"flavors":[{"name":"default-flavor","resources":[{"name":"cpu","nominalQuota":256},{"name":"memory","nominalQuota":"2Ti"},{"name":"ephemeral-storage","nominalQuota":"2Ti"},{"name":"github.com/fuse","nominalQuota":"10k"},{"name":"pods","nominalQuota":220}]}]}]}}
  creationTimestamp: "2024-02-07T14:30:12Z"
  finalizers:
  - kueue.x-k8s.io/resource-in-use
  generation: 4
  name: cq-all-resources
  resourceVersion: "336378666"
  uid: cb3e70ae-714d-4aa4-8edc-0b76041d24b9
spec:
  flavorFungibility:
    whenCanBorrow: Borrow
    whenCanPreempt: TryNextFlavor
  namespaceSelector: {}
  preemption:
    borrowWithinCohort:
      policy: Never
    reclaimWithinCohort: Never
    withinClusterQueue: Never
  queueingStrategy: StrictFIFO
  resourceGroups:
  - coveredResources:
    - nvidia.com/gpu
    flavors:
    - name: gpu-a40
      resources:
      - name: nvidia.com/gpu
        nominalQuota: 8
    - name: gpu-a100
      resources:
      - name: nvidia.com/gpu
        nominalQuota: 4
  - coveredResources:
    - cpu
    - memory
    - ephemeral-storage
    - github.com/fuse
    - pods
    flavors:
    - name: default-flavor
      resources:
      - name: cpu
        nominalQuota: 256
      - name: memory
        nominalQuota: 2Ti
      - name: ephemeral-storage
        nominalQuota: 2Ti
      - name: github.com/fuse
        nominalQuota: 10k
      - name: pods
        nominalQuota: 220
  stopPolicy: None
status:
  admittedWorkloads: 1
  conditions:
  - lastTransitionTime: "2024-02-07T14:31:07Z"
    message: Can admit new workloads
    reason: Ready
    status: "True"
    type: Active
  flavorsReservation:
  - name: gpu-a40
    resources:
    - borrowed: "0"
      name: nvidia.com/gpu
      total: "2"
  - name: gpu-a100
    resources:
    - borrowed: "0"
      name: nvidia.com/gpu
      total: "0"
  - name: default-flavor
    resources:
    - borrowed: "0"
      name: cpu
      total: "10"
    - borrowed: "0"
      name: ephemeral-storage
      total: 12Gi
    - borrowed: "0"
      name: github.com/fuse
      total: "0"
    - borrowed: "0"
      name: memory
      total: 45Gi
    - borrowed: "0"
      name: pods
      total: "1"
  flavorsUsage:
  - name: gpu-a40
    resources:
    - borrowed: "0"
      name: nvidia.com/gpu
      total: "2"
  - name: gpu-a100
    resources:
    - borrowed: "0"
      name: nvidia.com/gpu
      total: "0"
  - name: default-flavor
    resources:
    - borrowed: "0"
      name: cpu
      total: "10"
    - borrowed: "0"
      name: ephemeral-storage
      total: 12Gi
    - borrowed: "0"
      name: github.com/fuse
      total: "0"
    - borrowed: "0"
      name: memory
      total: 45Gi
    - borrowed: "0"
      name: pods
      total: "1"
  pendingWorkloads: 0
  reservingWorkloads: 1
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  creationTimestamp: "2024-02-07T14:33:08Z"
  generation: 1
  name: lq-all-resources
  namespace: pgrunt
  resourceVersion: "336378665"
  uid: 7f52812a-6752-4363-8eee-4789bb2d6358
spec:
  clusterQueue: cq-all-resources
status:
  admittedWorkloads: 1
  conditions:
  - lastTransitionTime: "2024-02-07T14:33:08Z"
    message: Can submit new workloads to clusterQueue
    reason: Ready
    status: "True"
    type: Active
  flavorUsage:
  - name: gpu-a40
    resources:
    - name: nvidia.com/gpu
      total: "2"
  - name: gpu-a100
    resources:
    - name: nvidia.com/gpu
      total: "0"
  - name: default-flavor
    resources:
    - name: cpu
      total: "10"
    - name: ephemeral-storage
      total: 12Gi
    - name: github.com/fuse
      total: "0"
    - name: memory
      total: 45Gi
    - name: pods
      total: "1"
  flavorsReservation:
  - name: gpu-a40
    resources:
    - name: nvidia.com/gpu
      total: "2"
  - name: gpu-a100
    resources:
    - name: nvidia.com/gpu
      total: "0"
  - name: default-flavor
    resources:
    - name: cpu
      total: "10"
    - name: ephemeral-storage
      total: 12Gi
    - name: github.com/fuse
      total: "0"
    - name: memory
      total: 45Gi
    - name: pods
      total: "1"
  pendingWorkloads: 0
  reservingWorkloads: 1

Job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  labels:
    app: ml-job
    kueue.x-k8s.io/queue-name: lq-all-resources
    kueue.x-k8s.io/priority-class: ml-low
  name: ml-job-webface-mapping-this_is_placeholder
spec:
  backoffLimit: 0
  suspend: true
  template:
    metadata:
      name: ml-job
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - hawking
      containers:
      - command:
        - bash
        - -c
        - |
          export PATH="/opt/venv/bin/:${PATH}" &&
          cd /data/workspace/facekit &&
          pip install -e . &&
          facekit face_annotator multiface ${WORKLOAD_ARGS} --processes 30
        env:
        - name: GIT_REPO
          value: "redacted"
        - name: GIT_CHECKOUT_BRANCH
          value: "redacted"
        - name: WORKLOAD_ARGS
          value: ""
        - name: OMP_NUM_THREADS
          value: "1"
        - name: NUMEXPR_NUM_THREADS
          value: "1"
        - name: AWS_ACCESS_KEY_ID
          valueFrom:
            secretKeyRef:
              key: AWS_ACCESS_KEY_ID
              name: user-credentials
        - name: AWS_SECRET_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              key: AWS_SECRET_ACCESS_KEY
              name: user-credentials
        - name: CLEARML_API_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              key: CLEARML_API_ACCESS_KEY
              name: user-credentials
        - name: CLEARML_API_SECRET_KEY
          valueFrom:
            secretKeyRef:
              key: CLEARML_API_SECRET_KEY
              name: user-credentials
        image: "redacted"
        imagePullPolicy: Always
        name: ml-main
        resources:
          limits:
            cpu: 100
            ephemeral-storage: 120Gi
            memory: 80Gi
            nvidia.com/gpu: "2"
          requests:
            cpu: 30
            ephemeral-storage: 120Gi
            memory: 45Gi
        securityContext:
          privileged: true
        volumeMounts:
        - mountPath: /data/user
          name: user-configuration
        - mountPath: /data/workspace
          name: workspace
        - mountPath: /srv/dvc_cache/
          name: dvc-cache
        - mountPath: /mnt/nas.brno/
          name: nas-brno
        - mountPath: /etc/redacted/
          name: iengine-lic
        - mountPath: /dev/shm
          name: dev-shm
        - mountPath: /mnt/data/downloader
          name: downloader
        - mountPath: /encrypted/INC-12499
          name: wiki-hdd
        - mountPath: /root
          name: user-home-dev-pod-0
        workingDir: /data/workspace
      imagePullSecrets:
      - name: registry-credentials
      initContainers:
      - command:
        - bash
        - -c
        - |
          if [[ ! -d "/root/.ssh" ]]; then
            mkdir ~/.ssh &&
            mkdir ~/.kube &&
            cp /data/user/id_* ~/.ssh &&
            cp /data/user/.git* ~/ &&
            cp /data/user/kubeconfig ~/.kube/config &&
            ssh-keyscan -p 7999 -t rsa redacted > ~/.ssh/known_hosts &&
            cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys &&
            chmod 600 ~/.ssh/id_rsa &&
            git clone $GIT_REPO &&
            cd "$(basename "$GIT_REPO" .git)" &&
            git checkout $GIT_CHECKOUT_BRANCH
          fi
        env:
        - name: GIT_REPO
          value: "redacted"
        - name: GIT_CHECKOUT_BRANCH
          value: "redacted"
        image: bitnami/git:latest
        name: init-git-repo
        resources:
          limits:
            cpu: 250m
            memory: 512Mi
          requests:
            cpu: 100m
            memory: 512Mi
        volumeMounts:
        - mountPath: /data/user
          name: user-configuration
        - mountPath: /data/workspace
          name: workspace
        workingDir: /data/workspace
      priorityClassName: ml-low
      restartPolicy: Never
      runtimeClassName: nvidia
      volumes:
      - name: user-configuration
        projected:
          sources:
          - secret:
              items:
              - key: id_rsa
                path: id_rsa
              - key: id_rsa.pub
                path: id_rsa.pub
              - key: .git-credentials
                path: .git-credentials
              - key: kubeconfig
                path: kubeconfig
              name: user-credentials
          - configMap:
              items:
              - key: .gitconfig
                path: .gitconfig
              name: gitconfig
          - configMap:
              items:
              - key: clearml.conf
                path: clearml.conf
              name: clearml.conf
      - hostPath:
          path: /srv/dvc_cache/
        name: dvc-cache
      - emptyDir: {}
        name: workspace
      - hostPath:
          path: /mnt/nas.brno
        name: nas-brno
      - configMap:
          name: iengine.lic
        name: iengine-lic
      - emptyDir:
          medium: Memory
          sizeLimit: 1Gi
        name: dev-shm
      - hostPath:
          path: /mnt/data/downloader
        name: downloader
      - hostPath:
          path: /encrypted/INC-12499
        name: wiki-hdd
      - name: user-home-dev-pod-0
        persistentVolumeClaim:
          claimName: user-home-dev-pod-0
  ttlSecondsAfterFinished: 1200

The Worklaod object has status:
Conditions:
Last Transition Time: 2024-02-11T10:42:40Z
Message: Quota reserved in ClusterQueue cq-all-resources
Reason: QuotaReserved
Status: True
Type: QuotaReserved
Last Transition Time: 2024-02-11T10:42:40Z
Message: The workload is admitted
Reason: Admitted Status: True
Type: Admitted

What you expected to happen:
Job gets un-suspended, Pod is created and running.
How to reproduce it (as minimally and precisely as possible):
Create cluster+local queue and try submitting job mentioned above.
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: cq-all-resources
spec:
  preemption:
    reclaimWithinCohort: Never
    withinClusterQueue: Never
  flavorFungibility:
    whenCanBorrow: Borrow
    whenCanPreempt: TryNextFlavor
  queueingStrategy: StrictFIFO
  namespaceSelector: {}
  resourceGroups:
    - coveredResources: ["nvidia.com/gpu"]
      flavors:
        - name: gpu-a40
          resources:
            - name: "nvidia.com/gpu"
              nominalQuota: 8
        - name: gpu-a100
          resources:
            - name: "nvidia.com/gpu"
              nominalQuota: 4
    - coveredResources: ["cpu", "memory", "ephemeral-storage", "github.com/fuse", "pods"]
      flavors:
      - name: "default-flavor"
        resources:
        - name: "cpu"
          nominalQuota: 256
        - name: "memory"
          nominalQuota: 2Ti
        - name: "ephemeral-storage"
          nominalQuota: 2Ti
        - name: "github.com/fuse"
          nominalQuota: 10k
        - name: "pods"
          nominalQuota: 220
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: pgrunt
  name: lq-all-resources
spec:
  clusterQueue: cq-all-resources

Anything else we need to know?:
I guess that's all, let me know if you need some more information and I will happily provide.
Environment:

Kubernetes version (use kubectl version): Server Version: v1.26.10+rke2r2
Kueue version (use git describe --tags --dirty --always): 0.5.2 installed via 0.1.0 Helm chart
Cloud provider or hardware configuration: on-prem, 8x NVIDIA-A40, AMD EPYC 7502, 1TB RAM
OS (e.g: cat /etc/os-release): Ubuntu 22.04.3 LTS
Kernel (e.g. uname -a): 5.15.0-79-generic
Install tools: Helm v3.11.2, Kustomize v5.0.4-0.20230601165947-6ce0bf390ce3

cc @mimowo @trasc
for ideas

Can you tell me how many characters did the job name have?
I wonder if it's something related to that.

ml-job-annotator-gt-webface-gpu which is 31

Also, it might be helpful if you could show as the output for
kubectl describe workloads/<workload_name> and  kubectl describe jobs/<job_name>

Also, it might be helpful if you could show as the output for kubectl describe workloads/<workload_name> and kubectl describe jobs/<job_name>

Maybe the full yaml of the workload is better

Maybe the full yaml of the workload is better

this can be handy as well kubectl get workloads/<workload_name> -oyaml

Heres the workload, but unfortunately, I no longer have to job and our cluster is fully booked atm. :(
`apiVersion: v1
items:

apiVersion: kueue.x-k8s.io/v1beta1
kind: Workload
metadata:
creationTimestamp: "2024-02-11T10:42:40Z"
generation: 3
labels:
kueue.x-k8s.io/job-uid: a6f3d317-9ab2-44ee-917e-690fd4d29668
name: job-ml-job-annotator-gt-webface-gpu-ff6d8
namespace: pgrunt
resourceVersion: "336381385"
uid: feb1af8b-abe6-4b35-a6f2-29a808a3416f
spec:
active: true
podSets:

count: 1
name: main
template:
metadata:
name: ml-job-annotator-gt-webface-gpu
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- hawking
containers:
- command:
- bash
- -c
- |
export PATH="/opt/venv/bin/:${PATH}" &&
cd /data/workspace/facekit &&
pip install -e . &&
facekit face_annotator multiface ${WORKLOAD_ARGS} --processes 20
env:
- name: GIT_REPO
value: "redacted"
- name: GIT_CHECKOUT_BRANCH
value: "redacted"
- name: WORKLOAD_ARGS
value: ' --input-path /mnt/data/downloader/wikidata/crawled_identities/gt_images.h5
--output-path /mnt/data/downloader/wikidata/crawled_identities/gt_images_annotated_webface.h5 '
- name: OMP_NUM_THREADS
value: "1"
- name: NUMEXPR_NUM_THREADS
value: "1"
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
key: AWS_ACCESS_KEY_ID
name: user-credentials
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
key: AWS_SECRET_ACCESS_KEY
name: user-credentials
- name: CLEARML_API_ACCESS_KEY
valueFrom:
secretKeyRef:
key: CLEARML_API_ACCESS_KEY
name: user-credentials
- name: CLEARML_API_SECRET_KEY
valueFrom:
secretKeyRef:
key: CLEARML_API_SECRET_KEY
name: user-credentials
image: "redacted"
imagePullPolicy: Always
name: ml-main
resources:
limits:
cpu: "20"
ephemeral-storage: 12Gi
memory: 80Gi
nvidia.com/gpu: "2"
requests:
cpu: "10"
ephemeral-storage: 12Gi
memory: 45Gi
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data/user
name: user-configuration
- mountPath: /data/workspace
name: workspace
- mountPath: /srv/dvc_cache/
name: dvc-cache
- mountPath: /mnt/nas.brno/
name: nas-brno
- mountPath: /dev/shm
name: dev-shm
- mountPath: /mnt/data/downloader
name: downloader
- mountPath: /encrypted/INC-12499
name: wiki-hdd
workingDir: /data/workspace
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: registry-credentials
initContainers:
- command:
- bash
- -c
- |
if [[ ! -d "/root/.ssh" ]]; then
mkdir ~/.ssh &&
mkdir ~/.kube &&
cp /data/user/id_* ~/.ssh &&
cp /data/user/.git* ~/ &&
cp /data/user/kubeconfig ~/.kube/config &&
ssh-keyscan -p 7999 -t rsa "redacted" > ~/.ssh/known_hosts &&
cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys &&
chmod 600 ~/.ssh/id_rsa &&
git clone $GIT_REPO &&
cd "$(basename "$GIT_REPO" .git)" &&
git checkout $GIT_CHECKOUT_BRANCH
fi
env:
- name: GIT_REPO
value: "redacted"
- name: GIT_CHECKOUT_BRANCH
value: "redacted"
image: bitnami/git:latest
imagePullPolicy: Always
name: init-git-repo
resources:
limits:
cpu: 250m
memory: 512Mi
requests:
cpu: 100m
memory: 512Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data/user
name: user-configuration
- mountPath: /data/workspace
name: workspace
workingDir: /data/workspace
priorityClassName: ml-low
restartPolicy: Never
runtimeClassName: nvidia
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: user-configuration
projected:
defaultMode: 420
sources:
- secret:
items:
- key: id_rsa
path: id_rsa
- key: id_rsa.pub
path: id_rsa.pub
- key: .git-credentials
path: .git-credentials
- key: kubeconfig
path: kubeconfig
name: user-credentials
- configMap:
items:
- key: .gitconfig
path: .gitconfig
name: gitconfig
- configMap:
items:
- key: clearml.conf
path: clearml.conf
name: clearml.conf
- hostPath:
path: /srv/dvc_cache/
type: ""
name: dvc-cache
- emptyDir: {}
name: workspace
- hostPath:
path: /mnt/nas.brno
type: ""
name: nas-brno
- configMap:
defaultMode: 420
name: iengine.lic
name: iengine-lic
- emptyDir:
medium: Memory
sizeLimit: 1Gi
name: dev-shm
- hostPath:
path: /mnt/data/downloader
type: ""
name: downloader
- hostPath:
path: /encrypted/INC-12499
type: ""
name: wiki-hdd
priority: 10
priorityClassName: ml-low
priorityClassSource: kueue.x-k8s.io/workloadpriorityclass
queueName: lq-all-resources
status:
admission:
clusterQueue: cq-all-resources
podSetAssignments:

count: 1
flavors:
cpu: default-flavor
ephemeral-storage: default-flavor
memory: default-flavor
nvidia.com/gpu: gpu-a40
pods: default-flavor
name: main
resourceUsage:
cpu: "10"
ephemeral-storage: 12Gi
memory: 45Gi
nvidia.com/gpu: "2"
pods: "1"
conditions:

lastTransitionTime: "2024-02-11T10:42:40Z"
message: Quota reserved in ClusterQueue cq-all-resources
reason: QuotaReserved
status: "True"
type: QuotaReserved
lastTransitionTime: "2024-02-11T10:42:40Z"
message: The workload is admitted
reason: Admitted
status: "True"
type: Admitted
kind: List
metadata:
resourceVersion: ""
`

The pod template in the workload differs from the pod template for the job, for example in this line facekit face_annotator multiface ${WORKLOAD_ARGS} --processes (20 vs 30).

But Kueue should be deleting those unmatching Workloads and create a new one. There is no deletion timestamp in the share yaml (assuming it's the latest state).

The Workload does not have a finalizer, meaning that Kueue removed it, but it somehow didn't call Delete? Or it did and it failed?
Do you see any log lines like: deleting not matching workload or Deleted not matching workload?

The pod template in the workload differs from the pod template for the job, for example in this line facekit face_annotator multiface ${WORKLOAD_ARGS} --processes (20 vs 30).

Sorry, there were some edits afterwards from the developer, but nothing major shouldn't have changed

The Workload does not have a finalizer, meaning that Kueue removed it, but it somehow didn't call Delete? Or it did and it failed?
Do you see any log lines like: deleting not matching workload or Deleted not matching workload?

No logs containing not matching

Indeed the workload is no matching the job and it should be deleted  but is not since it has no owner ref pointing to the job... , maybe the workload is left over from an older job with the same name potentially deleted wit --cascade=orphan.

I will reply with fresh job+workload definitions, so they are 100% matching. Sorry if I caused any confusion so far.

Unfortunately, if you don't specify a cascade option for Job, orphan is the default :(
Which could lead to this situation.
I wonder if we should just delete orphan Workloads... or is it user error to orphan a Workload and we shouldn't remove the object because the user has not chosen to delete it (by not using a different cascade).
But let's leave this investigation for now.
/triage needs-information

Unfortunately, if you don't specify a cascade option for Job, orphan is the default :(

I think it should be background.

via k9s ctrl+d which defaults to Background. I will post the new job+workload tomorrow, sorry for the delay.

@xmolitann Could you confirm if that happened? And if so, what was the motivation to use --cascade=orphan? We are not sure what the correct behavior should be. Options are:

Create a new workload with a new name, to avoid the collision
Inherit the existing workload. this would have the effect that the job would preserve its place in the queue, or be directly unsuspended, if the workload is admitted.

How about not inheriting but recreating the workload, so that there is still maintain equivalence between the job and the workload

I got slack confirmation from @trasc that deleting a job with --cascade=orphan and recreating (I assume with slightly different spec) leads to the observed behavior. In that case I'm wondering if as a fix we could detect this situation (the target workload has a non-existing job owner) and recreate the workload.

I can confirm this, because when I delete the job with background, the workloads gets deleted as well, I can then re-submit the jobs and pod gets admitted. When I delete it with orphan, what you are mentioning happens. So this is rather user error than bug, sorry for confusion. What to do with this behavior I will leave up to you.

In case I wasn't clear I think the issue is rather narrow scope, as this is the following scenario:

job is created and the workload is created by Kueue
job is deleted by the user with cascade=orphan
job template is modified by the user, and re-created with the same name
Issue: the attempt to create a workload fails, because one orphaned workload already exists.

My proposal is to fix it in a least intrusive manner: when we get "Already exists error" (step 4.), then fetch the workload, and verify if the workload is orphaned. If the workload is orphaned, then delete it, which will allow the new workload to be recreated in its place. This does not entail inheriting an existing workload necessarily. As a performance optimization we could inherit such an orphan workload, but I think only if we detect the job template is still equivalent with the workload.

In my opinion a workload should be dedicated to a job (k8s object).
By deleting and creating a new job with the same name you get another object.

I kind of like the idea of just using the UID. However @trasc can you verify what happens when you upgrade kueue? Do we make assumptions about the workload name?
The other point is that if the orphan Workload is not deleted and is not finished, it's consuming quota on the kueue. So maybe that's an argument for garbage collecting it.

By deleting and creating a new job with the same name you get another object.

The proposal https://github.com/kubernetes-sigs/kueue/issues/1726#issuecomment-1944206289 is compatible with this. We don't reuse the workload, but recreate.

I agree that it's compatible, but it's more steps.

I'm also hesitant about using UIDs because it makes the workload names virtually random. Having predictable workload names is a nice feature which can be useful for some users, even for us when documenting features.

I agree that it's compatible, but it's more steps.

Yes, but it is more steps only in this situation, which should be rare anyway.

The other point is that if the orphan Workload is not deleted and is not finished, it's consuming quota on the kueue. So maybe that's an argument for garbage collecting it. Or at least marking it Finished.

Yes, I like the idea of marking orphan workloads as finished (or even deleting).

In my opinion the fist step is

#1732

then add a garbage collection scheme.

I'm also hesitant about using UIDs because it makes the workload names virtually random

We already add a hash at the end of the name, so it's not immediately obvious how to get from the job name to the workload name.

We already add a hash at the end of the name, so it's not immediately obvious how to get from the job name to the workload name.

Right, but if you repeat some script multiple times it is enough to check once the workload name. For example in Kueue periodic tests we can find the same workload names when comparing different runs.

I think the following concerns are still valid:

this will cause all running jobs to stop as the workloads will not match during upgrade, all pending jobs are requeued
the random workload names might be an inconvenience for some users, for example those who periodically run cronjob and want to compare logs
this does not really solve the issue, just makes it less likely given 5-character name, this is 1/16mln, but at scale some users may still hit it, then repro and figuring out the cause will be very difficult

Thus I think it is reasonable to rethink if there are alternatives. I admit in the other approach we need 3 requests (one to detect conflict, one to fetch the new workload, one to check there is no owner reference in the workload), so not ideal either.
How about just deleting a workload from workload_controller in reaction to removed metadata.ownerReference (by kube garbage-collector) which removes it in the "orphan" mode? I think this would also solve the issue. One downside I see is that we would still delete even though "--cascade=orphan" is used.

this will cause all running jobs to stop as the workloads will not match during upgrade, all pending jobs are requeued

Actually, I'm not sure about this (didn't test). Now I think there actually may not be impact here, because the workload with the old scheme can still support the job, based on the ownerReference. Sorry for confusing, in that case the remaining two points aren't that relevant probably.

However @trasc can you verify what happens when you upgrade kueue? Do we make assumptions about the workload name?

@trasc This is my main concern against generating a hash with UID. If the workload is recreated and the readmission or termination against existing Jobs happens, including uid in has would be barriers for updating the kueue version.

The name is only used when creating the workload, after that we only use the owner references to "connect" the wl to its job. In case of kueue upgrade, the old wl will be paired with the jobs based on owner refs (regardless of names), newer workloads are created using the new naming method.

However @trasc can you verify what happens when you upgrade kueue? Do we make assumptions about the workload name?

@trasc This is my main concern against generating a hash with UID. If the workload is recreated and the readmission or termination against existing Jobs happens, including uid in has would be barriers for updating the kueue version.

The name is only used when creating the workload, after that we only use the owner references to "connect" the wl to its job. In case of kueue upgrade, the old wl will be paired with the jobs based on owner refs (regardless of names), newer workloads are created using the new naming method.

That makes sense. I'm fine with including a UID in the hash.


(for discussion) Move boilerplate for last checkpoint into code from docs into helper

(not for pushing to master)
The docs previously contained example code that can be pasted, but
as it is non-trivial, it is better placed as a helper function.
This commit also enhances that code to deal with the case where
no checkpoints exist yet - for example, on a first run.
However, this PR does not find all the needed checkpoints, I think, because they are made incrementally, and this will only find the most recent increment (?)

Linking the related issue for reference: #94.

https://github.com/Parsl/parsl/issues/273 contains some related discussion


Adding an AppLoadContext to TOTPVerifyParams

while I using cloudflare D1 as database in my project, I need init db instance from app context like below:
authenticator.use(
  new TOTPStrategy(
    {
      secret: process.env.ENCRYPTION_SECRET || "",
      magicLinkPath: '/magic',
      sendTOTP: async ({ email, code, magicLink }) => {
          if (process.env.NODE_ENV === 'development') {
          console.log('[Dev-Only] TOTP Code:', code)
          }
          await sendTOTPEmail(email, code, magicLink)
      },
    },
    async ({ email, context }) => {
      const db = getDbFromContext(context.context)
      const user = await db
      .select({
        email: users.email,
        id: users.id,
      })
      .from(users)
      .where(eq(users.email, email))
      .get();

      if(!user) {
        await db.insert(users).values({email: email});
        return await db
          .select({
            email: users.email,
            id: users.id,
          })
          .from(users)
          .where(eq(users.email, email))
          .get();
      } else {
        return user;
      }
    },
  ),
)

Adding an AppLoadContext to TOTPVerifyParams might be a good approach.
export interface TOTPVerifyParams {
  /**
   * The email address provided by the user.
   */
  email: string

  /**
   * The formData object from the Request.
   */
  formData?: FormData

  /**
   * The Request object.
   */
  request: Request
  /**
   * An object of arbitrary for route loaders and actions provided by the
   * server's `getLoadContext()` function.
   */
  context?: AppLoadContext;
}

@shydow: Thank you for raising this issue. Cloudflare does not support process.env for environment variables. You need to get them from the context (https://developers.cloudflare.com/pages/functions/bindings/#environment-variables). We recommend that the function that creates the TOTPStrategy takes the context as a parameter so it can pull out whatever it needs from the context in order to create the TOTPStratgy.
It might look like this in pseudo-code:
export function createAuth(context) {
  const { cloudflare: {env: { ENCRYPTION_SECRET, NODE_ENV}}, db } = context
  // ...
  authenticator.use(
    new TOTPStrategy({ secret: process.env.ENCRYPTION_SECRET,
      sendTOTP: async ({ email, code, magicLink }) => { ... },
      async ({ email, context }) => {
        const user = await db
          .select({ email: users.email, id: users.id })
          .from(users)
          .where(eq(users.email, email))
          .get();
        // ...
     }}))
    // ...

You can also refer to the remix-auth-totp-cloudflare-example.
https://github.com/mw10013/remix-auth-totp-cloudflare-example/blob/ff2236a26347ae951a94b09490b4d659bb455fa1/app/lib/services.server.ts#L47-L122

@dev-xo I also just ran into this, any chance we can re-open/reconsider? :)


Setting up Listener in rest-firebase

Very new to the rest-firebase gem.  Would like to setup rest-firebase to listen for changes to a NEST client.  Have successfully setup rest-firebase with the proper firebase URL, along with the SECRET assigned to NEST developer and have generated a token (does not look to be in the standard JWT format) .  I am able to run an "f.get" and retrieve my NEST data successful; however, if I do too many of these, I get the standard 429 (too many requests error).
So, was wondering what the best way is to setup a listener using Ruby.  Are there any examples out there?
The only example similar was for  using the em-eventsource gem which I am assuming the same thing rest-firebase is capable of doing
require "em-eventsource"
EM.run do
    source = EventMachine::EventSource.new("http://example.com/streaming")
     source.message do |message|
         puts "new message #{message}"
     end
     source.start # Start listening
 end

I don't know what's a NEST client, but if you're looking for event source then it's there. Checkout README.

By using the callback based solution, I am able to change a value on the
NEST and get an immediate response back from the rest-firebase program.
require 'rest-firebase'
firebase = RestFirebase.new(:log_method => method(:puts))
puts "callback also works"
firebase.get('users/tom') do |r|
p r['name']end
puts "It's not blocking... but doing concurrent requests underneath"
firebase.wait # we block here to wait for the request done
puts "DONE"
On Mon, Oct 24, 2016 at 12:29 PM, Eric Scalera<EMAIL_ADDRESS>wrote:

NEST works very closely with Firebase, I think they are both Google
companies.  The NEST thermostats all report to Firebase which allows
real-time updating.
On Mon, Oct 24, 2016 at 12:27 PM, Eric Scalera<EMAIL_ADDRESS>wrote:

Yes, I am using the code, Thank you.  The NEST is a thermostat company
which was bought by Google a few years ago.  Would like to monitor the
thermostat and get a notification when something changes such as the
temperature changing etc.
On Mon, Oct 24, 2016 at 12:12 PM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

I don't know what's a NEST client, but if you're looking for event
source then it's there. Checkout README
https://github.com/CodementorIO/rest-firebase#synopsis.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-255836605,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn2AGXzxboGxMsHEJWjvSYijVSmNWks5q3QMxgaJpZM4KfKN1
.

Lin
Do you know how to disable the  ":log_method?"  I am only looking to view
the changed json element.
Thank you.
Eric
On Mon, Oct 24, 2016 at 1:18 PM, Eric Scalera<EMAIL_ADDRESS>wrote:

By using the callback based solution, I am able to change a value on the
NEST and get an immediate response back from the rest-firebase program.
require 'rest-firebase'
firebase = RestFirebase.new(:log_method => method(:puts))
puts "callback also works"
firebase.get('users/tom') do |r|
p r['name']end
puts "It's not blocking... but doing concurrent requests underneath"
firebase.wait # we block here to wait for the request done
puts "DONE"
On Mon, Oct 24, 2016 at 12:29 PM, Eric Scalera<EMAIL_ADDRESS>wrote:

NEST works very closely with Firebase, I think they are both Google
companies.  The NEST thermostats all report to Firebase which allows
real-time updating.
On Mon, Oct 24, 2016 at 12:27 PM, Eric Scalera<EMAIL_ADDRESS>wrote:

Yes, I am using the code, Thank you.  The NEST is a thermostat company
which was bought by Google a few years ago.  Would like to monitor the
thermostat and get a notification when something changes such as the
temperature changing etc.
On Mon, Oct 24, 2016 at 12:12 PM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

I don't know what's a NEST client, but if you're looking for event
source then it's there. Checkout README
https://github.com/CodementorIO/rest-firebase#synopsis.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-255836605,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn2AGXzxboGxMsHEJWjvSYijVSmNWks5q3QMxgaJpZM4KfKN1
.

NEST works very closely with Firebase, I think they are both Google
companies.  The NEST thermostats all report to Firebase which allows
real-time updating.
On Mon, Oct 24, 2016 at 12:27 PM, Eric Scalera<EMAIL_ADDRESS>wrote:

Yes, I am using the code, Thank you.  The NEST is a thermostat company
which was bought by Google a few years ago.  Would like to monitor the
thermostat and get a notification when something changes such as the
temperature changing etc.
On Mon, Oct 24, 2016 at 12:12 PM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

I don't know what's a NEST client, but if you're looking for event source
then it's there. Checkout README
https://github.com/CodementorIO/rest-firebase#synopsis.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-255836605,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn2AGXzxboGxMsHEJWjvSYijVSmNWks5q3QMxgaJpZM4KfKN1
.

If you don't want :log_method then just don't pass it. I suppose this is what you want?

Yes, I am using the code, Thank you.  The NEST is a thermostat company
which was bought by Google a few years ago.  Would like to monitor the
thermostat and get a notification when something changes such as the
temperature changing etc.
On Mon, Oct 24, 2016 at 12:12 PM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

I don't know what's a NEST client, but if you're looking for event source
then it's there. Checkout README
https://github.com/CodementorIO/rest-firebase#synopsis.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-255836605,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn2AGXzxboGxMsHEJWjvSYijVSmNWks5q3QMxgaJpZM4KfKN1
.

So does it work for you now?

Lin,
Was able to resolve the logging issue.  Have been working on trying to
debug a NilClass issue and was reading through some of the issues related
to this.  I'm not sure this is the same issue as issue #5, but the program
is continually returning the following:
#<NoMethodError: undefined method `[]' for nil:NilClass> "#IO:(closed)"
"RestCore: spent 0.728148 Requested GET
https://firebase-apiserver08-tah01-iad01.dapi.production.nest.com:9553/.json?auth=
<"NEST_TOKEN>
The program is working perfectly with the exception of the NilClass issue.
Also ,  why does the program return the variable three times when I change
the value on the thermostat?
NEST returned variables below

65
"off"
50
"Hallway (George Ross)"

The program does not call the REST get, but get is being sent at the top
level which is what I want, so I do not have to explicitly write a get.
For that reason, I have not figured out how to use the ".tap{} command.
Is there a way to resolve this nilClass issue?
require 'rest-firebase'
require "awesome_print"
f = RestFirebase.new :site =>
'https://firebase-apiserver08-tah01-iad01.dapi.production.nest.com:9553',
:secret => 'NEST_SECRET_KEY',
:d => {:auth_data => ''},
:log_method => method(:p),
# timeout in seconds
:timeout => 20,
# max_retries upon failures. Default is: 0
:max_retries => 3,
# retry_exceptions for which exceptions should retry
# Default is: [IOError, SystemCallError]
:retry_exceptions =>
[IOError, SystemCallError, Timeout::Error],
# error_callback would get called each time there's
# an exception. Useful for monitoring and logging.
:error_callback => method(:puts),
# auth_ttl describes when we should refresh the auth
# token. Set it to false to disable auto-refreshing.
# The default is 23 hours.
:auth_ttl => false,
#:auth_ttl => 82800,
# auth is the auth token from Firebase. Leave it alone
# to auto-generate. Set it to false to disable it.
:auth => 'NEST_AUTH_TOKEN' # Ignore auth for this example!
@reconnect = true
es = f.event_source('')
RestFirebase.pool_size = 10
RestFirebase.pool_idle_time = 60
es.onopen { |sock| p sock } # Called when connected
es.onmessage{ |event, data, sock|
#ap data
puts ""
ap data["data"]["devices"]["thermostats"]["9FN_YpImgnw0NxIECK1_U_3cnYxayIHr"]
["ambient_temperature_f"]
ap data["data"]["devices"]["thermostats"]["9FN_YpImgnw0NxIECK1_U_3cnYxayIHr"]
["hvac_state"]
ap data["data"]["devices"]["thermostats"]["9FN_YpImgnw0NxIECK1_U_3cnYxayIHr"]
["target_temperature_f"]
ap data["data"]["devices"]["thermostats"]["9FN_YpImgnw0NxIECK1_U_3cnYxayIHr"]
["name"]
#
puts ""
 } # Called for each message

Called whenever there's an error
es.onerror  { |error, sock| p error, sock.inspect}
Extra: If we return true in onreconnect callback, it would automatically
reconnect the node for us if disconnected.
#es.onreconnect{ |error, sock| p error; @reconnect }
es.onreconnect{ |error, sock| ; @reconnect }
Start making the request
es.start
puts "callback also works"
0.upto(10) do
f.get('devices') do |r|
puts "======================"
p r['thermostats']["9FN_YpImgnw0NxIECK1_U_3cnYxayIHr"]["name"]
puts "======================"

end
sleep 10
end
puts "It's not blocking... but doing concurrent requests underneath"
f.wait # we block here to wait for the request done
puts "DONE"
Try to close the connection and see it reconnects automatically
es.close
Update users/tom.json
f.put('User', :name => 'Tom')
f.post('User', :name => 'Tom')
puts "=======================================\n"
#p f.get('/Users', :orderBy => '$key', :limitToFirst => 3)
# ap nest.status, :raw => false, :color => {:hash => :blue}
# puts "#{f.get('devices')}"
puts "=======================================\n"
#sleep 10
#f.get('User')
puts user
p f.delete('devices')

# With Firebase queries (it would encode query in JSON for you)
#p f.get('/User', :orderBy => '$key', :limitToFirst => 1)
Need to tell onreconnect stops reconnecting, or even if we close
the connection manually, it would still try to reconnect again.
@reconnect = false
Close the connection to gracefully shut it down.
es.close
Refresh the auth by resetting it
f.auth = nil
On Tue, Oct 25, 2016 at 11:33 AM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

If you don't want :log_method then just don't pass it. I suppose this is
what you want?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-256130293,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn61x33rHRr2JYBsuPTEcs6GZdd6Xks5q3ktlgaJpZM4KfKN1
.

Yes, it works except I have not yet been able to resolve the NilClass issue.
#<NoMethodError: undefined method `[]' for nil:NilClass> "#IO:(closed)"
On Wed, Oct 26, 2016 at 3:32 AM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

So does it work for you now?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-256309673,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn4ThLkReKuFihlTde_KUaMZkD6geks5q3yxIgaJpZM4KfKN1
.

Sorry but this is too hard to read. Could you please remove quotes if you're sending from emails, and maybe use gist to post the codes?

Sure,  please go to the following link:
https://gist.github.com/oscar-johnson/804e92f834f85fe1f18cc0a475ac0eb4
On Wed, Oct 26, 2016 at 8:45 AM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

Sorry but this is too hard to read. Could you please remove quotes if
you're sending from emails, and maybe use gist to post the codes?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-256389408,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn1LE_BA6y4VWDat_ld9nNGzjpQoaks5q33WOgaJpZM4KfKN1
.

Please try this link rather than the original link:
https://gist.github.com/oscar-johnson/cde65aa5976fbefb339457930f6d78f5
On Wed, Oct 26, 2016 at 10:11 AM, Eric Scalera<EMAIL_ADDRESS>wrote:

Sure,  please go to the following link:
https://gist.github.com/oscar-johnson/804e92f834f85fe1f18cc0a475ac0eb4
On Wed, Oct 26, 2016 at 8:45 AM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

Sorry but this is too hard to read. Could you please remove quotes if
you're sending from emails, and maybe use gist to post the codes?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-256389408,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn1LE_BA6y4VWDat_ld9nNGzjpQoaks5q33WOgaJpZM4KfKN1
.

I think your server was somehow not returning a proper message. You should check what's returning from your server.

It looks like its receiving a keep-alive from the server with null
data so the socket is closing.
The highlighted text is what I am seeing in the debugger.
def onmessage_for sock
while IO.select([sock], [], [], READ_WAIT)
event = sock.readline("\n\n").split("\n").inject({}) do |r, i|
event: {data: null, event: keep-alive}
k, v = i.split(': ', 2)
r[k] = v
r
end
onmessage(event['event'], event['data'], sock)
end
close_sock(sock)
onerror(EOFError.new, sock)
rescue IOError, SystemCallError => e
close_sock(sock)
onerror(e, sock)
end
On Wed, Oct 26, 2016 at 10:34 AM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

I think your server was somehow not returning a proper message. You should
check what's returning from your server.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-256421580,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn1DEfpcV-xAhc_PpWQ5SrXq0dFnFks5q348jgaJpZM4KfKN1
.

Then you should probably skip keep-alive event in your code. Also HTML doesn't work in email reply. There's no highlights at all.

Agreed, working on skipping keep-alive events.
On Wed, Oct 26, 2016 at 11:31 AM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

Then you should probably skip keep-alive event in your code. Also HTML
doesn't work in email reply. There's no highlights at all.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-256437289,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn636vublb8QiHLl6JL8t2G5x4jJ_ks5q35yJgaJpZM4KfKN1
.

I am closing this issue. If you have other questions, you could try chatting on gitter. I'm also there.

Lin,
Thanks for your help and thank you for writing such a wonderfully robust
program for everybody to use.   Excellent job.
Regards,
Eric R. Scalera
On Thu, Oct 27, 2016 at 9:09 AM, Lin Jen-Shin (godfat) <
<EMAIL_ADDRESS>wrote:

I am closing this issue. If you have other questions, you could try
chatting on gitter https://gitter.im/CodementorIO/rest-firebase. I'm
also there.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/CodementorIO/rest-firebase/issues/17#issuecomment-256691682,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AV-Kn5Sj6oC_lWVlouVFee4ylFXLB7Slks5q4MzGgaJpZM4KfKN1
.

No problems :)
Thanks for using it!


Broken link on Hugo

My website renders something totally different from what is rendered locally. I'd like to think it has something to do with reinstalling the Mainroad theme after the latest Hugo update. Ideally should look something like this

but I'm getting this on the url https://beyondrawdata.rbind.io
. I'm still new to this, I'd appreciate any help out there

Please use https://discourse.gohugo.io/ for questions/troubleshooting. Also see  Hugo Documentation.