RPC API Create Service: Requested entity was not found error - google-cloud-platform

I have been putting together a Go gRPC client for Cloud Run to use for an application that I am working on. I am able to perform LIST operations on services(and other objects), but not CREATE, REPLACE, DELETE or GET.
I have verified, using tcpdump, that the requests from the client are going to the intended regional endpoint and not to the global endpoint which I am aware only supports LIST.
The error I get is "rpc error: code = NotFound desc = Requested entity was not found."
It is unclear to me from this error message being returned what specific entity was not found.
Is it the case that ALL RPC endpoints only support LIST operations currently? I can think of no other explanation for this behaviour. Thanks in advance!
Here is my code:
package main
import (
"context"
"fmt"
runclient "github.com/cristian-radu/cloud-run-grpc/pkg/client"
runpb "github.com/cristian-radu/cloud-run-grpc/pkg/pb"
"google.golang.org/api/option"
)
func main() {
ctx := context.Background()
servicesClient, err := runclient.NewServicesClient(ctx, option.WithEndpoint("us-central1-run.googleapis.com:443"))
if err != nil {
fmt.Println(err)
}
service := runpb.Service{
ApiVersion: "serving.knative.dev/v1",
Kind: "Service",
Metadata: &runpb.ObjectMeta{
Name: "namespaces/{project-id}/services/test",
Namespace: "{project-id}",
Annotations: map[string]string{
"run.googleapis.com/ingress": "all",
},
},
Spec: &runpb.ServiceSpec{
Template: &runpb.RevisionTemplate{
Metadata: &runpb.ObjectMeta{
Annotations: map[string]string{
"autoscaling.knative.dev/maxScale": "10",
},
},
Spec: &runpb.RevisionSpec{
ServiceAccountName: "{service-account}#{project-id}.iam.gserviceaccount.com",
Containers: []*runpb.Container{
{
Image: "us-docker.pkg.dev/cloudrun/container/hello",
Ports: []*runpb.ContainerPort{
{
ContainerPort: 8080,
},
},
},
},
},
},
Traffic: []*runpb.TrafficTarget{
{
Percent: 100,
LatestRevision: true,
},
},
},
}
req := runpb.CreateServiceRequest{
Parent: "namespaces/{project-id}",
Service: &service,
}
_, err = servicesClient.CreateService(ctx, &req)
if err != nil {
fmt.Println(err)
}
authorizedDomainsClient, err := runclient.NewAuthorizedDomainsClient(ctx, option.WithEndpoint("us-central1-run.googleapis.com:443"))
if err != nil {
fmt.Println(err)
}
listAuthorizedDomains := runpb.ListAuthorizedDomainsRequest{Parent: "namespaces/{project-id}"}
authorizedDomainsIterator := authorizedDomainsClient.ListAuthorizedDomains(ctx, &listAuthorizedDomains)
fmt.Printf("Authorized Domains: %v \n\n", authorizedDomainsIterator.Response)
configurationsClient, err := runclient.NewConfigurationsClient(ctx, option.WithEndpoint("us-central1-run.googleapis.com:443"))
if err != nil {
fmt.Println(err)
}
listConfigurations := runpb.ListConfigurationsRequest{Parent: "namespaces/{project-id}"}
configurationsResp, err := configurationsClient.ListConfigurations(ctx, &listConfigurations)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Configurations: %v \n\n", configurationsResp)
domainMappingsClient, err := runclient.NewDomainMappingsClient(ctx, option.WithEndpoint("us-central1-run.googleapis.com:443"))
if err != nil {
fmt.Println(err)
}
listDomainMappings := runpb.ListDomainMappingsRequest{Parent: "namespaces/{project-id}"}
domainMappingsResp, err := domainMappingsClient.ListDomainMappings(ctx, &listDomainMappings)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Domain Mappings: %v \n\n", domainMappingsResp)
revisionsClient, err := runclient.NewRevisionsClient(ctx, option.WithEndpoint("us-central1-run.googleapis.com:443"))
if err != nil {
fmt.Println(err)
}
revisions := runpb.ListRevisionsRequest{Parent: "namespaces/{project-id}"}
revisionsResp, err := revisionsClient.ListRevisions(ctx, &revisions)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Revisions: %v \n\n", revisionsResp)
routesClient, err := runclient.NewRoutesClient(ctx, option.WithEndpoint("us-central1-run.googleapis.com:443"))
if err != nil {
fmt.Println(err)
}
routes := runpb.ListRoutesRequest{Parent: "namespaces/{project-id}"}
routesResp, err := routesClient.ListRoutes(ctx, &routes)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Routes: %v \n\n", routesResp)
}
The output I get:
rpc error: code = NotFound desc = Requested entity was not found.
Authorized Domains: <nil>
Configurations: api_version:"serving.knative.dev/v1" kind:"ConfigurationList" items:{api_version:"serving.knative.dev/v1" kind:"Configuration" metadata:{name:"test-1" namespace:"{project-number}" self_link:"/apis/serving.knative.dev/v1/namespaces/{project-number}/configurations/test-1" uid:"90cc5b51-c40e-4692-871f-f9beb8ab6bd2" resource_version:"AAXFqFkSE1k" generation:2 create_time:{seconds:1624114599 nanos:280472000} labels:{key:"cloud.googleapis.com/location" value:"us-central1"} labels:{key:"serving.knative.dev/route" value:"test-1"} labels:{key:"serving.knative.dev/service" value:"test-1"} labels:{key:"serving.knative.dev/serviceUid" value:"1bf35167-9557-41a1-8a83-fb6b9cc4f3ec"} annotations:{key:"client.knative.dev/user-image" value:"us-docker.pkg.dev/cloudrun/container/hello"} annotations:{key:"run.googleapis.com/client-name" value:"cloud-console"} annotations:{key:"serving.knative.dev/creator" value:"{service-account}#{project-id}.iam.gserviceaccount.com"} annotations:{key:"serving.knative.dev/lastModifier" value:"me#example.com"} owner_references:{api_version:"Service" name:"test-1" uid:"1bf35167-9557-41a1-8a83-fb6b9cc4f3ec" block_owner_deletion:true 5:"serving.knative.dev/v1" 7:1}} spec:{template:{metadata:{name:"test-1-00002-mer" annotations:{key:"autoscaling.knative.dev/maxScale" value:"100"} annotations:{key:"run.googleapis.com/client-name" value:"cloud-console"} annotations:{key:"run.googleapis.com/sandbox" value:"gvisor"}} spec:{container_concurrency:80 timeout_seconds:300 service_account_name:"{service-account}#{project-id}.iam.gserviceaccount.com" containers:{image:"us-docker.pkg.dev/cloudrun/container/hello" resources:{3:8080} ports:{name:"\n\x06memory\x12\x05512Mi"}}}}} status:{observed_generation:2 latest_created_revision_name:"test-1-00002-mer" latest_ready_revision_name:"test-1-00002-mer" conditions:{type:"Ready" status:"True" last_transition_time:{seconds:1624115077 nanos:363769000}}}} unreachable:"asia-east1" unreachable:"asia-east2" unreachable:"asia-northeast1" unreachable:"asia-northeast2" unreachable:"asia-northeast3" unreachable:"asia-south1" unreachable:"asia-south2" unreachable:"asia-southeast1" unreachable:"asia-southeast2" unreachable:"australia-southeast1" unreachable:"australia-southeast2" unreachable:"europe-central2" unreachable:"europe-north1" unreachable:"europe-west1" unreachable:"europe-west2" unreachable:"europe-west3" unreachable:"europe-west4" unreachable:"europe-west6" unreachable:"northamerica-northeast1" unreachable:"southamerica-east1" unreachable:"us-east1" unreachable:"us-east4" unreachable:"us-west1" unreachable:"us-west2" unreachable:"us-west3" unreachable:"us-west4"
Domain Mappings: api_version:"domains.cloudrun.com/v1" kind:"DomainMappingList" 6:"asia-east1" 6:"asia-east2" 6:"asia-northeast1" 6:"asia-northeast2" 6:"asia-northeast3" 6:"asia-south1" 6:"asia-south2" 6:"asia-southeast1" 6:"asia-southeast2" 6:"australia-southeast1" 6:"australia-southeast2" 6:"europe-central2" 6:"europe-north1" 6:"europe-west1" 6:"europe-west2" 6:"europe-west3" 6:"europe-west4" 6:"europe-west6" 6:"northamerica-northeast1" 6:"southamerica-east1" 6:"us-east1" 6:"us-east4" 6:"us-west1" 6:"us-west2" 6:"us-west3" 6:"us-west4"
Revisions: api_version:"serving.knative.dev/v1" kind:"RevisionList" items:{api_version:"serving.knative.dev/v1" kind:"Revision" metadata:{name:"test-1-00002-mer" namespace:"{project-number}" self_link:"/apis/serving.knative.dev/v1/namespaces/{project-number}/revisions/test-1-00002-mer" uid:"a9baacff-d6f8-48ac-bbdc-98ceff612292" resource_version:"AAXFH+YLhiQ" generation:1 create_time:{seconds:1624115070 nanos:453178000} labels:{key:"cloud.googleapis.com/location" value:"us-central1"} labels:{key:"serving.knative.dev/configuration" value:"test-1"} labels:{key:"serving.knative.dev/configurationGeneration" value:"2"} labels:{key:"serving.knative.dev/route" value:"test-1"} labels:{key:"serving.knative.dev/service" value:"test-1"} labels:{key:"serving.knative.dev/serviceUid" value:"1bf35167-9557-41a1-8a83-fb6b9cc4f3ec"} annotations:{key:"autoscaling.knative.dev/maxScale" value:"100"} annotations:{key:"run.googleapis.com/client-name" value:"cloud-console"} annotations:{key:"run.googleapis.com/sandbox" value:"gvisor"} annotations:{key:"serving.knative.dev/creator" value:"me#example.com"} owner_references:{api_version:"Configuration" name:"test-1" uid:"90cc5b51-c40e-4692-871f-f9beb8ab6bd2" block_owner_deletion:true 5:"serving.knative.dev/v1" 7:1}} spec:{container_concurrency:80 timeout_seconds:300 service_account_name:"{service-account}#{project-id}.iam.gserviceaccount.com" containers:{image:"us-docker.pkg.dev/cloudrun/container/hello" resources:{3:8080} ports:{name:"\n\x06memory\x12\x05512Mi"}}} status:{observed_generation:1 conditions:{type:"Ready" status:"True" last_transition_time:{seconds:1624115077 nanos:320431000}} conditions:{type:"Active" status:"True" last_transition_time:{seconds:1624115082 nanos:217762000} severity:"Info"} conditions:{type:"ContainerHealthy" status:"True" last_transition_time:{seconds:1624115077 nanos:320431000}} conditions:{type:"ResourcesAvailable" status:"True" last_transition_time:{seconds:1624115076 nanos:732413000}} log_url:"https://console.cloud.google.com/logs/viewer?project={project-id}&resource=cloud_run_revision/service_name/test-1/revision_name/test-1-00002-mer&advancedFilter=resource.type%3D%22cloud_run_revision%22%0Aresource.labels.service_name%3D%22test-1%22%0Aresource.labels.revision_name%3D%22test-1-00002-mer%22" image_digest:"us-docker.pkg.dev/cloudrun/container/hello#sha256:244fd3d0268aa56777020d0bd1b9c0b828f2f0a8f403dbcd26eba5610a450e2c"}} unreachable:"asia-east1" unreachable:"asia-east2" unreachable:"asia-northeast1" unreachable:"asia-northeast2" unreachable:"asia-northeast3" unreachable:"asia-south1" unreachable:"asia-south2" unreachable:"asia-southeast1" unreachable:"asia-southeast2" unreachable:"australia-southeast1" unreachable:"australia-southeast2" unreachable:"europe-central2" unreachable:"europe-north1" unreachable:"europe-west1" unreachable:"europe-west2" unreachable:"europe-west3" unreachable:"europe-west4" unreachable:"europe-west6" unreachable:"northamerica-northeast1" unreachable:"southamerica-east1" unreachable:"us-east1" unreachable:"us-east4" unreachable:"us-west1" unreachable:"us-west2" unreachable:"us-west3" unreachable:"us-west4"
Routes: api_version:"serving.knative.dev/v1" kind:"RouteList" items:{api_version:"serving.knative.dev/v1" kind:"Route" metadata:{name:"test-1" namespace:"{project-number}" self_link:"/apis/serving.knative.dev/v1/namespaces/{project-number}/routes/test-1" uid:"d9ce0d4d-2477-4d14-9920-2a26728c9b6e" resource_version:"AAXFIQRxbns" generation:1 create_time:{seconds:1624114599 nanos:247571000} labels:{key:"cloud.googleapis.com/location" value:"us-central1"} labels:{key:"serving.knative.dev/service" value:"test-1"} labels:{key:"serving.knative.dev/serviceUid" value:"1bf35167-9557-41a1-8a83-fb6b9cc4f3ec"} annotations:{key:"client.knative.dev/user-image" value:"us-docker.pkg.dev/cloudrun/container/hello"} annotations:{key:"run.googleapis.com/client-name" value:"cloud-console"} annotations:{key:"run.googleapis.com/ingress" value:"all"} annotations:{key:"run.googleapis.com/ingress-status" value:"all"} annotations:{key:"serving.knative.dev/creator" value:"{service-account}#{project-id}.iam.gserviceaccount.com"} annotations:{key:"serving.knative.dev/lastModifier" value:"me#example.com"} owner_references:{api_version:"Service" name:"test-1" uid:"1bf35167-9557-41a1-8a83-fb6b9cc4f3ec" block_owner_deletion:true 5:"serving.knative.dev/v1" 7:1}} spec:{target:{configuration_name:"test-1" percent:100}} status:{observed_generation:1 conditions:{type:"Ready" status:"True" last_transition_time:{seconds:1624115082 nanos:399315000}} traffic:{revision_name:"test-1-00002-mer" percent:100 latest_revision:true} url:"https://test-1-azcqr7ym2a-uc.a.run.app" address:{url:"https://test-1-azcqr7ym2a-uc.a.run.app"}}} unreachable:"asia-east1" unreachable:"asia-east2" unreachable:"asia-northeast1" unreachable:"asia-northeast2" unreachable:"asia-northeast3" unreachable:"asia-south1" unreachable:"asia-south2" unreachable:"asia-southeast1" unreachable:"asia-southeast2" unreachable:"australia-southeast1" unreachable:"australia-southeast2" unreachable:"europe-central2" unreachable:"europe-north1" unreachable:"europe-west1" unreachable:"europe-west2" unreachable:"europe-west3" unreachable:"europe-west4" unreachable:"europe-west6" unreachable:"northamerica-northeast1" unreachable:"southamerica-east1" unreachable:"us-east1" unreachable:"us-east4" unreachable:"us-west1" unreachable:"us-west2" unreachable:"us-west3" unreachable:"us-west4"

