How to read external variables - string

I am trying to read a variable sent as an external parameter by --configFile="", but I always get an error not found, even if I pass the absolute path
Vars:
var (
c Config
conf = c.getConf()
app = kingpin.New("exporter", "Exporter for Prometheus.")
configFile = app.Flag("configFile", "Configuration file destination (/etc/exporter/config.yaml)").Default("/etc/exporter/config.yaml").String()
)
Config:
func (c *Config) getConf() *Config {
yamlFile, err := ioutil.ReadFile(string(*configFile))
if err != nil {
log.Errorf("yamlFile.Get err #%v ", err)
}
err = yaml.Unmarshal(yamlFile, c)
if err != nil {
log.Errorf("Unmarshal: %v", err)
}
return c
}
Command/Output:
server:/etc/exporter # ./exporter --configFile="/etc/exporter/config.yaml"
ERRO[0000] yamlFile.Get err #open : no such file or directory
ls -ltr:
total 14152
-rw------- 1 root root 1334 Sep 25 20:47 config.yaml
-rwxrwxr-x 1 root root 14466568 Sep 25 22:03 exporter

Replace code here https://github.com/rafal-szypulka/itm_exporter/blob/master/main.go#L51
with:
conf *Config
Replace code here https://github.com/rafal-szypulka/itm_exporter/blob/master/main.go#L354
with:
p := kingpin.MustParse(app.Parse(os.Args[1:]))
conf = c.getConf()
switch p {

Related

How to implement the mount with golang

Can I use go to implement the mount function in Linux? Mount a path transferred from the foreground to a local path?such as
add_iptables "${shared_file_path}"
if [[ "x$domain" == "xnoDomain" ]]
then
expect > /dev/null 2>&1 <<EOF
set timeout 1
//
spawn /usr/bin/mount -t cifs -o nodev,nosuid,noexec,username=${user_name} ${shared_file_path} ${local_path}
expect {
"Passwor*:" {send "${local_pws}\n"}
}
expect eof
catch wait result
exit [lindex \$result 3]
EOF
else
expect > /dev/null 2>&1 <<EOF
set timeout 1
spawn /usr/bin/mount -t cifs -o nodev,nosuid,noexec,domain=${domain},username=${user_name} ${shared_file_path} ${local_path}
expect {
"Passwor*:" {send "${local_pws}\n"}
}
expect eof
catch wait result
exit [lindex \$result 3]
EOF
You could use Go to wrap a system call to pretty much anything you want.
For instance, in nanobox-io/nanobox with util/provider/dockermachine_mount_windows.go (extract of a larger function):
// ensure cifs/samba utilities are installed
cmd = []string{"sh", "-c", setupCifsUtilsScript()}
if b, err := Run(cmd); err != nil {
lumber.Debug("cifs output: %s", b)
return fmt.Errorf("cifs:%s", err.Error())
}
// mount!
// mount -t cifs -o sec=ntlmssp,username=USER,password=PASSWORD,uid=1000,gid=1000 //192.168.99.1/<path to app> /<vm location>
source := fmt.Sprintf("//192.168.99.1/nanobox-%s", appID)
// mfsymlinks,
config, _ := models.LoadConfig()
additionalOptions := config.NetfsMountOpts
// since the mount command inserts the user into the command string with
// single quotes, we need to escape any single quotes from the real
// username. As the command will be running in bash, the actual escape
// sequence is a bit tricky. Each ' will be replaced with '"'"'.
escapedUser := strings.Replace(user, "'", "'\"'\"'", -1)
opts := fmt.Sprintf("nodev,sec=ntlmssp,user='%s',password='%s',uid=1000,gid=1000", escapedUser, pass)
if additionalOptions != "" {
opts = fmt.Sprintf("%s,%s", additionalOptions, opts)
}
cmd = []string{
"sudo",
"/bin/mount",
"-t",
"cifs",
"-o",
opts,
source,
host,
}
lumber.Debug("cifs mount cmd: %v", cmd)
if b, err := Run(cmd); err != nil {
lumber.Debug("mount output: %s", b)
return fmt.Errorf("mount: output: %s err:%s", b, err.Error())
}

Go "Permission Denied" when trying to create a new backup config file inside /etc

I am writing APIs with functionalities to save backups of config files inside /etc.
backupContents, openErr := os.ReadFile(path)
if openErr == nil {
t := time.Now()
backupPath := path + "." + t.Format("2006-01-02") + ".bk"
err := os.WriteFile(backupPath, backupContents, 0777)
if err != nil {
return err
}
}
if openErr == nil || errors.Is(openErr, os.ErrNotExist) {
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
if _, err := file.Write(updated); err != nil { //update file
return err
}
} else if openErr != nil {
return openErr
}
return nil
}
However, I get the error open /etc/dhcpcd.conf.2022-03-24.bk: permission denied"
I can write to /etc/dhcpcd.conf successfully in the same function as my API binaries run with root access, how come creating a new file in /etc has permission errors? I thought of umask though I think it is not the issue, my default umask was 0022 but I set it to 0000 instead to try, but got the same permission errors. I also tried to replace os.WriteFile with os.OpenFile (with os.O_RDWR|os.O_CREATE flags) or os.Create but get the same permission denied errors.
Here is the permission of the /etc folder:
drwxr-xr-x 115 root root 4096 Mar 24 10:56
Please help, thanks a lot~~
you are probably running the script with a user that is not root user.
try running the script with root user or with sudo.
/etc dir requires root permissions for creating/removing/editing files
You need root permission, run with sudo before the command to run the script or sudo su in bash to get root access.

