How to pass single quote to the exec.Command on Go lang - go

When I type kubectl run my-release-kafka-client --restart='Never' --image docker.io/bitnami/kafka:2.7.0-debian-10-r68 --namespace default --command -- sleep infinity on bash, it works perfectly. However, if I run through the exec.Command(), it says invalid restart policy. The workaround is make it --restart=Never. However, I'd like to know why it happens.
out, _ := exec.Command("kubectl", "run", "my-release-kafka-client", "--restart='Never'", "--image", "docker.io/bitnami/kafka:2.7.0-debian-10-r68", "--namespace", "default", "--command", "--", "sleep", "infinity").CombinedOutput()
fmt.Println(string(out))
result
error: invalid restart policy: 'Never'
See 'kubectl run -h' for help and examples

This is because when you put something in double quote " ", it is considered as string. So when you give "--restart='Never'" then the final value will be --restart='Never' not --restart=Never which is also pretty clear from your error message .error: invalid restart policy: 'Never'
That's why kubectl is looking for restartPolicy 'Never' instead of Never. That's the reason of your error message.

Related

gcloud cli failing to add record when contents start with dash

I'm working with the LetsEncrypt dns-01 challenge system which entails dynamically creating a TXT record in Google Cloud DNS with specific content, so LE can assert proof of ownership for generating a wildcard certificate (so I can't use http-01). The problem is sometimes LE tells me to create a TXT record that starts with a "-", for example -E_DFDFHJKF1783FSHDJ. I cannot get the gcloud cli to properly accept this data no matter what I do.
Example:
gcloud dns record-sets transaction start --zone=myzone
gcloud dns record-sets transaction add "-E_ASDFSDF" --ttl=30 --zone=myzone --name=test --type=TXT
gcloud dns record-sets transaction remove "-A_DSFKHSDF" --ttl=30 --zone=myzone --name=test2 --type=TXT
If you run those commands and inspect the resulting transaction.yaml you can see whether it properly contains the right string. If it did it correct, you should see something like:
- kind: dns#resourceRecordSet
name: test.
rrdatas:
- '"ASDFASDF"'
ttl: 30
type: TXT
I am executing this via Node's child_process, but I have the issue even if I execute it directly from bash, so Node isn't really meaningful issue at the moment. I've tried echoing the value in. I've tried setting an environment variable and using that in the string.
No matter what I do I get an error like the following:
ERROR: (gcloud.dns.record-sets.transaction.add) unrecognized arguments: -E_ASDFSDF
It turns out some characters need to be escaped in the CLI. I can confirm that the following works:
gcloud dns --project=myprojectid record-sets transaction add "\-test123" --name=test.mydomain.com. --ttl=300 --type=TXT --zone=myzoneid

How to set variables using terragrunt before_hook