Related

k8s how to update specific value in secret

I need to update a secret with specific value,(the secret contain additional data) my question is how I can update just the value and not all the secret data (I don't want to override the existing data). I mean if the secret have additional values I don’t want to override them just the entry foo
updSec := v1.Secret{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: "d-values",
Namespace: "terv”,
},
Immutable: nil,
Data: nil,
StringData: nil,
Type: "Opaque",
}
updSec.Data[“foo”] = newVal
if err := r.Client.Update(ctx, &updSec); err != nil {
return ctrl.Result{}, err
}
The issue is that the secret is already exist and here im creating new object and not sure how to do it right ...I need for secret that called d-values just update the newVal for key foo
update
when trying the code in the answer after I run the
patch, err := yaml.Marshal(updSec)
the data looks like following
and the patch are failed with error, any idea if its related ?
if I try with the c.Client.Update it works but not with Patch but the Patch is the right way as if I've ties before is should keep them..
I don't think you can update a single key using the Update method, but you can certainly do that using Patch instead. Here's an example that uses a StrategicMergePatch; it will replace the key val2 in a secret with the value newval:
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"path/filepath"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
var kubeconfig *string
var namespace *string
var secretname *string
namespace = flag.String("namespace", "", "namespace of secret")
secretname = flag.String("name", "", "name of secret")
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
if *namespace == "" {
panic(fmt.Errorf("you must specify a namespace"))
}
if *secretname == "" {
panic(fmt.Errorf("you must specify a secret name"))
}
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
secretClient := clientset.CoreV1().Secrets(*namespace)
ctx := context.TODO()
updSec := v1.Secret{
Data: map[string][]byte{
"val2": []byte("newval"),
},
}
payloadBytes, err := json.Marshal(updSec)
if err != nil {
panic(err)
}
if _, err = secretClient.Patch(ctx, *secretname,
types.StrategicMergePatchType, payloadBytes, metav1.PatchOptions{}); err != nil {
panic(err)
}
// Fetch updated secret
sec, err := secretClient.Get(ctx, *secretname, metav1.GetOptions{})
if err != nil {
panic(err)
}
secJson, err := json.MarshalIndent(sec, "", " ")
if err != nil {
panic(err)
}
fmt.Print(string(secJson))
}
For example, if I create a secret like this:
kubectl create secret generic \
--from-literal val1=key1 \
--from-literal val2=key2 example
And then run the above code like this:
go run main.go -namespace default -name example
The code will output the update secret. Looking at the data section, we see:
"data": {
"val1": "a2V5MQ==",
"val2": "bmV3dmFs"
},
And if we decode val2 we see:
$ kubectl get secret example -o json | jq '.data.val2|#base64d'
"newval"
Using the Operator SDK
If you're working with the Operator SDK, you can use Update if you're first reading the existing value, like this:
// Read the existing secret
secret := &corev1.Secret{}
if err := r.Get(ctx, req.NamespacedName, secret); err != nil {
panic(err)
}
// Check if it needs to be modified
val, ok := secret.Data["val2"]
// If yes, update the secret with a new value and then write
// the entire object back with Update
if !ok || !bytes.Equal(val, []byte("val2")) {
ctxlog.Info("needs update", "secret", secret)
secret.Data["val2"] = []byte("newval")
if err := r.Update(ctx, secret); err != nil {
panic(err)
}
}
You can use the Patch method if you only want to submit a partial update:
if !ok || !bytes.Equal(val, []byte("val2")) {
ctxlog.Info("needs update", "secret", secret)
newVal := corev1.Secret{
Data: map[string][]byte{
"val2": []byte("newval"),
},
}
patch, err := json.Marshal(newVal)
if err != nil {
panic(err)
}
if err := r.Client.Patch(ctx, secret, client.RawPatch(types.StrategicMergePatchType, patch)); err != nil {
panic(err)
}
}
This is pretty much identical to the earlier example. There are examples of using the client.Patch method in the docs, but I'll be honest, I don't find the example very clear.