Golang tarring directory

I am having trouble figuring out how to write a directory into tarball's headerinfo. For example, I have this directory structure:
test [dir]
-- test1.txt
-- subDirA [sub dir]
-- test2.txt
If I tar up test using my Go tar executable, it will untar and have the original structure. If I do a tar -tvf on the tarball, the listing will be:
test/test1.txt
test/subDirA/test2.txt
However if I manually do a tar -cvf of test and then do a tar -tvf, the listing will be:
test/
test/test1.txt
test/subDirA/
test/subDirA/test2.txt
This is what I want my Go tarring program to do as well. In my Go program, I tried to add a new method writeDirToTar to deal with adding directories into the tarWriter. I call either writeFileToTar or writeDirToTar from a fileWalk function. I am getting a "test/subDirA is a directory" error when I call io.Copy(tarWriter, file) in writeDirToTar, which kind of makes sense. Is there a workaround for this?
func writeToTar(fileDir string,
sourceBase string,
tarWriter *tar.Writer,
f os.FileInfo) error {
file, err := os.Open(fileDir)
if err != nil {
log.Print("error opening file")
return err
}
defer file.Close()
// relative paths are used to preserve the directory paths in each file path
relativePath, err := filepath.Rel(sourceBase, fileDir)
tarheader := new(tar.Header)
tarheader.Name = relativePath
tarheader.Size = f.Size()
tarheader.Mode = int64(f.Mode())
tarheader.ModTime = f.ModTime()
err = tarWriter.WriteHeader(tarheader)
if err != nil {
log.Print("error writing tarHeader")
return err
}
_, err = io.Copy(tarWriter, file)
if err != nil {
log.Print("error writing to tarWriter")
return err
}
return nil
}
func writeDirToTar(fileDir string,
sourceBase string,
tarWriter *tar.Writer,
f os.FileInfo) error {
file, err := os.Open(fileDir)
if err != nil {
log.Print("error opening file")
return err
}
defer file.Close()
// relative paths are used to preserve the directory paths in each file path
relativePath, err := filepath.Rel(sourceBase, fileDir)
if tarHeader, err := tar.FileInfoHeader(f, relativePath); err != nil {
log.Print("error writing tarHeader")
return err
}
tarHeader.Name = relativePath
tarheader.Mode = int64(f.Mode())
tarheader.ModTime = f.ModTime()
_, err = io.Copy(tarWriter, file)
if err != nil {
log.Print("error writing to tarWriter")
return err
}
return nil
}
You're missing the Typeflag field in the tar.Header.
For the directory you'll want at least:
tarheader := &tar.Header{
Name: relativePath,
Mode: int64(f.Mode()),
ModTime: f.ModTime(),
Typeflag: tar.TypeDir,
}
You don't want a size here, nor do you want to copy the directory data, since the internal directory data structures mean nothing to tar.
You may also want to add a / to the filename to visually indicate it's a directory and match the POSIX tar behavior.
Alternatively you could just use the tar.FileInfoHeader function just like you did with the files to create the proper header structure.

Go: strange results when using strings with exec.Command

I have a Go function that processes Linux CLI commands and their arguments:
func cmd(cmd string, args ...string) ([]byte, error) {
path, err := exec.Command("/usr/bin/which", cmd).Output()
if err != nil {
return []byte(""), err
}
response, err := exec.Command(string(path), args...).Output()
if err != nil {
response = []byte("Unknown")
}
return response, err
}
Which is called by the following:
func main() {
uname, err := cmd("uname", "-a")
fmt.Println(string(uname))
}
The "which" command returns the correct path to the binary but when it tries to run the second exec command with a dynamic path the return is always:
fork/exec /usr/bin/uname
: no such file or directory
exit status 1
Yet if the second exec command is hardcoded, everything works as expected and prints the uname:
response, err := exec.Command("/usr/bin/uname", args...).Output()
Am I missing something about how exec and strings behave?
Thanks
The which command prints a newline following the name of the executable. The path variable is set to "/usr/bin/uname\n". There is no executable with this path. The extra newline is visible in the error message (the newline just before the ":").
Trim the newline suffix to get the correct name of the executable:
response, err := exec.Command(strings.TrimSuffix(string(path), "\n"), args...).Output()

Download files from RackSpace Files

