diff --git a/api/v1alpha1/os_types.go b/api/v1alpha1/os_types.go index 0de6fb1f288aac196999b866614509af2faa7b14..b2b1fb6e9b0d376336c78e4933620f636ba84604 100644 --- a/api/v1alpha1/os_types.go +++ b/api/v1alpha1/os_types.go @@ -84,6 +84,8 @@ type Content struct { Key string `json:"key"` // +kubebuilder:validation:Optional Value string `json:"value"` + // +kubebuilder:validation:Optional + Operation string `json:"operation"` } // +kubebuilder:subresource:status diff --git a/cmd/agent/Makefile b/cmd/agent/Makefile index c499d24b780800958a61f7a35dfdd4bb226f216c..15588b29ba6e3d2b40050a6778f0fc6cfea3d81e 100644 --- a/cmd/agent/Makefile +++ b/cmd/agent/Makefile @@ -9,7 +9,7 @@ ## See the Mulan PSL v2 for more details. grpc: - protoc --go_out=plugins=grpc:. --go_opt=paths=source_relative api/agent.proto + protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative api/agent.proto cover: go test -v ./... -coverprofile=cover.out go tool cover -html=cover.out -o cover.html diff --git a/cmd/agent/api/agent.pb.go b/cmd/agent/api/agent.pb.go index 847aa30e172978ecf4a107cb8cd39cbc4e608be2..077a57e387a29f5e080ce040ceb8922bfebf690e 100644 --- a/cmd/agent/api/agent.pb.go +++ b/cmd/agent/api/agent.pb.go @@ -11,8 +11,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v3.14.0 +// protoc-gen-go v1.30.0 +// protoc v3.14.0 // source: api/agent.proto package agent @@ -428,9 +428,9 @@ type SysConfig struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Model string `protobuf:"bytes,1,opt,name=model,proto3" json:"model,omitempty"` - ConfigPath string `protobuf:"bytes,2,opt,name=configPath,proto3" json:"configPath,omitempty"` - Contents map[string]string `protobuf:"bytes,3,rep,name=contents,proto3" json:"contents,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Model string `protobuf:"bytes,1,opt,name=model,proto3" json:"model,omitempty"` + ConfigPath string `protobuf:"bytes,2,opt,name=configPath,proto3" json:"configPath,omitempty"` + Contents map[string]*KeyInfo `protobuf:"bytes,3,rep,name=contents,proto3" json:"contents,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *SysConfig) Reset() { @@ -479,13 +479,68 @@ func (x *SysConfig) GetConfigPath() string { return "" } -func (x *SysConfig) GetContents() map[string]string { +func (x *SysConfig) GetContents() map[string]*KeyInfo { if x != nil { return x.Contents } return nil } +type KeyInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + Operation string `protobuf:"bytes,2,opt,name=operation,proto3" json:"operation,omitempty"` +} + +func (x *KeyInfo) Reset() { + *x = KeyInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_api_agent_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *KeyInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*KeyInfo) ProtoMessage() {} + +func (x *KeyInfo) ProtoReflect() protoreflect.Message { + mi := &file_api_agent_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use KeyInfo.ProtoReflect.Descriptor instead. +func (*KeyInfo) Descriptor() ([]byte, []int) { + return file_api_agent_proto_rawDescGZIP(), []int{8} +} + +func (x *KeyInfo) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *KeyInfo) GetOperation() string { + if x != nil { + return x.Operation + } + return "" +} + var File_api_agent_proto protoreflect.FileDescriptor var file_api_agent_proto_rawDesc = []byte{ @@ -525,7 +580,7 @@ var file_api_agent_proto_rawDesc = []byte{ 0x2e, 0x53, 0x79, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0x25, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0xba, 0x01, 0x0a, 0x09, 0x53, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0xca, 0x01, 0x0a, 0x09, 0x53, 0x79, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, @@ -533,26 +588,31 @@ var file_api_agent_proto_rawDesc = []byte{ 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x79, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x43, 0x6f, + 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x4b, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xbe, 0x01, 0x0a, 0x02, 0x4f, 0x53, 0x12, 0x37, - 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x08, 0x52, 0x6f, 0x6c, 0x6c, 0x62, - 0x61, 0x63, 0x6b, 0x12, 0x16, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, - 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x65, 0x12, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x20, 0x5a, 0x1e, 0x6f, 0x70, 0x65, 0x6e, - 0x65, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x6f, 0x73, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x24, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4b, 0x65, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3d, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0xbe, 0x01, 0x0a, 0x02, 0x4f, 0x53, 0x12, 0x37, 0x0a, + 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x08, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, + 0x63, 0x6b, 0x12, 0x16, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x65, 0x12, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x20, 0x5a, 0x1e, 0x6f, 0x70, 0x65, 0x6e, 0x65, + 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x6f, 0x73, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -567,7 +627,7 @@ func file_api_agent_proto_rawDescGZIP() []byte { return file_api_agent_proto_rawDescData } -var file_api_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_api_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_api_agent_proto_goTypes = []interface{}{ (*UpdateRequest)(nil), // 0: agent.UpdateRequest (*CertsInfo)(nil), // 1: agent.CertsInfo @@ -577,23 +637,25 @@ var file_api_agent_proto_goTypes = []interface{}{ (*ConfigureRequest)(nil), // 5: agent.ConfigureRequest (*ConfigureResponse)(nil), // 6: agent.ConfigureResponse (*SysConfig)(nil), // 7: agent.SysConfig - nil, // 8: agent.SysConfig.ContentsEntry + (*KeyInfo)(nil), // 8: agent.KeyInfo + nil, // 9: agent.SysConfig.ContentsEntry } var file_api_agent_proto_depIdxs = []int32{ 1, // 0: agent.UpdateRequest.certs:type_name -> agent.CertsInfo 7, // 1: agent.ConfigureRequest.configs:type_name -> agent.SysConfig - 8, // 2: agent.SysConfig.contents:type_name -> agent.SysConfig.ContentsEntry - 0, // 3: agent.OS.Update:input_type -> agent.UpdateRequest - 3, // 4: agent.OS.Rollback:input_type -> agent.RollbackRequest - 5, // 5: agent.OS.Configure:input_type -> agent.ConfigureRequest - 2, // 6: agent.OS.Update:output_type -> agent.UpdateResponse - 4, // 7: agent.OS.Rollback:output_type -> agent.RollbackResponse - 6, // 8: agent.OS.Configure:output_type -> agent.ConfigureResponse - 6, // [6:9] is the sub-list for method output_type - 3, // [3:6] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 9, // 2: agent.SysConfig.contents:type_name -> agent.SysConfig.ContentsEntry + 8, // 3: agent.SysConfig.ContentsEntry.value:type_name -> agent.KeyInfo + 0, // 4: agent.OS.Update:input_type -> agent.UpdateRequest + 3, // 5: agent.OS.Rollback:input_type -> agent.RollbackRequest + 5, // 6: agent.OS.Configure:input_type -> agent.ConfigureRequest + 2, // 7: agent.OS.Update:output_type -> agent.UpdateResponse + 4, // 8: agent.OS.Rollback:output_type -> agent.RollbackResponse + 6, // 9: agent.OS.Configure:output_type -> agent.ConfigureResponse + 7, // [7:10] is the sub-list for method output_type + 4, // [4:7] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_api_agent_proto_init() } @@ -698,6 +760,18 @@ func file_api_agent_proto_init() { return nil } } + file_api_agent_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KeyInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -705,7 +779,7 @@ func file_api_agent_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_api_agent_proto_rawDesc, NumEnums: 0, - NumMessages: 9, + NumMessages: 10, NumExtensions: 0, NumServices: 1, }, diff --git a/cmd/agent/api/agent.proto b/cmd/agent/api/agent.proto index a8858ceaef5f6f331e0fce48d804ade199db13bb..fd15b9f1d0aaca5a8f7107e1324b6dfff6ceec48 100644 --- a/cmd/agent/api/agent.proto +++ b/cmd/agent/api/agent.proto @@ -60,5 +60,10 @@ message ConfigureResponse { message SysConfig { string model = 1; string configPath = 2; - map contents = 3; + map contents = 3; } + +message KeyInfo { + string value = 1; + string operation = 2; +} \ No newline at end of file diff --git a/cmd/agent/server/config.go b/cmd/agent/server/config.go index 8669f16d0221f5ab1c08e9f17ccc43e3c22b1fb1..f7682aebf3d8c4c5bf94cc08e66835b4e5611179 100644 --- a/cmd/agent/server/config.go +++ b/cmd/agent/server/config.go @@ -18,6 +18,7 @@ import ( "fmt" "os" "path/filepath" + "regexp" "strings" "sync" @@ -29,7 +30,9 @@ import ( const ( defaultProcPath = "/proc/sys/" defaultKernelConPath = "/etc/sysctl.conf" + defalutGrubCfgPath = "/boot/efi/EFI/openEuler/grub.cfg" defaultKernelConPermission = 0644 + defaultGrubCfgPermission = 0751 ) // Configuration defines interface of configuring @@ -43,11 +46,17 @@ type KernelSysctl struct{} // SetConfig sets kernel.sysctl configuration func (k KernelSysctl) SetConfig(config *agent.SysConfig) error { logrus.Info("start set kernel.sysctl") - for key, value := range config.Contents { + for key, keyInfo := range config.Contents { procPath := getProcPath(key) - - if err := os.WriteFile(procPath, []byte(value), defaultKernelConPermission); err != nil { - return err + if keyInfo.Operation == "delete" { + logrus.Errorf("Failed to delete kernel.sysctl config with key %s", key) + } else if keyInfo.Operation == "add" || keyInfo.Operation == "update" || keyInfo.Operation == "" { + if err := os.WriteFile(procPath, []byte(keyInfo.Value), defaultKernelConPermission); err != nil { + logrus.Errorf("Failed to write kernel.sysctl with key %s: %v", key, err) + return err + } + } else { + logrus.Errorf("Failed to parse kernel.sysctl config operation %s", keyInfo.Operation) } } return nil @@ -65,13 +74,16 @@ func (k KerSysctlPersist) SetConfig(config *agent.SysConfig) error { } fileExist, err := checkConfigPath(configPath) if err != nil { + logrus.Errorf("Failed to find config path: %v", err) return err } configs, err := getAndSetConfigsFromFile(config.Contents, configPath, fileExist) if err != nil { + logrus.Errorf("Failed to set persist kernel configs: %v", err) return err } if err = writeConfigToFile(configPath, configs); err != nil { + logrus.Errorf("Failed to write configs to file: %v", err) return err } return nil @@ -82,13 +94,121 @@ type GrubCmdline struct{} // SetConfig sets grub.cmdline configuration func (g GrubCmdline) SetConfig(config *agent.SysConfig) error { - logrus.Info("start set kernel.sysctl") - for key, value := range config.Contents { - fmt.Println(key + "=" + value) + logrus.Info("start set grub.cmdline configuration") + fileExist, err := checkConfigPath(defalutGrubCfgPath) + if err != nil { + logrus.Errorf("Failed to find config path: %v", err) + return err + } + err = getAndSetGrubCfg(config.Contents, fileExist) + if err != nil { + logrus.Errorf("Failed to set grub configs: %v", err) + return err } return nil } +func getAndSetGrubCfg(expectConfigs map[string]*agent.KeyInfo, fileExist bool) error { + if !fileExist { + return os.ErrNotExist + } + file, err := os.OpenFile(defalutGrubCfgPath, os.O_RDWR, defaultGrubCfgPermission) + if err != nil { + return err + } + defer file.Close() + + reFindCurLinux := `^\s*linux.*root=.*` + r, err := regexp.Compile(reFindCurLinux) + if err != nil { + return err + } + + var lines []string + configScanner := bufio.NewScanner(file) + for configScanner.Scan() { + line := configScanner.Text() + if r.MatchString(line) { + line, err = modifyLinuxCfg(expectConfigs, line) + if err != nil { + return fmt.Errorf("error modify grub.cfg %v", err) + } + } + lines = append(lines, line) + } + + // override new configs to the grub.cfg file + _, err = file.Seek(0, 0) + if err != nil { + return err + } + writer := bufio.NewWriter(file) + for _, line := range lines { + if _, err := fmt.Fprintln(writer, line); err != nil { + return fmt.Errorf("error write grub.cfg %v", err) + } + } + return nil +} + +func modifyLinuxCfg(m map[string]*agent.KeyInfo, line string) (string, error) { + expectConfigs := deepCopyConfigMap(m) + newConfigs := []string{" "} + oldConfigs := strings.Split(line, " ") + // Config has two format: key or key=value. Following variables stand for the length after splitting + onlyKey, KVpair := 1, 2 + for _, oldConfig := range oldConfigs { + if oldConfig == "" { + continue + } + config := strings.Split(oldConfig, "=") + if len(config) != onlyKey && len(config) != KVpair { + return "", fmt.Errorf("cannot parse grub.cfg linux line %s", oldConfig) + } + if keyInfo, ok := expectConfigs[config[0]]; ok { + if keyInfo.Operation == "delete" { + if len(config) == KVpair && keyInfo.Value != config[1] { + logrus.Warnf("Failed to delete key %s with inconsistent values %s and %s", + config[0], config[1], keyInfo.Value) + continue + } + delete(expectConfigs, config[0]) + continue + } + if keyInfo.Operation != "delete" && len(config) == KVpair { + config[1] = keyInfo.Value + } + } + if len(config) == onlyKey { + newConfigs = append(newConfigs, config[0]) + } else if len(config) == KVpair { + newConfigs = append(newConfigs, strings.Join(config, "=")) + } + delete(expectConfigs, config[0]) + } + for key, keyInfo := range expectConfigs { + if keyInfo.Operation == "delete" { + logrus.Warnf("Failed to delete inexistent key %s", key) + continue + } + if keyInfo.Value == "" { + newConfigs = append(newConfigs, key) + } else { + newConfigs = append(newConfigs, fmt.Sprintf("%s=%s", key, keyInfo.Value)) + } + } + var newLine strings.Builder + for _, newConfig := range newConfigs { + if newConfig == "" { + continue + } + if _, err := fmt.Fprintf(&newLine, " %s", newConfig); err != nil { + return "", err + } + } + return newLine.String(), nil +} + func startConfig(configs []*agent.SysConfig) error { for _, config := range configs { if err := ConfigFactoryTemplate(config.Model, config); err != nil { @@ -108,17 +228,17 @@ func ConfigFactoryTemplate(configType string, config *agent.SysConfig) error { configTemplate[KerSysctlPersistName.String()] = new(KerSysctlPersist) configTemplate[GrubCmdlineName.String()] = new(GrubCmdline) }) - if _,ok := configTemplate[configType];ok{ + if _, ok := configTemplate[configType]; ok { return configTemplate[configType].SetConfig(config) } - return fmt.Errorf("get configTemplate error : cannot recoginze configType %s",configType) + return fmt.Errorf("get configTemplate error : cannot recoginze configType %s", configType) } func getProcPath(key string) string { return filepath.Join(defaultProcPath, strings.Replace(key, ".", "/", -1)) } -func getAndSetConfigsFromFile(expectConfigs map[string]string, path string, fileExist bool) ([]string, error) { +func getAndSetConfigsFromFile(expectConfigs map[string]*agent.KeyInfo, path string, fileExist bool) ([]string, error) { var configsWrite []string if fileExist { file, err := os.Open(path) @@ -142,9 +262,11 @@ func getAndSetConfigsFromFile(expectConfigs map[string]string, path string, file return nil, fmt.Errorf("could not parse systctl config %s", line) } key := strings.TrimSpace(configKV[0]) - if newValue, ok := expectConfigs[key]; ok { - config := key + " = " + newValue - configsWrite = append(configsWrite, config) + if newKeyInfo, ok := expectConfigs[key]; ok { + if newKeyInfo.Operation != "delete" { + config := key + " = " + newKeyInfo.Value + configsWrite = append(configsWrite, config) + } delete(expectConfigs, key) continue } @@ -154,11 +276,12 @@ func getAndSetConfigsFromFile(expectConfigs map[string]string, path string, file return nil, err } } - for newKey, newValue := range expectConfigs { - config := newKey + " = " + newValue - configsWrite = append(configsWrite, config) + for newKey, newKeyInfo := range expectConfigs { + if newKeyInfo.Operation != "delete" { + config := newKey + " = " + newKeyInfo.Value + configsWrite = append(configsWrite, config) + } } - return configsWrite, nil } diff --git a/cmd/agent/server/utils.go b/cmd/agent/server/utils.go index 092417bdc012da9afbe4532fbf50704ab49e6d39..d3b1262cd67e0de0de4c45b2e08bb2be4f7e3213 100644 --- a/cmd/agent/server/utils.go +++ b/cmd/agent/server/utils.go @@ -308,3 +308,14 @@ func checkOCIImageDigestMatch(containerRuntime string, imageName string, checkSu } return nil } + +func deepCopyConfigMap(m map[string]*pb.KeyInfo) map[string]*pb.KeyInfo { + result := make(map[string]*pb.KeyInfo) + for key, val := range m { + result[key] = &pb.KeyInfo{ + Value: val.Value, + Operation: val.Operation, + } + } + return result +} diff --git a/cmd/proxy/controllers/os_controller.go b/cmd/proxy/controllers/os_controller.go index c08bc166d1724d49d1e9d27bccab3f0aec348c87..2e140990d3848ed64f906c66a8fae288e45e9102 100644 --- a/cmd/proxy/controllers/os_controller.go +++ b/cmd/proxy/controllers/os_controller.go @@ -299,9 +299,12 @@ func (r *OSReconciler) setConfig(ctx context.Context, osInstance *upgradev1.OSIn Model: config.Model, ConfigPath: config.ConfigPath, } - contentsTmp := make(map[string]string) + contentsTmp := make(map[string]agentclient.KeyInfo) for _, content := range config.Contents { - contentsTmp[content.Key] = content.Value + contentsTmp[content.Key] = agentclient.KeyInfo{ + Value: content.Value, + Operation: content.Operation, + } } configTmp.Contents = contentsTmp sysConfigs = append(sysConfigs, configTmp) diff --git a/pkg/agentclient/connection.go b/pkg/agentclient/connection.go index 47d4bc59ed7e366fd8e76cebe5fffaf45ebacdb2..7b53a144fda49d13f11bdd058692e1e0268a89a1 100644 --- a/pkg/agentclient/connection.go +++ b/pkg/agentclient/connection.go @@ -52,7 +52,13 @@ type ConfigsInfo struct { type SysConfig struct { Model string ConfigPath string - Contents map[string]string + Contents map[string]KeyInfo +} + +// KeyInfo contains value and operation (i.e. delete, update or add) of a given key for configuration +type KeyInfo struct { + Value string + Operation string } // New create a gRPC channel to communicate with the server and return a client stub to perform RPCs @@ -111,9 +117,12 @@ func (c *Client) ConfigureSpec(configsInfo *ConfigsInfo) error { Model: config.Model, ConfigPath: config.ConfigPath, } - sysContents := make(map[string]string) + sysContents := make(map[string]*pb.KeyInfo) for configName, content := range config.Contents { - sysContents[configName] = content + sysContents[configName] = &pb.KeyInfo{ + Value: content.Value, + Operation: content.Operation, + } } sysConfig.Contents = sysContents sysConfigs = append(sysConfigs, sysConfig)