Google Cloud Platform presignURL using Go

Trying to upload a picture to Google Cloud Platform, I always get the same err "<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GOOG4-RSA-SHA256 20.................951Z".
I did add a service-account to the bucket with the role Storage Admin and Storage Object Admin as you can see on the pic
I have generated a Key(for the service account) and downloaded it as .json file, then I generate a presignURL using this code:
// key is the downloaded .json key file from the GCP service-account
// the return string is the presignedURL
func getPresignedURL(path, key string) (string, error) {
sakeyFile := filepath.Join(path, key)
saKey, err := ioutil.ReadFile(sakeyFile)
if err != nil {
log.Fatalln(err)
}
cfg, err := google.JWTConfigFromJSON(saKey)
if err != nil {
log.Fatalln(err)
}
bucket := "mybucket"
ctx := context.Background()
client, err := storage.NewClient(ctx)
if err != nil {
return "", fmt.Errorf("storage.NewClient: %v", err)
}
defer client.Close()
opts := &storage.SignedURLOptions{
Scheme: storage.SigningSchemeV4,
Method: "PUT",
Headers: []string{
"Content-Type:image/jpeg",
},
Expires: time.Now().Add(15 * time.Minute),
GoogleAccessID: cfg.Email,
PrivateKey: cfg.PrivateKey,
}
u, err := client.Bucket(bucket).SignedURL("mypic.jpeg", opts)
if err != nil {
return "", fmt.Errorf("Bucket(%q).SignedURL: %v", bucket, err)
}
return u, nil
}
The presignedURL looks good, something like this:
https://storage.googleapis.com/djedjepicbucket/mypic.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=djedje%40picstorage-363707.iam.gserviceaccount.com%2F20220926%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20220926T081951Z&X-Goog-Expires=899&X-Goog Signature=3f330715d7a38ea08f99134a16f464fb............5ad800a7665dfb1440034ab1f5ab045252336&X-Goog-SignedHeaders=content-type%3Bhost
Then I read a file(picture) from disk and upload it using the presignURL
// the uri is the presignedURL
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
if err != nil {
return nil, err
}
_, err = io.Copy(body, file)
for key, val := range params {
_ = writer.WriteField(key, val)
}
err = writer.Close()
if err != nil {
return nil, err
}
req, err := http.NewRequest("PUT", uri, body)
req.Header.Set("Content-Type", "image/jpeg")
return req, err
}
Then I exec the request
// the previous func
request, err := newfileUploadRequest(purl, extraParams, "picture", filepath.Join(path, "download.jpeg"))
if err != nil {
log.Fatal(err)
}
client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
log.Fatal(err)
} else {
body := &bytes.Buffer{}
_, err := body.ReadFrom(resp.Body)
if err != nil {
log.Fatal(err)
}
resp.Body.Close()
fmt.Println(resp.StatusCode)
fmt.Println(resp.Header)
fmt.Println(body)
}
Unfortunatly, I always get the same error back
403
map[Alt-Svc:[h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"] Content-Length:[884] Content-Type:[application/xml; charset=UTF-8] Date:[Mon, 26 Sep 2022 08:22:19 GMT] Server:[UploadServer] X-Guploader-Uploadid:[ADPyc......................ECL_4W]]
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GOOG4-RSA-SHA256
20220926T081951Z
20220926/auto/storage/goog4_request
c5f36838af4......................8ffb56329c1eb27f</StringToSign><CanonicalRequest>PUT
/djedjepicbucket/mypic.jpeg
X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=djedje%40picstorage-363707.iam.gserviceaccount.com%2F20220926%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20220926T081951Z&X-Goog-Expires=899&X-Goog-SignedHeaders=content-type%3Bhost
content-type:multipart/form-data; boundary=5be13cc........................dd6aef6823
host:storage.googleapis.com
content-type;host
UNSIGNED-PAYLOAD</CanonicalRequest></Error>
Actually I have tryied many other ways as well but I basically always get this(more or less) same err back, Does someone have an Idea what am I forgetting(I am on that for 2 days now...) ? Thank you
=============================
I edited the question, that code works perfectly
Found the answer, in the both getPresignedURL() and newfileUploadRequest() func, the Header must be set to "Content-Type:application/octet-stream"(or "Content-Type:image/jpeg" for instance if the picture need to be display using its URL), then the pic is uploaded without issue.

Localstack: AWS was not able to validate the provided access credentials

When trying to use EC2 client, I get the following error:
=== RUN TestEc2
time="2022-06-10T14:18:43-07:00" level=info msg="starting localstack"
time="2022-06-10T14:18:44-07:00" level=info msg="waiting for localstack to start..."
time="2022-06-10T14:19:01-07:00" level=info msg="localstack: finished waiting"
all_test.go:305: operation error EC2: RunInstances, https response error StatusCode: 401, RequestID: 080f9f11-67d7-4061-86d3-e581551458c1, api error AuthFailure: AWS was not able to validate the provided access credentials
--- FAIL: TestEc2 (18.47s)
FAIL
FAIL command-line-arguments 19.197s
FAIL
func TestEc2(t *testing.T) {
ls, err := localstack.NewInstance()
if err != nil {
log.Fatalf("could not connect to docker: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
if err := ls.StartWithContext(ctx); err != nil {
log.Fatalf("could not start Localstack: %v", err)
}
ec2Client = ec2.NewFromConfig(awsConfig(ctx, ls, localstack.EC2))
createInstance(t, ec2Client)
}
func awsConfig(ctx context.Context, l *localstack.Instance, s localstack.Service) aws.Config {
rf := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
return aws.Endpoint{
PartitionID: "aws",
URL: l.EndpointV2(s),
SigningRegion: endpoints.UsEast1RegionID,
}, nil
})
cfg, err := config.LoadDefaultConfig(ctx,
config.WithRegion("us-east-1"),
config.WithEndpointResolverWithOptions(rf),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("dummy", "dummy", "dummy")),
)
if err != nil {
log.Fatalf("could not load config: %v", err)
}
return cfg
}
func createInstance(t *testing.T, c *ec2.Client) types.Instance {
t.Helper()
result, err := c.RunInstances(
context.TODO(),
&ec2.RunInstancesInput{
ImageId: aws.String("ami-e7527ed7"),
InstanceType: types.InstanceTypeT2Micro,
MinCount: aws.Int32(1),
MaxCount: aws.Int32(1),
})
if err != nil {
t.Fatal(err)
}
if result == nil {
t.Fatal("empty RunInstance result")
}
if len(result.Instances) != 1 {
t.Fatalf("exptected 1 instance, got %d", len(result.Instances))
}
return result.Instances[0]
}
But if instead I use the deprecated EndpointResolverFunc everything seem to work OK
r := aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
return aws.Endpoint{
PartitionID: "aws",
URL: l.EndpointV2(s),
SigningRegion: endpoints.UsEast1RegionID,
}, nil
})
cfg, err := config.LoadDefaultConfig(ctx,
....
config.WithEndpointResolver(r),
)
Anyone has any idea what I might be missing?