I have installed PHP SDK using composer. It seems samples folder has old code cause it does not work for me. I want to download some of files from RackSpace folder. Following is my code and it brings nothing.
<?php
require 'vendor/autoload.php';
$authURL = 'https://identity.api.rackspacecloud.com/v2.0/';
$credentials = array(
'username' => 'XXXX',
'apiKey' => 'XXXX'
);
$connection = new \OpenCloud\Rackspace($authURL, $credentials);
// var_dump($connection);exit;
$objstore = $connection->objectStoreService('cloudFiles', 'DFW');
// get our containers
print("Containers:\n");
$conlist = $objstore->listContainers();
//var_dump($conlist);
while($container = $conlist->Next()) {
printf("* %s\n", $container->name);
}
First and foremost, update to the latest release of php-opencloud, currently 1.7.
Next, included sample code for the Object Store is located here, but doesn't include what you were looking to do.
The following code, given a path, will iterate through your containers and save the objects from your container to the destination path ($savePath). If the object already exists in that path, it will be skipped. This version includes output indicating success or failure for each object. Give this a try and let me know if you have any issues.
NOTE: Keep in mind that Rackspace's Cloud Files, Object Store, is handled on a per Datacenter basis so files stored in a container in ORD would be accessible only if you connect to the objectStoreService in ORD.
<?php
require 'vendor/autoload.php';
$authURL = 'https://identity.api.rackspacecloud.com/v2.0/';
$credentials = array(
'username' => 'YOUR_USERNAME',
'apiKey' => 'YOUR_API_KEY',
);
$savePath = '/path/to/files/';
$connection = new \OpenCloud\Rackspace($authURL, $credentials);
$objstore = $connection->objectStoreService('cloudFiles', 'ORD');
// get our containers
print("Containers:\n");
$conlist = $objstore->listContainers();
//var_dump($conlist);
while($container = $conlist->Next()) {
printf("*** %s\n", $container->name);
if($container->name == 'test2')
{
$files = $container->ObjectList();
while($o = $files->Next())
{
$file_name = $o->getName();
// Get our object
$file = $container->getObject($file_name);
printf("** %s\n", $file->getName());
// Let's save this file
echo "* Saving object\n";
if(file_exists($savePath.$file_name))
{
echo "* File already exists! SKIPPING\n\n";
}
else
{
if (!$fp = #fopen($savePath.$file_name, "wb")) {
throw new OpenCloud\Common\Exceptions\IOError(sprintf(
'Could not open file [%s] for writing',
$savePath.$file_name
));
}
//$retval = fwrite($fp, $o->getContent());
if (fwrite($fp, $file->getContent()) === FALSE) {
echo "* ERROR - Cannot write to file ($savePath.$file_name)\n\n";
}
else
{
echo "* File successfully written\n\n";
}
}
}
}
}
Output:
Containers:
*** gallery
*** test2
** 61OUUC44G-L._SL1471_.jpg
* Saving object
* File written
** Computer-Code.jpg
* Saving object
* File written
** accessibility2.jpg
* Saving object
* File written
Directory Listing on my server:
root#app01:/path/to/files# ll
total 960
drwxrwxrwx 2 root root 4096 Nov 8 18:53 ./
drwxr-xr-x 15 www-data www-data 4096 Nov 8 18:20 ../
-rw-r--r-- 1 www-data www-data 68650 Nov 8 18:45 61OUUC44G-L._SL1471_.jpg
-rw-r--r-- 1 www-data www-data 374177 Nov 8 18:45 accessibility2.jpg
-rw-r--r-- 1 www-data www-data 515919 Nov 8 18:45 Computer-Code.jpg
Download Rackspace Cloud Files recursively
<?php
/**
* "require": {
* "rackspace/php-opencloud": "dev-master"
* }
*/
ini_set('memory_limit', '2048M'); // size must be bigger than the biggest file
ini_set('max_execution_time', 0);
require 'vendor/autoload.php';
use OpenCloud\Rackspace;
// Instantiate a Rackspace client.
$client = new Rackspace(Rackspace::US_IDENTITY_ENDPOINT, array(
'username' => '<USERNAME>',
'apiKey' => '<APIKEY>'
));
$objStore = $client->objectStoreService('cloudFiles', 'LON');
$savePath = __DIR__.'/backup/';
// get our containers
print("Containers:\n");
$containersList = $objStore->listContainers();
while($container = $containersList->Next()) {
if( ! in_array($container->name, array('.CDN_ACCESS_LOGS', '<CONTAINER_TO_EXCLUDE>'))) {
printf("*** %s\n", $container->name);
$containerDir = $savePath.$container->name.'/';
if (!is_dir($containerDir)) {
mkdir($containerDir, 0777, true);
}
$files = $container->ObjectList();
while($o = $files->Next()) {
$file_name = $o->getName();
if (file_exists($containerDir . $file_name)) {
echo '## '.$containerDir.$file_name.' already exists'."\n";
continue;
}
// Get our object
$file = $container->getObject($file_name);
if (strpos($file->getName(), '<FILES_TO_EXCLUDE>') !== false) {
continue;
}
$tempDir = $containerDir . dirname($file->getName()) . '/';
if (!is_dir($tempDir)) {
mkdir($tempDir, 0777, true);
}
if (file_put_contents($containerDir . $file_name, $file->getContent())) {
printf("** %s - OK\n", $file->getName());
} else {
printf("** %s - KO\n", $file->getName());
}
unset($file);
}
}
}

Resources