I need to use some gcloud commands in order to create a Redis instance on GCP as terraform does not support some options that I need.
I'm trying this:
terraform {
# Before apply, run script.
before_hook "create_redis_script" {
commands = ["apply"]
execute = ["REDIS_REGION=${local.module_vars.redis_region}", "REDIS_PROJECT=${local.module_vars.redis_project}", "REDIS_VPC=${local.module_vars.redis_vpc}", "REDIS_PREFIX_LENGHT=${local.module_vars.redis_prefix_lenght}", "REDIS_RESERVED_RANGE_NAME=${local.module_vars.redis_reserved_range_name}", "REDIS_RANGE_DESCRIPTION=${local.module_vars.redis_range_description}", "REDIS_NAME=${local.module_vars.redis_name}", "REDIS_SIZE=${local.module_vars.redis_size}", "REDIS_ZONE=${local.module_vars.redis_zone}", "REDIS_ALT_ZONE=${local.module_vars.redis_alt_zone}", "REDIS_VERSION=${local.module_vars.redis_version}", "bash", "../../../scripts/create-redis-instance.sh"]
}
The script is like this:
echo "[+]Creating IP Allocation Automatically using <$REDIS_VPC-network\/$REDIS_PREFIX_LENGHT>"
gcloud compute addresses create $REDIS_RESERVED_RANGE_NAME \
--global \
--purpose=VPC_PEERING \
--prefix-lenght=$REDIS_PREFIX_LENGHT \
--description=$REDIS_RANGE_DESCRIPTION \
--network=$REDIS_VPC
The error I get is:
terragrunt apply
5b35d0bf15d0a0d61b303ed32556b85417e2317f
5b35d0bf15d0a0d61b303ed32556b85417e2317f
5b35d0bf15d0a0d61b303ed32556b85417e2317f
ERRO[0002] Hit multiple errors:
Hit multiple errors:
exec: "REDIS_REGION=us-east1": executable file not found in $PATH
ERRO[0002] Unable to determine underlying exit code, so Terragrunt will exit with error code 1
I encountered the same issue and resigned myself to pass the values as parameters instead of environment variables.
It involves to modify the script and is a far less clearer declaration, but it works :|

chaincode argument error: unexpected end of JSON input

I have created a test network and I am able to install the chaincode I have created in golang. But when instantiating it I receive the following:
2020-03-24 08:00:00.843 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 04a Using default escc
2020-03-24 08:00:00.844 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 04b Using default vscc
Error: chaincode argument error: unexpected end of JSON input
If I build the code in its own directory, it compiles without problems.
I can install and instantiate the code in another development network, but not in one I have created from scratch.
Help would be appreciated!
Thanks!
Use quotation marks when referencing CC_CONSTRUCTOR variable. Otherwise, bash prioritizes inner spaces over inner quotation marks:
peer chaincode instantiate -C $CC_CHANNEL_ID -n $CC_NAME -v $CC_VERSION -c "$CC_CONSTRUCTOR" -o $ORDERER_ADDRESS
Thanks. I am setting env variables, then call the instantiate. Same variables are set for the install, which works fine.
export CC_CONSTRUCTOR='{ "Args" : [ "Message" , "Hello World - Init message" ] }'
export CC_NAME="testcc"
export CC_PATH="testcc"
export CC_VERSION="1.1"
export CC_CHANNEL_ID="testchannel"
peer chaincode instantiate -C $CC_CHANNEL_ID -n $CC_NAME -v $CC_VERSION -c $CC_CONSTRUCTOR -o $ORDERER_ADDRESS
I have tried escaping some that might need, that does not work. And again, the very same golang code and JSON constructor works on another test environment.
If I unset the CC_CONSTRUCTOR variable, I receive another error message, hence with high probability that is the problem.
In same cases, this error is generated by
const stateValue = await ctx.stub.getState(state);
when the state does not exist.
In other cases, it is because
evaluateTransaction is used instead of submitTransaction when reading states

shell script echo back fatal error

I am using Elixir's porcelain to invoke shell script, in there I have command like:
#!/usr/bin/env bash
aws s3 sync frontend/dist s3://$S3_BUCKET --delete
echo
Now, if command fails(because of wrong bucket) it displays:
fatal error: An error occurred (InvalidBucketName) when calling the
ListObjects operation: The specified bucket is not valid.
But doesn't return this fatal "fatal error" message back to porcelain. How can I echo this error back?
Edit:
Porcelain code:
Porcelain.shell(". #{Path.join(:code.priv_dir(:hub), "scripts/copy_site_to_s3.sh")}")
I know the possible solution would be to use exec instead of shell but this is more of an example, I have a couple of slightly more complicated but similar shell scripts, facing the same problem.
Another script/example(I am testing failures):
Invoking with:
result = Porcelain.shell(". #{Path.join(:code.priv_dir(:hub),
"scripts/git_clone_pull.sh")} #{github}"
)
IO.inspect result
Script:
if cd frontend; then git reset --hard && git pull; else git clone $1 frontend; fi
It properly fails with:
fatal: Authentication failed for
'https://github.com/x/frontend.git/'
But porcelain result fails to capture message:
%Porcelain.Result{err: nil, out: "", status: 128}
If you’ll check the documentation for Porcelain.{exec,shell}/3 options, you’ll see:
:err — specify the way stderr will be passed back to Elixir.
Possible values are the same as for :out. In addition, it accepts the atom :out which denotes redirecting stderr to stdout.
Caveat: when using Porcelain.Driver.Basic, the only supported values are nil (stderr will be printed to the terminal) and :out.
Emphasis is mine. That caveat might be easily proven in the less cumbersome environment, without involving AWS and any other 3rd parties:
iex|1 ▶ Porcelain.shell("ls --gg", err: {:append, "error.log"})
#⇒ ls: unrecognized option '--gg'
# Try 'ls --help' for more information.
# %Porcelain.Result{err: {:append, "error.log"}, out: "", status: 2}
iex|2 ▶ ls "error.log"
# [ERROR] No such file or directory error.log
But we still have :out option!
iex|3 ▶ Porcelain.shell(">&2 echo 'error'", err: :out)
%Porcelain.Result{err: :out, out: "error\n", status: 0}
iex|4 ▶ Porcelain.shell("ls --gg", err: :out)
%Porcelain.Result{
err: :out,
out: "ls: unrecognized option '--gg'\nTry 'ls --help' for more information.\n",
status: 2
}
Naya, luckily even Basic driver might redirect :err to :out. That said, you have two options:
use err: :out parameter, pattern match to when status > 0 and examine standard output, or:
use Porcelain.Driver.Goon driver and deal with your stderr stream like a profi.

How can I "SCRIPT FLUSH" with Redigo?

I try to flush the scripts using the command:" SCRIPT FLUSH" running the code like this:
c.Send("SCRIPT FLUSH")
c.Flush()
spew.Dump(c.Receive())
But I get this output:
(interface {}) <nil>
(redis.Error) (len=33) ERR unknown command 'SCRIPT FLUSH'
When I run the command from the command line I get an OK response:
How can I solve this problem?
Use two arguments:
c.Send("SCRIPT", "FLUSH")
c.Flush()
spew.Dump(c.Receive())
Also, use Do instead of the Send/Flush/Receive calls:
spew.Dump(c.Do("SCRIPT", "FLUSH"))

Resources