Go GORM Mocking Begin Expected

I am trying to test a function that gets some details then update details in db. I am using gorm for my ORM and mocking db exec with DATA-DOG/sqlmock. But I keep getting expected begin error but not sure where I am messing up. I tried many variations of the code where I remove the expectBegin expectCommit etc.
Here is the code I am trying to test:
// UpsertUserProfile saves the user if doesn't exists and adds the OAuth profile
// and updates existing user info if record exist in db
func (o *ORM) UpsertUserProfile(gu *goth.User) (*models.User, error) {
db := o.DB
up := &models.UserProfile{}
u, err := models.GothUserToDBUser(gu, false)
if err != nil {
return nil, err
}
tx := db.Where("email = ?", gu.Email).First(u)
if tx.Error != nil && tx.Error != gorm.ErrRecordNotFound {
return nil, tx.Error
}
if tx := db.Model(u).Save(u); tx.Error != nil {
return nil, tx.Error
}
tx = db.Where("email = ? AND provider = ? AND external_user_id = ?", gu.Email, gu.Provider, gu.UserID).First(up)
if tx.Error != nil && tx.Error != gorm.ErrRecordNotFound {
return nil, tx.Error
}
up, err = models.GothUserToDBUserProfile(gu, false)
if err != nil {
return nil, err
}
up.User = *u
if tx := db.Model(up).Save(up); tx.Error != nil {
return nil, tx.Error
}
return u, nil
}
And here is the test code
func TestORM_UpsertUserProfile(t *testing.T) {
mockdb, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}
gormDB, err := gorm.Open(postgres.New(postgres.Config{
Conn: mockdb,
}), &gorm.Config{})
if err != nil {
t.Fatal(err.Error())
}
defer mockdb.Close()
id, _ := uuid.NewV4()
rows := sqlmock.NewRows([]string{"id", "first_name", "last_name"}).
AddRow(id.String(), "fname", "lname")
profileRows := sqlmock.NewRows([]string{"email"}).AddRow("email")
// Test cases
t.Run("success", func(t *testing.T) {
o := &ORM{
DB: gormDB,
}
now := time.Now()
fName := "fname"
lName := "lname"
wantUsr := models.User{
Email: "email",
FirstName: &fName,
LastName: &lName,
BaseModelSoftDelete: models.BaseModelSoftDelete{
BaseModel: models.BaseModel{
ID: id,
CreatedAt: &now,
UpdatedAt: &now,
},
},
}
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "users"`)).WithArgs("email").WillReturnRows(rows)
mock.ExpectBegin()
mock.ExpectExec(regexp.QuoteMeta(`UPDATE`)).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectCommit()
mock.ExpectBegin()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user_profiles"`)).WithArgs("email", "provider", "testID").WillReturnRows(profileRows)
mock.ExpectCommit()
mock.ExpectBegin()
got, err := o.UpsertUserProfile(&goth.User{Email: "email", UserID: "testID", Provider: "provider"})
if (err != nil) != false {
t.Errorf("ORM.UpsertUserProfile() error = %v, wantErr %v", err, false)
return
}
if !reflect.DeepEqual(got, wantUsr) {
t.Errorf("ORM.UpsertUserProfile() = %v, want %v", got, wantUsr)
}
})
}
but the test keeps returning this error
SELECT * FROM "user_profiles" WHERE email = 'email' AND provider = 'provider' AND external_user_id = 'testID' ORDER BY "user_profiles"."id" LIMIT 1
/Users/public/Projects/go-rest-service/internal/orm/orm_test.go:260: ORM.UpsertUserProfile() error = call to Query 'SELECT * FROM "user_profiles" WHERE email = $1 AND provider = $2 AND external_user_id = $3 ORDER BY "user_profiles"."id" LIMIT 1' with args [{Name: Ordinal:1 Value:email} {Name: Ordinal:2 Value:provider} {Name: Ordinal:3 Value:testID}], was not expected, next expectation is: ExpectedBegin => expecting database transaction Begin, wantErr false

