| #include <stdio.h> |
| #include <stdlib.h> |
| #include <getopt.h> |
| #include <limits.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <errno.h> |
| |
| #include "vzcfgscale.h" |
| #include "vzctl.h" |
| #include "list.h" |
| #include "config.h" |
| #include "validate.h" |
| #include "vzfs.h" |
| #include "vz.h" |
| #include "distrconf.h" |
| |
| struct CParam *gparam, *lparam; |
| struct CList *redirect_conf = NULL; |
| |
| static struct option options[] = |
| { |
| {"output-file", required_argument, NULL, PARAM_OUTPUT_FILE}, |
| {"all", required_argument, NULL, PARAM_ALL}, |
| {"cpu-only", required_argument, NULL, PARAM_CPU}, |
| {"disk-only", required_argument, NULL, PARAM_DISK}, |
| {"ubc-only", required_argument, NULL, PARAM_UBC}, |
| {"network-only",required_argument, NULL, PARAM_NET}, |
| {"remove", no_argument, NULL, PARAM_REMOVE}, |
| {"validate", no_argument, NULL, PARAM_VALIDATE}, |
| {"help", no_argument, NULL, PARAM_HELP}, |
| { NULL, 0, NULL, 0 } |
| }; |
| |
| void usage(int rc) |
| { |
| fprintf(rc ? stderr : stdout, "Usage: vzcfgscale [options] <configfile> |
| Options are: |
| \t-o, --output-file <file> Write output to file. Default is stdout |
| \t-a, --all <coeff> Scale all parameters to the value <coeff> |
| \t-c, --cpu-only <coeff> Scale only CPU parameters |
| \t-d, --disk-only <coeff> Scale only disk quota parameters |
| \t-u, --ubc-only <coeff> Scale only UBC parameters |
| \t-n, --network-only <coeff> Scale only network bandwidth parameters |
| \t-v, --validate Validate UBC parameters |
| \t-r, --remove Removes container-specific parameters\n"); |
| exit(rc); |
| } |
| |
| void remove_ve_spec(struct CParam *param) |
| { |
| #define FREE_PARAM(name) \ |
| do { \ |
| if (param->name != NULL) \ |
| { \ |
| free(param->name); \ |
| param->name = NULL; \ |
| } \ |
| } while (0); \ |
| |
| FREE_PARAM(hostname) |
| FREE_PARAM(nameserver) |
| FREE_PARAM(searchdomain) |
| FREE_PARAM(tmpl_set) |
| FREE_PARAM(ve_root_orig) |
| FREE_PARAM(ve_private_orig) |
| FREE_PARAM(shared_base_id) |
| FREE_PARAM(templates) |
| ListFree(param->ipadd); |
| param->ipadd = NULL; |
| } |
| |
| void scale(float ubc_k, float cpu_k, float disk_k, float net_k, |
| struct CParam *param) |
| { |
| unsigned long val0, val1; |
| |
| #define SCALE_UBC(name, k) \ |
| do { \ |
| if (param->name == NULL) \ |
| break; \ |
| val0 = param->name[0]; \ |
| val1 = param->name[1]; \ |
| if (val0 != LONG_MAX) \ |
| val0 *= k; \ |
| if (val0 > LONG_MAX) \ |
| val0 = LONG_MAX; \ |
| if (val1 != LONG_MAX) \ |
| val1 *= k; \ |
| if (val1 > LONG_MAX) \ |
| val1 = LONG_MAX; \ |
| param->name[0] = val0; \ |
| param->name[1] = val1; \ |
| } while(0); |
| |
| #define SCALE_PARAM(name, k) \ |
| do { \ |
| if (param->name == NULL) \ |
| break; \ |
| param->name[0] *= k; \ |
| param->name[1] *= k; \ |
| if (param->name[0] > LONG_MAX) \ |
| param->name[0] = LONG_MAX; \ |
| if (param->name[1] > LONG_MAX) \ |
| param->name[1] = LONG_MAX; \ |
| } while(0); |
| |
| if (ubc_k) |
| { |
| SCALE_UBC(kmemsize, ubc_k) |
| SCALE_UBC(avnumproc, ubc_k) |
| SCALE_UBC(numproc, ubc_k) |
| SCALE_UBC(vmguarpages, ubc_k) |
| SCALE_UBC(oomguarpages, ubc_k) |
| SCALE_UBC(lockedpages, ubc_k) |
| SCALE_UBC(shmpages, ubc_k) |
| SCALE_UBC(privvmpages, ubc_k) |
| SCALE_UBC(numfile, ubc_k) |
| SCALE_UBC(numflock, ubc_k) |
| SCALE_UBC(numpty, ubc_k) |
| SCALE_UBC(numsiginfo, ubc_k) |
| SCALE_UBC(dcachesize, ubc_k) |
| SCALE_UBC(physpages, ubc_k) |
| SCALE_UBC(numtcpsock, ubc_k) |
| SCALE_UBC(numothersock, ubc_k) |
| SCALE_UBC(tcpsndbuf, ubc_k) |
| SCALE_UBC(tcprcvbuf, ubc_k) |
| SCALE_UBC(othersockbuf, ubc_k) |
| SCALE_UBC(dgramrcvbuf, ubc_k) |
| SCALE_UBC(numiptent, ubc_k) |
| } |
| if (cpu_k && param->cpu_units != NULL) |
| { |
| *param->cpu_units *= cpu_k; |
| if (*param->cpu_units > MAXCPUUNITS) |
| *param->cpu_units = MAXCPUUNITS; |
| } |
| if (disk_k) |
| { |
| SCALE_PARAM(quota_block, disk_k) |
| SCALE_PARAM(quota_inode, disk_k) |
| } |
| if (net_k && param->rate != NULL) |
| { |
| struct CList *p; |
| |
| for (p = param->rate; p != NULL; p = p->next) |
| { |
| if (p->val2 == NULL) |
| continue; |
| *p->val2 *= net_k; |
| if (*p->val2 > LONG_MAX) |
| *p->val2 = LONG_MAX; |
| } |
| } |
| } |
| |
| int check_file(char *file1, char *file2) |
| { |
| struct stat st1, st2; |
| |
| if (file1 == NULL || file2 == NULL) |
| return 0; |
| if (stat(file1, &st1)) |
| return 0; |
| if (stat(file2, &st2)) |
| return 0; |
| if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) |
| return 1; |
| return 0; |
| } |
| |
| int get_id(char *in_file) |
| { |
| char buf[STR_SIZE]; |
| char *p; |
| int id; |
| |
| if (in_file == NULL) |
| return 0; |
| if ((p = strrchr(in_file, '/')) != NULL) |
| p++; |
| else |
| p = in_file; |
| if (sscanf(p, "%d.conf", &id) != 1) |
| return 0; |
| snprintf(buf, sizeof(buf), SCRIPT_DIR "%d.conf", id); |
| if (check_file(in_file, buf)) |
| return id; |
| return 0; |
| } |
| |
| int cpfile(char *in, char *out) |
| { |
| char buf[STR_SIZE]; |
| |
| if (in == NULL || out == NULL) |
| return 0; |
| if (check_file(in, out)) |
| return 0; |
| snprintf(buf, sizeof(buf), "/bin/cp -f %s %s", in, out); |
| if (system(buf)) |
| return 1; |
| return 0; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| struct CParam param; |
| struct stat st; |
| char buf[STR_SIZE]; |
| char *in_file = NULL; |
| char *out_file = NULL; |
| float ubc_k, cpu_k, disk_k, net_k, all_k; |
| int remove, validate; |
| int veid, c; |
| |
| gparam = ¶m; |
| memset(¶m, 0, sizeof(param)); |
| ubc_k = cpu_k = disk_k = net_k = all_k = 0; |
| remove = validate = 0; |
| if (argc < 2) |
| usage(1); |
| while(1) |
| { |
| int option_index = -1; |
| c = getopt_long(argc, argv, "o:a:c:d:u:n:hrv", options, |
| &option_index); |
| if (c == -1) |
| break; |
| switch(c) |
| { |
| case PARAM_OUTPUT_FILE : |
| out_file = strdup(optarg); |
| break; |
| case PARAM_ALL : |
| if (sscanf(optarg, "%f", &all_k) != 1) |
| { |
| fprintf(stderr, "Bad parameter %s\n", |
| optarg); |
| return 1; |
| } |
| break; |
| case PARAM_CPU : |
| if (sscanf(optarg, "%f", &cpu_k) != 1) |
| { |
| fprintf(stderr, "Bad parameter %s\n", |
| optarg); |
| return 1; |
| } |
| break; |
| case PARAM_DISK : |
| if (sscanf(optarg, "%f", &disk_k) != 1) |
| { |
| fprintf(stderr, "Bad parameter %s\n", |
| optarg); |
| return 1; |
| } |
| break; |
| case PARAM_UBC : |
| if (sscanf(optarg, "%f", &ubc_k) != 1) |
| { |
| fprintf(stderr, "Bad parameter %s\n", |
| optarg); |
| return 1; |
| } |
| break; |
| case PARAM_NET : |
| if (sscanf(optarg, "%f", &net_k) != 1) |
| { |
| fprintf(stderr, "Bad parameter %s\n", |
| optarg); |
| return 1; |
| } |
| break; |
| case PARAM_REMOVE : |
| remove = 1; |
| break; |
| case PARAM_VALIDATE : |
| validate = 1; |
| break; |
| case PARAM_HELP : |
| usage(0); |
| case '?' : |
| exit(1); |
| default : |
| fprintf(stderr, "Unknown option %s\n", optarg); |
| exit(1); |
| } |
| |
| } |
| if (optind == argc - 1) |
| { |
| in_file = strdup(argv[optind]); |
| } |
| else if (optind < argc) |
| { |
| fprintf(stderr, "non-option ARGV-elements: "); |
| while (optind < argc - 1) |
| fprintf(stderr, "%s ", argv[optind++]); |
| fprintf(stderr, "\n"); |
| exit(1); |
| } |
| if (in_file == NULL) |
| { |
| usage(1); |
| } |
| if (!stat(out_file, &st) && S_ISDIR(st.st_mode)) |
| { |
| printf("Error: output file %s is directory\n", out_file); |
| free(in_file); |
| return 1; |
| } |
| if (all_k) |
| ubc_k = cpu_k = disk_k = net_k = all_k; |
| if (stat(in_file, &st)) |
| { |
| fprintf(stderr, "No such file %s\n", in_file); |
| exit(1); |
| } |
| if (ParseConfig(0, in_file, ¶m, 0)) |
| { |
| fprintf(stderr, "Unable open %s\n", in_file); |
| free(in_file); |
| return 1; |
| } |
| scale(ubc_k, cpu_k, disk_k, net_k, ¶m); |
| if (remove) |
| remove_ve_spec(¶m); |
| if (validate) |
| { |
| param.validatemode = strdup(STR_ACT_ERROR); |
| if (validate_ve(0, ¶m)) { |
| free(in_file); |
| return 1; |
| } |
| } |
| if ((veid = get_id(in_file))) |
| { |
| if (!vz_init(veid) && env_is_running(veid)) |
| { |
| fprintf(stderr, "Container %d is running, applying " |
| "new parameters\n", veid); |
| if (disk_k) |
| VZFSQuotaSet(veid, NULL, ¶m, QUOTA_SET, 0); |
| if (ubc_k) |
| VZSetUbLimit(veid, ¶m); |
| if (cpu_k) |
| SetFairShed(veid, param.cpu_weight, |
| param.cpu_units, param.cpu_limit, 0); |
| } |
| } |
| /* if out_file already exist make backup */ |
| if (out_file != NULL && !stat(out_file, &st)) |
| { |
| snprintf(buf, sizeof(buf), "%s.bak", out_file); |
| if (remove) |
| rename(out_file, buf); |
| else |
| cpfile(out_file, buf); |
| } |
| if (out_file != NULL && !remove) |
| cpfile(in_file, out_file); |
| free(in_file); |
| if (SaveConfig(0, out_file, ¶m) == -1) |
| return 1; |
| if (!validate && param.class_id != NULL && *param.class_id == 1) |
| fprintf(stderr, "Warning: Some parameters were reduced, You need" |
| " to validate the configuration by vzcfgvalidate.\n"); |
| fprintf(stderr, "Scale completed: success\n"); |
| return 0; |
| } |