Unit testing client-go function that auths and returns a k8s clientset

I am writing the simplest fxn possible using client-go that justs performs in-cluster authentication and returns a pointer to the kubernetes.Clientset object
// getInClusterAuth performs in cluster authentication and returns the clientset
func getInClusterAuth() (*kubernetes.Clientset, error) {
// creates the in-cluster config
config, err := rest.InClusterConfig()
if err != nil {
return nil, err
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
return clientset, nil
}
Since this is sth that not only does it run against an external system (a k8s api server) but it is also supposed to be running from within a Pod once deployed, what is the appropriate way of unit-testing it?
Could it be that it is an acceptable practice to cover the case in e2e or integration tests?
you can use k8s.io/client-go/kubernetes/fake.NewSimpleClientset to mock a clientSet in your unit test .
import (
"context"
"testing"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
func TestHelloWorld(t *testing.T) {
clientset := fake.NewSimpleClientset(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "influxdb-v2",
Namespace: "default",
Annotations: map[string]string{},
},
}, &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "chronograf",
Namespace: "default",
Annotations: map[string]string{},
},
})
_, err := clientset.CoreV1().Pods(v1.NamespaceDefault).Get(context.Background(), "influxdb-v2", metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
t.Error(err)
} else {
t.Errorf("failed to get service from apiserver: %s", err)
}
}
p := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "helloooooo"}}
_, err = clientset.CoreV1().Pods(v1.NamespaceDefault).Create(context.Background(), p, metav1.CreateOptions{})
if err != nil {
t.Fatalf("error injecting pod add: %v", err)
}
}
this is a sample: a fakeclient case